Friday, January 30, 2015
CRM 2011 Javascript null check
if (Xrm.Page.getAttribute('myfield') != null) {
var text = '';
if (Xrm.Page.getAttribute('myfield').getValue() != null) {
text = Xrm.Page.getAttribute('myfield').getSelectedOption().text;
}
}
function SectionExistsOnForm(tabName, sectionName) {
var section = Xrm.Page.ui.tabs.get(tabName).sections.get(sectionName);
return section != null;
}
function FieldExistsOnForm(field) {
var fieldControl = Xrm.Page.getAttribute(field);
return fieldControl != null;
}
function GetOptionSetText(field) {
if (FieldExistsOnForm(field)) {
var text = '';
if (Xrm.Page.getAttribute(field).getValue() != null) {
text = Xrm.Page.getAttribute(field).getSelectedOption().text;
}
return text;
}
}
function GetLookupValue(lookup) {
var name = '';
var lookupid;
var lookupObject = Xrm.Page.getAttribute(lookup);
if (lookupObject != null) {
var lookUpObjectValue = lookupObject.getValue();
if ((lookUpObjectValue != null)) {
name = lookUpObjectValue[0].name;
lookupid = lookUpObjectValue[0].id;
}
}
return lookupid;
}
function SetLookupValue(lookup, name, id, entityType) {
if (FieldExistsOnForm(lookup)) {
var lookupid = null;
var lookupObject = Xrm.Page.getAttribute(lookup);
var value = new Array();
value[0] = new Object();
value[0].id = id;
value[0].name = name;
value[0].entityType = entityType;
Xrm.Page.getAttribute(lookup).setValue(value);
}
}
var text = '';
if (Xrm.Page.getAttribute('myfield').getValue() != null) {
text = Xrm.Page.getAttribute('myfield').getSelectedOption().text;
}
}
function SectionExistsOnForm(tabName, sectionName) {
var section = Xrm.Page.ui.tabs.get(tabName).sections.get(sectionName);
return section != null;
}
function FieldExistsOnForm(field) {
var fieldControl = Xrm.Page.getAttribute(field);
return fieldControl != null;
}
function GetOptionSetText(field) {
if (FieldExistsOnForm(field)) {
var text = '';
if (Xrm.Page.getAttribute(field).getValue() != null) {
text = Xrm.Page.getAttribute(field).getSelectedOption().text;
}
return text;
}
}
function GetLookupValue(lookup) {
var name = '';
var lookupid;
var lookupObject = Xrm.Page.getAttribute(lookup);
if (lookupObject != null) {
var lookUpObjectValue = lookupObject.getValue();
if ((lookUpObjectValue != null)) {
name = lookUpObjectValue[0].name;
lookupid = lookUpObjectValue[0].id;
}
}
return lookupid;
}
function SetLookupValue(lookup, name, id, entityType) {
if (FieldExistsOnForm(lookup)) {
var lookupid = null;
var lookupObject = Xrm.Page.getAttribute(lookup);
var value = new Array();
value[0] = new Object();
value[0].id = id;
value[0].name = name;
value[0].entityType = entityType;
Xrm.Page.getAttribute(lookup).setValue(value);
}
}
Wednesday, January 28, 2015
Query for getting label of Optionset Used in SSRS report
select t1.activityid,t1. abc_tasktype,t2.value as ActivityName FROM Task t1
left outer join StringMap t2 on
(t2.AttributeName = 'abc_tasktype'
and t2.ObjectTypeCode = 4212)
Tuesday, January 20, 2015
Thursday, January 15, 2015
Updates the email address of a Crm 2011 User record from Active Directory.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices.AccountManagement;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using System.DirectoryServices;
namespace UpdateCRM2011UsersFromAD
{
class Program
{
static Dictionary<string, string> xRMToADFields = new Dictionary<string, string>();
/// <summary>
/// Setup which xRM fields map to which AD fields
/// </summary>
public static void SetupFieldMapping()
{
xRMToADFields.Add("firstname", "givenName");
xRMToADFields.Add("lastname", "sn");
xRMToADFields.Add("internalemailaddress", "mail");
xRMToADFields.Add("title", "title");
xRMToADFields.Add("address1_telephone1", "telephoneNumber");
xRMToADFields.Add("mobilephone", "mobile");
xRMToADFields.Add("address1_fax", "facsimileTelephoneNumber");
xRMToADFields.Add("address1_line1", "streetAddress");
xRMToADFields.Add("address1_city", "l");
xRMToADFields.Add("address1_stateorprovince", "st");
xRMToADFields.Add("address1_postalcode", "postalCode");
xRMToADFields.Add("address1_country", "co");
}
/// <summary>
/// Finds differences in email between AD and crm 2011 user record.
/// Argument0: CRM 2011 Url ex. http://crm/crmorg
/// Argument1: Run mode (S)can, (P)rompt, or (U)pdate
/// </summary>
/// <param name="args"></param>
public static void Main(string[] args)
{
Console.WriteLine("Initializing...");
SetupFieldMapping();
// Grab the Crm Url from the first line argument. Ex. http://crmservername/crmorgname
string crmUrl = args[0];
// Grab the running mode (S = scan mode, P = prompt mode, U = update mode)
// scan mode only displays the differences
// prompt mode prompts you before updating the current record
// and update mode updates everything without
string runMode;
// Default it to Prompt mode if not entered
if (args.Count() > 1)
runMode = args[1];
else
runMode = "P";
runMode = runMode.ToUpper();
string crmConnectionString = "Url=" + crmUrl;
var systemConnection = CrmConnection.Parse(crmConnectionString);
using (var crmContext = new CrmOrganizationServiceContext(systemConnection))
{
// Disable caching
crmContext.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
// Get all the non disabled users
var enabledUsers = (from u in crmContext.CreateQuery("systemuser") where u.GetAttributeValue<bool>("isdisabled") == false select u);
// Grab the domain context
Dictionary<string, string> modifiedFields = new Dictionary<string, string>();
foreach (var currentEnabledUser in enabledUsers)
{
crmContext.Detach(currentEnabledUser);
// Make sure the user record is valid and has a domain name.
if (!string.IsNullOrWhiteSpace(currentEnabledUser.GetAttributeValue<string>("domainname")))
{
// Get System User's Domain name and email address.
string userDomainName = currentEnabledUser.GetAttributeValue<string>("domainname");
string domainName = userDomainName.Substring(0, userDomainName.IndexOf('\\'));
PrincipalContext domain = new PrincipalContext(ContextType.Domain, domainName);
// Grab the crm system user's Active Directory object
UserPrincipal ADUserRecord = UserPrincipal.FindByIdentity(domain, userDomainName);
if (ADUserRecord != null)
{
bool isUserModified = false;
Entity userObject = new Entity("systemuser");
userObject.Id = currentEnabledUser.Id;
crmContext.Attach(userObject);
// Open up the actual directory entry object which contains much more data than a simple user principal object
using (DirectoryEntry underlyingADRecord = (DirectoryEntry)ADUserRecord.GetUnderlyingObject())
{
// Look through each field, if they do not match prompt/or update
foreach (var currentProperty in xRMToADFields)
{
// Get the AD and the CRM values for the current property.
string adValue = underlyingADRecord.Properties.Contains(currentProperty.Value)
? underlyingADRecord.Properties[currentProperty.Value].Value.ToString()
: "";
string crmValue = currentEnabledUser.Attributes.Contains(currentProperty.Key)
? currentEnabledUser.GetAttributeValue<string>(currentProperty.Key)
: "";
// Check if any of the fields are modified if so turn the flag to true without overriding it.
if ((currentEnabledUser.GetAttributeValue<string>(currentProperty.Key) == null && !string.IsNullOrWhiteSpace(adValue))
||
adValue.ToLower() != crmValue.ToLower())
{
// It is the first modified field of a new user so display the user we are processing.
if (!isUserModified)
{
Console.WriteLine();
Console.WriteLine("Modifications to the user: {0}", userDomainName);
Console.WriteLine();
}
// Display the fields that need an update
Console.WriteLine("Old {0}: {1}{3}New {0}: {2}{3}",
currentProperty.Key,
crmValue,
adValue,
Environment.NewLine);
// Put the changes to the User Object
userObject[currentProperty.Key] = adValue;
// Flag that user record has been modified
isUserModified |= true;
}
}
// If the record has modifications that we need to push and it is not scan mode run the update block
if (isUserModified && runMode != "S")
{
// Try prompting the user if the runmode is not on update mode
if (runMode != "U")
{
// Prompt the user if we should update this record.
Console.WriteLine("Would you like to update the record Y/N/U U for Updating all the users.");
var response = Console.ReadLine();
response = response.ToUpper().ElementAt(0).ToString();
// if they said U switch the run mode to update so they don't get consequent prompts.
if (response == "U")
runMode = "U";
// If it is not a positive response skip updating the record, start processing the next record
if (response != "U" && response != "Y")
continue;
}
// If the code reached here it means we want to push the user object to the crm server
try
{
crmContext.UpdateObject(userObject);
crmContext.SaveChanges();
Console.WriteLine("Updated User: {0}", userDomainName);
}
catch (Exception ex)
{
Console.WriteLine("Error on user {0]", userDomainName);
Console.WriteLine(ex.Message);
}
Console.WriteLine();
}
}
crmContext.Detach(userObject);
}
else
Console.WriteLine("Warning: User {0} no longer exists in AD.", userDomainName);
}
}
}
Console.WriteLine("Run completed, press any key to continue...");
Console.ReadKey();
}
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices.AccountManagement;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Client.Services;
using Microsoft.Xrm.Sdk;
using System.DirectoryServices;
namespace UpdateCRM2011UsersFromAD
{
class Program
{
static Dictionary<string, string> xRMToADFields = new Dictionary<string, string>();
/// <summary>
/// Setup which xRM fields map to which AD fields
/// </summary>
public static void SetupFieldMapping()
{
xRMToADFields.Add("firstname", "givenName");
xRMToADFields.Add("lastname", "sn");
xRMToADFields.Add("internalemailaddress", "mail");
xRMToADFields.Add("title", "title");
xRMToADFields.Add("address1_telephone1", "telephoneNumber");
xRMToADFields.Add("mobilephone", "mobile");
xRMToADFields.Add("address1_fax", "facsimileTelephoneNumber");
xRMToADFields.Add("address1_line1", "streetAddress");
xRMToADFields.Add("address1_city", "l");
xRMToADFields.Add("address1_stateorprovince", "st");
xRMToADFields.Add("address1_postalcode", "postalCode");
xRMToADFields.Add("address1_country", "co");
}
/// <summary>
/// Finds differences in email between AD and crm 2011 user record.
/// Argument0: CRM 2011 Url ex. http://crm/crmorg
/// Argument1: Run mode (S)can, (P)rompt, or (U)pdate
/// </summary>
/// <param name="args"></param>
public static void Main(string[] args)
{
Console.WriteLine("Initializing...");
SetupFieldMapping();
// Grab the Crm Url from the first line argument. Ex. http://crmservername/crmorgname
string crmUrl = args[0];
// Grab the running mode (S = scan mode, P = prompt mode, U = update mode)
// scan mode only displays the differences
// prompt mode prompts you before updating the current record
// and update mode updates everything without
string runMode;
// Default it to Prompt mode if not entered
if (args.Count() > 1)
runMode = args[1];
else
runMode = "P";
runMode = runMode.ToUpper();
string crmConnectionString = "Url=" + crmUrl;
var systemConnection = CrmConnection.Parse(crmConnectionString);
using (var crmContext = new CrmOrganizationServiceContext(systemConnection))
{
// Disable caching
crmContext.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
// Get all the non disabled users
var enabledUsers = (from u in crmContext.CreateQuery("systemuser") where u.GetAttributeValue<bool>("isdisabled") == false select u);
// Grab the domain context
Dictionary<string, string> modifiedFields = new Dictionary<string, string>();
foreach (var currentEnabledUser in enabledUsers)
{
crmContext.Detach(currentEnabledUser);
// Make sure the user record is valid and has a domain name.
if (!string.IsNullOrWhiteSpace(currentEnabledUser.GetAttributeValue<string>("domainname")))
{
// Get System User's Domain name and email address.
string userDomainName = currentEnabledUser.GetAttributeValue<string>("domainname");
string domainName = userDomainName.Substring(0, userDomainName.IndexOf('\\'));
PrincipalContext domain = new PrincipalContext(ContextType.Domain, domainName);
// Grab the crm system user's Active Directory object
UserPrincipal ADUserRecord = UserPrincipal.FindByIdentity(domain, userDomainName);
if (ADUserRecord != null)
{
bool isUserModified = false;
Entity userObject = new Entity("systemuser");
userObject.Id = currentEnabledUser.Id;
crmContext.Attach(userObject);
// Open up the actual directory entry object which contains much more data than a simple user principal object
using (DirectoryEntry underlyingADRecord = (DirectoryEntry)ADUserRecord.GetUnderlyingObject())
{
// Look through each field, if they do not match prompt/or update
foreach (var currentProperty in xRMToADFields)
{
// Get the AD and the CRM values for the current property.
string adValue = underlyingADRecord.Properties.Contains(currentProperty.Value)
? underlyingADRecord.Properties[currentProperty.Value].Value.ToString()
: "";
string crmValue = currentEnabledUser.Attributes.Contains(currentProperty.Key)
? currentEnabledUser.GetAttributeValue<string>(currentProperty.Key)
: "";
// Check if any of the fields are modified if so turn the flag to true without overriding it.
if ((currentEnabledUser.GetAttributeValue<string>(currentProperty.Key) == null && !string.IsNullOrWhiteSpace(adValue))
||
adValue.ToLower() != crmValue.ToLower())
{
// It is the first modified field of a new user so display the user we are processing.
if (!isUserModified)
{
Console.WriteLine();
Console.WriteLine("Modifications to the user: {0}", userDomainName);
Console.WriteLine();
}
// Display the fields that need an update
Console.WriteLine("Old {0}: {1}{3}New {0}: {2}{3}",
currentProperty.Key,
crmValue,
adValue,
Environment.NewLine);
// Put the changes to the User Object
userObject[currentProperty.Key] = adValue;
// Flag that user record has been modified
isUserModified |= true;
}
}
// If the record has modifications that we need to push and it is not scan mode run the update block
if (isUserModified && runMode != "S")
{
// Try prompting the user if the runmode is not on update mode
if (runMode != "U")
{
// Prompt the user if we should update this record.
Console.WriteLine("Would you like to update the record Y/N/U U for Updating all the users.");
var response = Console.ReadLine();
response = response.ToUpper().ElementAt(0).ToString();
// if they said U switch the run mode to update so they don't get consequent prompts.
if (response == "U")
runMode = "U";
// If it is not a positive response skip updating the record, start processing the next record
if (response != "U" && response != "Y")
continue;
}
// If the code reached here it means we want to push the user object to the crm server
try
{
crmContext.UpdateObject(userObject);
crmContext.SaveChanges();
Console.WriteLine("Updated User: {0}", userDomainName);
}
catch (Exception ex)
{
Console.WriteLine("Error on user {0]", userDomainName);
Console.WriteLine(ex.Message);
}
Console.WriteLine();
}
}
crmContext.Detach(userObject);
}
else
Console.WriteLine("Warning: User {0} no longer exists in AD.", userDomainName);
}
}
}
Console.WriteLine("Run completed, press any key to continue...");
Console.ReadKey();
}
}
}
Finding the value of the state and status codes in CRM 2011
select
AttributeName,
AttributeValue,
Value
from dbo.StringMap
where
(dbo.StringMap.AttributeName = 'statuscode'
or
dbo.StringMap.AttributeName = 'statecode')
and
dbo.StringMap.ObjectTypeCode = 1
Will display the following values for the Account Entity ( ObjectTypeCode = 1 ):
AttributeName AttributeValue Value
statecode 0 Active
statecode 1 Inactive
statuscode 1 Active
statuscode 2 Inactive
Extension Method
Q10. What is Extension method?
Ans. An extension method is a static method of a static class that can be invoked like as an instance method syntax. Extension methods are used to add new behaviors to an existing type without altering.
In extension method "this" keyword is used with the first parameter and the first parameter will be of type that is extended by extension method. Other parameters of extensions types can be of any types (data type).
Example: //defining extension method public static class MyExtensions
{ public static int WordCount(this String str) {
return str.Split(new char[] { ' ', '.', ',' }).Length; } }
class Program { public static void Main() { string s = "Dot Net Tricks Extension Method Example";
//calling extension method int i = s.WordCount(); Console.WriteLine(i); } }
//output: //6
Key points about extension method
1. An extension method is defined as static method but it is called like as an instance method.
2. An extension method first parameter specifies the type of the extended object, and it is preceded by the "this" keyword.
3. An extension method having the same name and signature like as an instance method will never be called since it has low priority than instance method.
4. An extension method couldn't override the existing instance methods.
5. An extension method cannot be used with fields, properties or events.
6. The compiler doesn't cause an error if two extension methods with same name and signature are defined in two different namespaces and these namespaces are included in same class file using directives. Compiler will cause an error if you will try to call one of them extension method.
Ans. An extension method is a static method of a static class that can be invoked like as an instance method syntax. Extension methods are used to add new behaviors to an existing type without altering.
In extension method "this" keyword is used with the first parameter and the first parameter will be of type that is extended by extension method. Other parameters of extensions types can be of any types (data type).
Example: //defining extension method public static class MyExtensions
{ public static int WordCount(this String str) {
return str.Split(new char[] { ' ', '.', ',' }).Length; } }
class Program { public static void Main() { string s = "Dot Net Tricks Extension Method Example";
//calling extension method int i = s.WordCount(); Console.WriteLine(i); } }
//output: //6
Key points about extension method
1. An extension method is defined as static method but it is called like as an instance method.
2. An extension method first parameter specifies the type of the extended object, and it is preceded by the "this" keyword.
3. An extension method having the same name and signature like as an instance method will never be called since it has low priority than instance method.
4. An extension method couldn't override the existing instance methods.
5. An extension method cannot be used with fields, properties or events.
6. The compiler doesn't cause an error if two extension methods with same name and signature are defined in two different namespaces and these namespaces are included in same class file using directives. Compiler will cause an error if you will try to call one of them extension method.
Anonymous Method and Lambda Expression
What is anonymous method?
Ans. The concept of anonymous method was introduced in C# 2.0. An anonymous method is an inline unnamed method in the code. It is created using the delegate keyword and doesn’t have its name and return type.
In this way, an anonymous method has no name, optional parameters and return type; it has only body. An anonymous method behaves like a regular method and allows you to write inline code in place of regular method.
class Program {
//delegate for representing anonymous method
delegate int del(int x, int y); static void Main(string[] args)
{ //anonymous method using delegate keyword
del d1 = delegate(int x, int y)
{ return x * y; };
int z1 = d1(2, 3);
Console.WriteLine(z1); } }
Key points about anonymous method
1. A variable, declared outside the anonymous method can be accessed inside the anonymous method.
2. A variable, declared inside the anonymous method can’t be accessed outside the anonymous method.
3. We use anonymous method in event handling.
4. An anonymous method, declared without parenthesis can be assigned to a delegate with any signature.
5. Unsafe code can’t be accessed within an anonymous method.
6. An anonymous method can’t access the ref or out parameters of an outer scope.
What is lambda expression?
Ans. The concept of lambda expression was introduced in C# 3.0. Typically, lambda expression is a more concise syntax of anonymous method. It is just a new way to write anonymous method. At compile time all the lambda expressions are converted into anonymous methods according to lambda expression conversion rules. The left side of the lambda operator "=>" represents the arguments of anonymous method and the right side represents the method body.
Lambda expression Syntax
(Input-parameters) => expression-or-statement-block
Types of Lambda expression
1. Statement Lambda -Statement lambda has a statement block on the right side of the lambda operator "=>". x => { return x * x; };
2. Expression Lambda - Expression lambda has only an expression (no return statement or curly braces), on the right side of the lambda operator "=>".
x => x * x; // here x*x is expression
Anonymous Method and Lambda Expression example:
class Program { //delegate for representing anonymous method
delegate int del(int x, int y);
static void Main(string[] args)
{ //anonymous method using expression lambda
del d1 = (x, y) => x * y; //
or (int x, int y) => x * y;
//anonymous method using statement lambda del d2 = (x, y) => { return x * y; };
// or (int x, int y) => { return x * y; };
//anonymous method using delegate keyword
del d3 = delegate(int x, int y)
{ return x * y; };
int z1 = d1(2, 3);
int z2 = d2(3, 3);
int z3 = d3(4, 3);
Console.WriteLine(z1);
Console.WriteLine(z2);
Console.WriteLine(z3);
} } /
Ans. The concept of anonymous method was introduced in C# 2.0. An anonymous method is an inline unnamed method in the code. It is created using the delegate keyword and doesn’t have its name and return type.
In this way, an anonymous method has no name, optional parameters and return type; it has only body. An anonymous method behaves like a regular method and allows you to write inline code in place of regular method.
class Program {
//delegate for representing anonymous method
delegate int del(int x, int y); static void Main(string[] args)
{ //anonymous method using delegate keyword
del d1 = delegate(int x, int y)
{ return x * y; };
int z1 = d1(2, 3);
Console.WriteLine(z1); } }
Key points about anonymous method
1. A variable, declared outside the anonymous method can be accessed inside the anonymous method.
2. A variable, declared inside the anonymous method can’t be accessed outside the anonymous method.
3. We use anonymous method in event handling.
4. An anonymous method, declared without parenthesis can be assigned to a delegate with any signature.
5. Unsafe code can’t be accessed within an anonymous method.
6. An anonymous method can’t access the ref or out parameters of an outer scope.
What is lambda expression?
Ans. The concept of lambda expression was introduced in C# 3.0. Typically, lambda expression is a more concise syntax of anonymous method. It is just a new way to write anonymous method. At compile time all the lambda expressions are converted into anonymous methods according to lambda expression conversion rules. The left side of the lambda operator "=>" represents the arguments of anonymous method and the right side represents the method body.
Lambda expression Syntax
(Input-parameters) => expression-or-statement-block
Types of Lambda expression
1. Statement Lambda -Statement lambda has a statement block on the right side of the lambda operator "=>". x => { return x * x; };
2. Expression Lambda - Expression lambda has only an expression (no return statement or curly braces), on the right side of the lambda operator "=>".
x => x * x; // here x*x is expression
Anonymous Method and Lambda Expression example:
class Program { //delegate for representing anonymous method
delegate int del(int x, int y);
static void Main(string[] args)
{ //anonymous method using expression lambda
del d1 = (x, y) => x * y; //
or (int x, int y) => x * y;
//anonymous method using statement lambda del d2 = (x, y) => { return x * y; };
// or (int x, int y) => { return x * y; };
//anonymous method using delegate keyword
del d3 = delegate(int x, int y)
{ return x * y; };
int z1 = d1(2, 3);
int z2 = d2(3, 3);
int z3 = d3(4, 3);
Console.WriteLine(z1);
Console.WriteLine(z2);
Console.WriteLine(z3);
} } /
CRM 2011 Server Setup Commonly Asked Questions
As customers are starting to plan for CRM 2011 installations and upgrades, we’ve begun to see questions regarding environment setups. Here’s a list of the questions I’ve seen thus far:
Q: Are the CRM 2011 Report Extensions (commonly referred to as the “report connector”) an optional component?
A: All installations now require the CRM 2011 Report Extensions to be installed and configured on the SQL Reporting Server. If it is not installed, certain features will not work properly: reporting will not function, creating new organizations, and organization imports will be blocked until the extensions are installed and configured.
Q: Do I need to install the CRM 2011 Reporting Extensions prior to installing CRM?
A: No, these should be installed after you install the CRM 2011 Server components.
Q: When installing CRM server roles on different servers (ex: install front-end and deployment components on server1 and back-end components on server2) I am not prompted to install the reporting extensions, why is this?
A: When the CRM server roles are installed separately (without first installing a CRM full-server) you’ll notice that no organizations are created by default. Once the servers are all setup and configured, the first step to setup CRM is to launch deployment manager and create an organization. It is at that time you will be required to input a reporting server that has the CRM 2011 Reporting Extensions installed.
Q: On CRM 4.0, as long as the report extensions were not installed, a Reporting Server (or scaled out reporting server farm) could host reports for multiple CRM installations/deployments. How has this changed in CRM 2011?
A: In CRM 2011 the Reporting Extensions are now required, which means each Reporting server (or scaled out reporting server farm) with the report extensions installed may only host reports for a single CRM 2011 Deployment. NOTE: The Reporting Server (or scaled out reporting server farm) can host reports for multiple tenants (organizations) in the deployment.
Q: If I were to run all CRM servers services under different service accounts how many service accounts do I need and what CRM groups should each service account belong to?
A: There are numerous configurations you could use to accomplish this, but if you were to separate everything here is a table explaining what group membership is required-- I’ve also included SSRS and SQL server:
* The performance log user group is a local group on each server and not a domain group
** Email router will run as local system
*** The Installing user should be a separate service account, but it should not be used to run any services.
IMPORTANT: If any of the service accounts are created as users in CRM, you may encounter various problems, some of which are potential security issues.
Q: I am concerned when it comes to security and want to be sure I limit my attack surface whenever possible. What Windows Server Roles and Features are required for each CRM Server role?
A: Below is a table broken down by the 8 different server roles CRM installs.
NOTE: The IIS Web Server will also install the following role services:
·Web-Static-Content
·Web-Default-Doc
·Web-Http-Errors
·Web-Http-Redirect
·Web-Dir-Browsing
·Web-Asp-Net
·Web-Windows-Auth
·Web-Stat-Compression
·Web-Dyn-Compression
·Web-Mgmt-Console
·Web-Metabase
Q: If I want to split up my roles between a CRM Front-End Server and a CRM Back-End Server, but I don’t want to have a third server just for the purpose of hosting the deployment tools. Is there a best practice or preferred placement given the two choices?
A: The deployment tools can live on either server. As you see in the chart above, the IIS Windows Web Server Role is required for both the Front-End Server services as well as the Deployment tools. If you have a goal of minimizing your attack surface and want to limit your installations of IIS, the best location for the Deployment Tools role would be on the Front-End Server as all web services would be hosted on your Front-End Server and the Back-End Server would be hosting non-IIS based components.
Q: How does the CRM Front-End Server Roles contact the CRM Sandbox and Async Services and do I need to set anything up or allow for any firewall exceptions?
A: The CRM Async service is not called directly by any of the other services. The async service operates out of the AsyncOperations queue and will process records as they’re place into the queue. However, the Sandbox service operates differently. When work is handed off to the Sandbox service it is done so over a TCP channel (port 808 by default). In the case of a synchronous plugin, the web application server will contact the sandbox service; in the case of an asynchronous plugin, the async service will contact the sandbox service. Also, note: if you are: A) Running the sandbox service on a dedicated server (not installing the full server role) and B) running the sandbox service as a service account identity, and not as network service, a dedicated SPN is required in active directory. The SPN would be homed under the service account running the sandbox service and would look like this: MSCRMSandboxService/<SandboxServerName>. For example: if my sandbox server was named “CRMSandboxSrv01” and my sandbox service ran under CRM_Sandbox_SvcAcct my SPN would look like: MSCRMSandboxService/CrmSandboxSrv01 and the SPN would live under the CRM_Sandbox_SvcAcct user object in Active Directory.
Q: If I want to manage my CRM deployment via PowerShell are there any specific recommendations or “gotcha’s”?
A: Currently, if you wish to manage your CRM deployment via PowerShell, the Deployment Web Services must be running as a service account identity and not as Network Service. If you run the deployment web services as Network Service, certain functions of the CRM PowerShell add-in will return a security error.
If additional questions come up feel free to leave them as comments and we’ll do our best to address them in some way, shape, or form. I hope this helps clear up the confusion around some of the more complex environment configurations and what operating system features and roles are required for various CRM Server Roles.
Q: Are the CRM 2011 Report Extensions (commonly referred to as the “report connector”) an optional component?
A: All installations now require the CRM 2011 Report Extensions to be installed and configured on the SQL Reporting Server. If it is not installed, certain features will not work properly: reporting will not function, creating new organizations, and organization imports will be blocked until the extensions are installed and configured.
Q: Do I need to install the CRM 2011 Reporting Extensions prior to installing CRM?
A: No, these should be installed after you install the CRM 2011 Server components.
Q: When installing CRM server roles on different servers (ex: install front-end and deployment components on server1 and back-end components on server2) I am not prompted to install the reporting extensions, why is this?
A: When the CRM server roles are installed separately (without first installing a CRM full-server) you’ll notice that no organizations are created by default. Once the servers are all setup and configured, the first step to setup CRM is to launch deployment manager and create an organization. It is at that time you will be required to input a reporting server that has the CRM 2011 Reporting Extensions installed.
Q: On CRM 4.0, as long as the report extensions were not installed, a Reporting Server (or scaled out reporting server farm) could host reports for multiple CRM installations/deployments. How has this changed in CRM 2011?
A: In CRM 2011 the Reporting Extensions are now required, which means each Reporting server (or scaled out reporting server farm) with the report extensions installed may only host reports for a single CRM 2011 Deployment. NOTE: The Reporting Server (or scaled out reporting server farm) can host reports for multiple tenants (organizations) in the deployment.
Q: If I were to run all CRM servers services under different service accounts how many service accounts do I need and what CRM groups should each service account belong to?
A: There are numerous configurations you could use to accomplish this, but if you were to separate everything here is a table explaining what group membership is required-- I’ve also included SSRS and SQL server:
Service
|
PrivUser
Group
|
SqlAccess
Group
|
PrivRept
Group
|
Rept
Group
|
Perf. Log
Users*
|
CRM User?
|
Deployment Services SvcAcct
|
þ
|
þ
|
-
|
-
|
-
|
NO
|
Application Service (CRMAppPool)
|
þ
|
þ
|
-
|
-
|
þ
|
NO
|
Async service SvcAcct
|
þ
|
þ
|
-
|
-
|
þ
|
NO
|
Sandbox services SvcAcct
|
NO
|
NO
|
-
|
-
|
þ
|
NO
|
SQL Server SvcAcct
|
-
|
-
|
-
|
-
|
-
|
-
|
SQL Reporting Services SvcAcct
|
þ
|
-
|
þ
|
-
|
-
|
NO
|
Email router account**
|
þ
|
-
|
-
|
-
|
-
|
NO
|
Installing User***
|
-
|
-
|
-
|
þ
|
-
|
þ
|
User accounts in CRM
|
NO
|
NO
|
NO
|
þ
|
-
|
þ
|
* The performance log user group is a local group on each server and not a domain group
** Email router will run as local system
*** The Installing user should be a separate service account, but it should not be used to run any services.
IMPORTANT: If any of the service accounts are created as users in CRM, you may encounter various problems, some of which are potential security issues.
Q: I am concerned when it comes to security and want to be sure I limit my attack surface whenever possible. What Windows Server Roles and Features are required for each CRM Server role?
A: Below is a table broken down by the 8 different server roles CRM installs.
Component
|
Web
App
|
Org
WS
|
Disc
WS
|
Help
Server
|
Depl
Tools
|
Depl
WS
|
Async
Svc
|
Sandbox
Svc
| ||
IIS Web Server Role
|
þ
|
þ
|
þ
|
þ
|
-
|
þ
|
-
|
-
| ||
.NET HTTP Activation
|
-
|
þ
|
þ
|
-
|
-
|
þ
|
-
|
-
| ||
File Server Indexing Services
|
-
|
-
|
-
|
þ
|
-
|
-
|
-
|
-
| ||
Windows PowerShell
|
-
|
-
|
-
|
-
|
þ
|
-
|
-
|
-
| ||
NOTE: The IIS Web Server will also install the following role services:
·Web-Static-Content
·Web-Default-Doc
·Web-Http-Errors
·Web-Http-Redirect
·Web-Dir-Browsing
·Web-Asp-Net
·Web-Windows-Auth
·Web-Stat-Compression
·Web-Dyn-Compression
·Web-Mgmt-Console
·Web-Metabase
Q: If I want to split up my roles between a CRM Front-End Server and a CRM Back-End Server, but I don’t want to have a third server just for the purpose of hosting the deployment tools. Is there a best practice or preferred placement given the two choices?
A: The deployment tools can live on either server. As you see in the chart above, the IIS Windows Web Server Role is required for both the Front-End Server services as well as the Deployment tools. If you have a goal of minimizing your attack surface and want to limit your installations of IIS, the best location for the Deployment Tools role would be on the Front-End Server as all web services would be hosted on your Front-End Server and the Back-End Server would be hosting non-IIS based components.
Q: How does the CRM Front-End Server Roles contact the CRM Sandbox and Async Services and do I need to set anything up or allow for any firewall exceptions?
A: The CRM Async service is not called directly by any of the other services. The async service operates out of the AsyncOperations queue and will process records as they’re place into the queue. However, the Sandbox service operates differently. When work is handed off to the Sandbox service it is done so over a TCP channel (port 808 by default). In the case of a synchronous plugin, the web application server will contact the sandbox service; in the case of an asynchronous plugin, the async service will contact the sandbox service. Also, note: if you are: A) Running the sandbox service on a dedicated server (not installing the full server role) and B) running the sandbox service as a service account identity, and not as network service, a dedicated SPN is required in active directory. The SPN would be homed under the service account running the sandbox service and would look like this: MSCRMSandboxService/<SandboxServerName>. For example: if my sandbox server was named “CRMSandboxSrv01” and my sandbox service ran under CRM_Sandbox_SvcAcct my SPN would look like: MSCRMSandboxService/CrmSandboxSrv01 and the SPN would live under the CRM_Sandbox_SvcAcct user object in Active Directory.
Q: If I want to manage my CRM deployment via PowerShell are there any specific recommendations or “gotcha’s”?
A: Currently, if you wish to manage your CRM deployment via PowerShell, the Deployment Web Services must be running as a service account identity and not as Network Service. If you run the deployment web services as Network Service, certain functions of the CRM PowerShell add-in will return a security error.
If additional questions come up feel free to leave them as comments and we’ll do our best to address them in some way, shape, or form. I hope this helps clear up the confusion around some of the more complex environment configurations and what operating system features and roles are required for various CRM Server Roles.
Using Fiddler To Check For Kerberos Auth
http://blogs.msdn.com/b/crminthefield/archive/2012/10/10/using-fiddler-to-check-for-kerberos-auth.aspx
How var type is different from anonymous type
Ans. var- var data type was introduced with C# 3.0. It is used to declare implicitly typed local variable means it tells the
compiler to figure out the type of the variable at compile time. A var variable must be initialized at the time of declaration.
For Example: var i = 20; // implicitly typed int i = 20; //explicitly typed var str = "1"; //declaration and initialization var num = 0; string s = "string"; //explicitly typed var s2 = s; // implicitly typed
Basically, var is an anonymous type, hence use it whenever you don't know the type of output or it is anonymous. Suppose you are
joining two tables and retrieving data from both the tables then the result will be an anonymous type since data will come from both the tables.
Expression assigned to var must be executed at compile time to know the type of output, so that var type may behave like the new type assigned to it.
DataContext context =
new DataContext();
var q =
(from e in context.Employee join d in context.Department on e.DeptID equals d.DeptID
select new { e.EmpID, e.FirstName, d.DeptName, d.DeptLocation });
Anonymous Type- An anonymous type is a simple class generated by the compiler within IL to store a set of values. var data type and new keyword is used to create an anonymous type.
var emp = new { Name = "Deepak", Address = "Noida", Salary = 21000 };
At compile time, the compiler will create an anonymous type, as follows:
class __Anonymous1
{ private string name;
private string address;
int salary;
public string Name { get { return name; } set { name=value } }
public string Address { get { return address; }
set { address = value; } } public int Salary { get { return salary; }
set { salary = value; }
}
}
The anonymous type is very useful when you want to shape the result in your desired form like this:
DataContext context = new DataContext();
var result = from book in context.Books where book.Price > 200 orderby book.IssueDate
descending
select new { Name = book.Name, IssueNumber = "#" + book.Issue };
In above example, I change the name of the “Issue” field of Book table to “IssueNumber” and add # before value to get desired output.
Soap Retrieve Entity Request
RetrieveEntityRequest = function (logicalName, fnSuccessCallback, fnErrorCallback) {
/// Returns a sorted array of entities
var request = "";
request += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += " <s:Body>";
request += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
request += " <request i:type=\"a:RetrieveEntityRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
request += " <a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>EntityFilters</b:key>";
request += " <b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">Entity Attributes Privileges Relationships</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>MetadataId</b:key>";
request += " <b:value i:type=\"ser:guid\" xmlns:ser=\"http://schemas.microsoft.com/2003/10/Serialization/\">00000000-0000-0000-0000-000000000000</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>LogicalName</b:key>";
request += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + logicalName + "</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>RetrieveAsIfPublished</b:key>";
request += " <b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">true</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " </a:Parameters>";
request += " <a:RequestId i:nil=\"true\" />";
request += " <a:RequestName>RetrieveEntity</a:RequestName>";
request += " </request>";
request += " </Execute>";
request += " </s:Body>";
request += "</s:Envelope>";
return _ExecuteRequest(request, "Execute", .RetrieveEntityResponse, fnSuccessCallback, fnErrorCallback);
};
/// Returns a sorted array of entities
var request = "";
request += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += " <s:Body>";
request += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
request += " <request i:type=\"a:RetrieveEntityRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
request += " <a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>EntityFilters</b:key>";
request += " <b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">Entity Attributes Privileges Relationships</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>MetadataId</b:key>";
request += " <b:value i:type=\"ser:guid\" xmlns:ser=\"http://schemas.microsoft.com/2003/10/Serialization/\">00000000-0000-0000-0000-000000000000</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>LogicalName</b:key>";
request += " <b:value i:type=\"c:string\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">" + logicalName + "</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>RetrieveAsIfPublished</b:key>";
request += " <b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">true</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " </a:Parameters>";
request += " <a:RequestId i:nil=\"true\" />";
request += " <a:RequestName>RetrieveEntity</a:RequestName>";
request += " </request>";
request += " </Execute>";
request += " </s:Body>";
request += "</s:Envelope>";
return _ExecuteRequest(request, "Execute", .RetrieveEntityResponse, fnSuccessCallback, fnErrorCallback);
};
Subscribe to:
Posts (Atom)