How to Change the Remove Desktop (RDP) Port

You can use "Remote Desktop Connection" tool to connect to other PC and mange them remotely. It is a great tool that is really helpful specially when are talking about outsourcing industry. I do not mean this is only helpful only in IT outsourcing industry, but what I meant it is providing a huge help on that industry because you need to work on windows based machines while you are setting in a different country.

For me, I exposed my personal PC at home to be accessible from public internet network in order to be able to connect to it while I am travelling or at work. But this means I am also exposing my personal PC for hacking risk specially when I am not having a very good secured network infra-structure at home.

Hiding the Remote Desktop port is one step is to make my personal hard to hack. The default remote desktop’s port is 3389. so I decided to change it to something else to make it harder for hackers to attack on my PC. Below is the steps of how to do it:

1. Click on Start menu
2. Choose Run , this will open the RUN dialog box
3. Type REGEDIT and click on ok, this will launch the Registry Editor for you
4. Locate the following key in the registry
  HKEY_LOCAL_MACHINE\System\Current\ControlSet\Control\Terminal Server\WinStations\RDP-Tcp\PortNumber

5. Double click on PortNumber and choose "Decimal" option then change the port number there to something else, let’s say you changed it to be 3333

6. Click OK , then quit Registry Editor
EditDWORDRegistryValue
To connect to the PC, you need to type the port number along with PC’s name or IP just like blow examples:
1. PCNAME:333
2. 192.168.1.100:333

How to register a Plugin inside MS CRM 4.0 using Registration tool shipped with CRM SDK 4.0 Plugins

Plugins on CRM 4.0 replaces Callouts on CRM 3.0.. Mainly Plugins/Callouts is a custom code that should run to response for an action taken place against specific entity. actions like : Create / Update… and so on. Plugins can response to more events than Callouts.. the more events mean more complexity on registering Plugins if we comparing it with Callouts. Thanks for MS, MS released a registration tool with CRM Sdk 4.0 to make out life easier. I listed below main steps to register Plugins inside CRM 4.0.

To register Plugins on CRM 4.0 Please follow these steps:

  1. Your assembly should be strongly named.

  2. The Class that wills response to actions on activity should be implements IPlugin Interface.

  3. Move your assemblies to C:\Program Files\Microsoft Dynamics CRM\Server\bin\assembly\ folder with any resources needed[like XML configuration file, and so on.].

  4. Open Plugin Registration tool that is shipped with CRM Sdk 4.0
  5. Connect to CRM server, then to CRM instance [NB: Your User Should be in Deployment Manager group.
  6. Register your assembly… to open Register assembly dialog Press (Ctrl +A)
RegisterCRM Plugin Building

7.  Add step to your assembly to open Register new step Press(Ctrl + T).. Step is representing a response to an Action happened on CRM Entity..
For example: to response to an Update Event for Contact Entity.. You have to add a step like the following Picture:

Register%20CRM%20Plugin2

How to audit Privileges changes (Security Role) on MS CRM 4.0

One of the challenges that I face while I was working on auditing changes on the major entities at MS CRM 4.0 is to audit changes on Privileges… CRM 4.0 consider privilege entity as a special case this is why we need to build a special case for auditing changes here.

First of all, there is no supported Message (Event) to handle this case. So we have to enable couple of messages to be able to audit changes on security Roles. Those messages called:

1. AddPrivileges. –> this event will handle the creating of a new Security Role

2.  ReplacePrivileges. –> this message will handle adding/update/delete security privileges

The below script help you to enable those messages:

 

/*

Enable Privileges unsupported messages

*/

DECLARE @Message1   uniqueidentifier

DECLARE @Message2 uniqueidentifier

SET @Message1= (SELECT SdkMessageId FROM SdkMessageBase WHERE [Name] = ‘ReplacePrivileges’)

SET @Message2 = (SELECT SdkMessageId FROM SdkMessageBase WHERE [Name] = ‘AddPrivileges’)

UPDATE SdkMessageFilterBase SET IsCustomProcessingStepAllowed = 1

WHERE SdkMessageId = @Message1

UPDATE SdkMessageFilterBase SET IsCustomProcessingStepAllowed = 1

WHERE SdkMessageId = @Message2

After applying the above data script to MSCRM DB, you will be able to find those messages exposed for you on MS CRM 4.0 Plugin Registration tool so you will be able to register a plugin against those messages (Events). Now we need to build the Message handler to audit any changes, below steps showing you how to do that.

I am going to use the same code that audit regular entities with a little adjustments, the reasons of my adjustments are:

· The Pre-Image and Post-Image will not have enough info that needed by Audit handlers; thus I need to add a special handler for that.

· The Audit code that you can download from internet does not handle ReplacePrivileges/AddPrivileges Messages, thus we need to build a special case for that.

Note: To read more about default Audit component please refer to this article: "Auditing MS CRM 4.0 Record Changes"

To solve the problem (A), I have to add a Pre Handler for ReplacePrivilege Message, this is a very simple handler that will contains code to store the current Privileges (before doing update) on a shared Variable to be passed to the Post ReplacePrivilege message handler; below is the code of PreReplacePrivilege Message handler:

public class PreReplacePrivilege:IPlugin

{

#region IPlugin Members

public void Execute(IPluginExecutionContext context)

{

if (context.MessageName == "ReplacePrivileges")

{

if (context.InputParameters.Contains("RoleId"))

{

context.SharedVariables["PreRolePrivilagesValues"] =

Utilities.GetRolePrivilages(context.InputParameters.Properties["RoleId"].ToString(),

context.CreateCrmService(true));

context.SharedVariables["RoleId"] = context.InputParameters.Properties["RoleId"];

}

}

}

#endregion

}

static class Utilities

{

/// <summary>

/// Get privilages for Roles.

/// </summary>

public static Dictionary<string, string> GetRolePrivilages(string roleId, ICrmService crmService)

{

Microsoft.Crm.Sdk.Query.AllColumns cols = new Microsoft.Crm.Sdk.Query.AllColumns();

Dictionary<Guid, string> privileges = GetAllPrivilages(crmService); //Get list of all privileges

RetrieveRolePrivilegesRoleRequest request = new RetrieveRolePrivilegesRoleRequest();

request.RoleId = new Guid(roleId);

RetrieveRolePrivilegesRoleResponse response = (RetrieveRolePrivilegesRoleResponse)crmService.Execute(request);

Dictionary<string, string> rolePrigivleges = ResolvePrivilageNames(privileges, response.RolePrivileges);

return rolePrigivleges;

}

/// <summary>

/// Get all privilages on system

/// </summary>

/// <param name="crmService"></param>

/// <returns></returns>

private static Dictionary<Guid, string> GetAllPrivilages(ICrmService crmService)

{

Dictionary<Guid, string> privilages = new Dictionary<Guid, string>();

RetrievePrivilegeSetRequest requestp = new RetrievePrivilegeSetRequest();

requestp.ReturnDynamicEntities = true;

RetrievePrivilegeSetResponse responsep = (RetrievePrivilegeSetResponse)crmService.Execute(requestp);

foreach (DynamicEntity p in responsep.BusinessEntityCollection.BusinessEntities)

{

privilages.Add( ((Key)p["privilegeid"]).Value,p["name"].ToString());

}

return privilages;

}

/// <summary>

/// Resolving Privileges Names

/// </summary>

/// <param name="rolePrivilegesList"></param>

/// <param name="crmService"></param>

/// <returns></returns>

public static Dictionary<string, string> ResolvePrivilageNames(RolePrivilege[] rolePrivilegesList, ICrmServicecrmService)

{

Dictionary<Guid, string> privileges = GetAllPrivilages(crmService);

Dictionary<string, string> rolePrigivleges = new Dictionary<string, string>();

foreach (RolePrivilege r in rolePrivilegesList)

{

rolePrigivleges.Add(privileges[r.PrivilegeId], r.Depth.ToString());

}

foreach (KeyValuePair<Guid, string> pair in privileges)

{

if (!rolePrigivleges.ContainsKey(pair.Value))

rolePrigivleges.Add(pair.Value, "None");

}

return rolePrigivleges;

}

public static string GetPropertyValue(object property)

{

try

{

if (property.GetType() == typeof(CrmBoolean))

return ((CrmBoolean)property).Value.ToString();

else if (property.GetType() == typeof(CrmDateTime))

return ((CrmDateTime)property).UserTime.ToString();

else if (property.GetType() == typeof(Owner))

return ((Owner)property).Value.ToString();

else if (property.GetType() == typeof(Lookup))

return ((Lookup)property).Value.ToString();

else if (property.GetType() == typeof(Picklist))

return ((Picklist)property).Value.ToString();

else if (property.GetType() == typeof(StringProperty))

return ((StringProperty)property).Value.ToString();

else if (property.GetType() == typeof(LookupProperty))

return ((LookupProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(OwnerProperty))

return ((OwnerProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(PicklistProperty))

return ((PicklistProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(CrmDateTimeProperty))

return ((CrmDateTimeProperty)property).Value.UserTime.ToString();

else if (property.GetType() == typeof(KeyProperty))

return ((KeyProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmBooleanProperty))

return ((CrmBooleanProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmDecimalProperty))

return ((CrmDecimalProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmFloatProperty))

return ((CrmFloatProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmMoneyProperty))

return ((CrmMoneyProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmNumberProperty))

return ((CrmNumberProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CustomerProperty))

return ((CustomerProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(CustomerProperty))

return ((CustomerProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(StatusProperty))

return ((StatusProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(StateProperty))

return ((StateProperty)property).Value.ToString();

else if (property.GetType() == typeof(UniqueIdentifierProperty))

return ((UniqueIdentifierProperty)property).Value.Value.ToString();

else if (property == null)

return "";

else

return property.ToString();

}

catch

{ return ""; }

}

public static AuditDifferenceCollection AddDifferences(IMetadataService metaService, string entityName,DynamicEntity preImage, DynamicEntity postImage)

{

AuditDifferenceCollection col = new AuditDifferenceCollection();

System.Collections.Hashtable attributesMetadata =

MetadataHelper.GetEntityAttributeMetadata(metaService, entityName, Microsoft.Crm.Sdk.Metadata.EntityItems.IncludeAttributes);

//For any Message that has a Pre and/or Post Image. I will add the values to the Audit Differences.

foreach (Property prop in preImage.Properties)

{

if(prop.GetType()!= typeof(KeyProperty) && prop.Name!="modifiedby" && prop.Name != "modifiedon" && prop.Name != "createdby" && prop.Name != "createdon")

{

col.Add(new AuditDifference(prop.Name,attributesMetadata[prop.Name].ToString(),Utilities.GetPropertyValue(prop), ""));

}

}

foreach (Property prop in postImage.Properties)

{

if(prop.GetType()!= typeof(KeyProperty) && prop.Name!="modifiedby" && prop.Name != "modifiedon" && prop.Name != "createdby" && prop.Name != "createdon")

{

if (col.Contains(prop.Name))

{

AuditDifference diff = col[prop.Name];

diff.CurrentValue = Utilities.GetPropertyValue(prop);

col[prop.Name] = diff;

}

else

{

col.Add(new AuditDifference(prop.Name, attributesMetadata[prop.Name].ToString(),"",Utilities.GetPropertyValue(prop)));

}

}

}

return col;

}

public static AuditDifferenceCollection AddDifferences(IMetadataService metaService, string entityName,Dictionary<string, string> preValues, Dictionary<string, string> postValues)

{

AuditDifferenceCollection col = new AuditDifferenceCollection();

if (preValues != null && preValues.Count > 0)

{

foreach (KeyValuePair<string, string> entry in preValues)

{

col.Add(new AuditDifference(entry.Key + ":" + entry.Value, entry.Value, ""));

}

}

if (postValues != null & postValues.Count > 0)

{

foreach (KeyValuePair<string, string> entry in postValues)

{

if (col.Contains(entry.Key + ":" + entry.Value))

{

AuditDifference diff = col[entry.Key + ":" + entry.Value];

diff.CurrentValue = entry.Value;

col[entry.Key + ":" + entry.Value] = diff;

}

else

{

col.Add(new AuditDifference(entry.Key + ":" + entry.Value, "", entry.Value));

}

}

}

return col;

}

public static string AddAttributeToList(string value, string list)

{

if (list.IndexOf(value) == -1)

{

if (list == "")

list = value;

else

 

===================================

To solve problem (B) we need to adjust the Execute Method of  Create Class… this is the full code after adjustment for Create class:

==================================

public class Create : IPlugin

{

string m_config;

string m_secureConfig;

private string _relationshipAttribute = "";

private string _primaryAttribute = "";

public string Config

{

get { return m_config; }

set { m_config = value; }

}

public string SecureConfig

{

get { return m_secureConfig; }

set { m_secureConfig = value; }

}

public Create(string config, string secureConfig)

{

m_config = config;

m_secureConfig = secureConfig;

if (config.Trim() != "")

{

string[] configSettings = config.Split(‘;’);

for (int i = 0; i < configSettings.Length; i++)

{

string[] values = configSettings[i].Split(‘=’);

switch (values[0].ToString().ToLower())

{

case "primaryattribute":

_primaryAttribute = values[1].ToString().Trim().ToLower();

break;

case "relationshipattribute":

_relationshipAttribute = values[1].ToString().Trim().ToLower();

break;

}

}

}

}

public void Execute(IPluginExecutionContext context)

{

string attributes = "";

Audit audit = new Audit();

DynamicEntity PreImage = new DynamicEntity();

DynamicEntity PostImage = new DynamicEntity();

audit.Service = context.CreateCrmService(true);

audit.MetadataService = context.CreateMetadataService(true);

audit.EntityName = context.PrimaryEntityName;

audit.Type = context.MessageName;

audit.Name = context.PrimaryEntityName + " " + context.MessageName;

Dictionary<String, String> preValues = new Dictionary<string, string>();

Dictionary<String, String> postValues = new Dictionary<string, string>();

if (context.InputParameters.Properties.Contains("Target") &&

context.InputParameters.Properties["Target"] is Moniker)

{

Moniker moniker = (Moniker)context.InputParameters.Properties["Target"];

audit.RecordID = moniker.Id.ToString();

}

else if (context.InputParameters.Properties.Contains("EntityMoniker") &&

context.InputParameters.Properties["EntityMoniker"] is Moniker)

{

Moniker moniker = (Moniker)context.InputParameters.Properties["EntityMoniker"];

audit.RecordID = moniker.Id.ToString();

}

else if (context.InputParameters.Properties.Contains("Target") &&

context.InputParameters.Properties["Target"] is DynamicEntity)

{

//if the transaction is create then get the ID from the OutputParameters

if (context.OutputParameters.Contains("id"))

audit.RecordID = context.OutputParameters.Properties["id"].ToString();

//pull the KeyProperty from the entity.

foreach (Property prop in ((DynamicEntity)context.InputParameters.Properties["Target"]).Properties)

{

if (prop.GetType() == typeof(KeyProperty))

{

audit.RecordID = ((KeyProperty)prop).Value.Value.ToString();

break;

}

}

}

else if (context.MessageName == "ReplacePrivileges" ||

context.MessageName == "AddPrivileges" ||

context.MessageName == "RemovePrivilege") //Unsupported Message and it needs special handling

{

if(context.InputParameters.Properties.Contains("RoleId"))

audit.RecordID = ((Guid)context.InputParameters.Properties["RoleId"]).ToString();

else if(context.SharedVariables.Contains("RoleId"))

audit.RecordID = ((Guid) context.SharedVariables["RoleId"]).ToString();

//Pull Pre state of previleges from shared variable populated on PreStage plugin

if (context.SharedVariables.Contains("PreRolePrivilagesValues"))

preValues = (Dictionary<string, string>)context.SharedVariables["PreRolePrivilagesValues"];

else

preValues = new Dictionary<string, string>();

if (context.InputParameters.Contains("Privileges"))

{

postValues = Utilities.ResolvePrivilageNames(

(RolePrivilege[])context.InputParameters["Privileges"], audit.Service);

}

else

postValues = new Dictionary<string, string>();

}

//Get the Pre and Post Images

if (context.PreEntityImages.Properties.Contains("Images") && context.PreEntityImages.Properties["Images"] isDynamicEntity)

PreImage = (DynamicEntity)context.PreEntityImages.Properties["Images"];

if (context.PostEntityImages.Properties.Contains("Images") && context.PostEntityImages.Properties["Images"] isDynamicEntity)

PostImage = (DynamicEntity)context.PostEntityImages.Properties["Images"];

//Compare the images values.

//Messages not support Pre/Post images.

if (string.IsNullOrEmpty(PreImage.Name) && string.IsNullOrEmpty(PostImage.Name))

{

audit.AuditDifferences = Utilities.AddDifferences(audit.MetadataService, context.PrimaryEntityName, preValues, postValues);

}

else //Messages support Pre/Post images.

{

audit.AuditDifferences = Utilities.AddDifferences(audit.MetadataService, context.PrimaryEntityName, PreImage, PostImage);

}

foreach (AuditDifference diff in audit.AuditDifferences)

{

if (context.MessageName == "AddPrivileges" || context.MessageName == "ReplacePrivileges")

diff.ReplaceAttributeName = string.Format("Privilege:{0}", diff.AttributeName.Substring(0, diff.AttributeName.IndexOf(":")));

if (diff.CurrentValue != diff.PreviousValue)

attributes = Utilities.AddAttributeToList(diff.AttributeDisplayName, attributes);

}

if (_relationshipAttribute.Trim() != "" && audit.RecordID.Trim() != "" && context.MessageName != "Delete")

audit.Relationship = new EntityRelationship(_relationshipAttribute, new Guid(audit.RecordID));

audit.Attributes = attributes;

if (!context.PreEntityImages.Properties.Contains("Images")

&& !context.PostEntityImages.Properties.Contains("Images")

&& context.MessageName != "ReplacePrivileges")

{

audit.Create();

}

else

{

if (attributes.Trim() != "")

audit.Create();

}

}

I am attaching below the  3 classes I made changes on, I got the original classes and do the changes to them.

I hope you will have this useful and will solve your issue

 

Download Code

How to Know the Execution Time of SQL Statements in Simple Way

When client report to you a performance issue in certain area on your system, you start troubleshooting and tackling the issue. the performance bottleneck might be everywhere on your system, it might be on front-end, business layer, data access layer, … etc. The scope of this article is to check the execution time taken for certain SQL statement till you get the result out from the DB. this would  very helpful if the performance issue is at  data retrieval.  after figuring out the performance bottleneck is at data retrieval, the solution might be as easy as adding index for some of table’s columns. but in most cases you might get into a trouble of changing the body of SQL statements to have better performance. so you need a tool to assess your changes. SQL 2008 IDE shipped with a built-in tool that I found so much helpful and made my life much easier.

if you notice there is a small icon on tool bar called “Include Client Statistics”, it is by default not enabled. if you enable it and try to execute a sql statement, you will get a new tab at the result panel. below is snapshot of the new tab on the result panel

 

building

 

SQLClientStaticsResultPanel

 

Notice the statics between different trials. it will keep the statics up to 10 trials. The statics including with some visual graphics to let you note the effect of your changes weather it increase the execution time or it reduced it.
Try it and you will find it so useful!

Be Simple winner

"Be Simple winner" this is a phrase I heard from a friend of mine long a time ago. He was advising me in regards to couple of things. After thinking of it I believed it is totally a true statement. our discussion was about software development industry specifically but I believe this statement can be reflected to other industries as well, being a simple winner does not means to deliver a bad quality software that does not meet your client requirements. being simple winner means to develop a software that meets client requirements and not exceed the requirements to extra requirements that your client is not in need for it. You should not deliver something that is extra for your client and they might not get benefited from . This does not means to ignore the basic software requirements that your client did not ask for explicitly like security and performance requirements. actually ignoring such a basic requirements might make your product not useable at all and your efforts will ends up with a big failure because of ignoring these basic requirements.

Being simple winner is targeting to deliver software that will make your client happy and at the same time meets the project success factors like being within budget, deadline, high quality… etc deliverables.

Personally I believe being simple winner can be applied in all aspects on your life not only at work level.

Don’t Delete Negative Reviews/Comments

I had discussion with a friend of mine couple of days about negative reviews that somebody might have on their site. He was after convincing me to simply DELETE negative comments or reviews. His idea is simply hide that negative thing from being displaying on your website and protect yourself from it.

My opinion was totally against that. I believe I should keep negative comments just like keeping positive comments. There are many reasons that letting you doing that. Simply it is part of honest relationship between you and your readers/customers. It is a great chance to have conversation with your reader/customer and to get his feedback and if he/she has the correct opinion, then you need to fix that immediately.

What trigger me to write this article not only the conversation I have with my friend. The trigger is mainly an article I just read about the same subject. The author of this article is Lisa Barone s Co-Founder and Chief Branding Officer of Outspoken Media, Inc. I strongly recommend to read this article.

How to Make your URL shorter

For many reasons you might ends you having a very long URL for certain pages, distributing the long URL might be an issue for you as people usually does not remember long URLs and they like having short URLs.

Today there is many websites that make your long URLs shorter and make your life easier. Personally I checked http://tinyurl.com  site and it worked just perfectly for me. I am pretty sure there are more sites that are doing the same thing for you. But I am recommending this one for you.

Dealing with Time.. Be Careful!

Dealing with time is something crucial that we need to a pay very close attention to it. I like the aphorism  that say " Time is like a river. You can’t touch the same water twice", This is very true statement and I am having it in front of me every single minute in my every day.

In my past days I wasted many days doing not useful things. I have a guilty feeling because of that and I hope if I can go back to fix that. But there is no Time-Machine that will get me back to that time to fix my mistakes. I hope if I can have a time-machine that will lead me to correct my mistakes I made in the past. I learned that in the hard way while I could learn it in the easy way if I listen to my father or teacher when they were telling me about an Arabic aphorism that says "Time life like a blade, if you did not kill it; it is going to kill you" meaning if you did not utilize your time in a very useful things, this will fire back on you after a while.

These days, I am trying to utilize every single minutes in my day and optimize my life for that. Well, I admit this is very hard but I would not make the same mistake as the old days. One thing that trigger me to write this article is a discussion I have with one of my family members about the impotency of time and how we should deal with it.He wanted to spend most of his time playing games and at coffee-shops. I was totally against this while he was trying to convenes me with his thought which I was totally disagree on them.

I believe you have to do funny things and spend time with family and friends but that does not means wasting the whole holiday days doing such a stuff. Playing Computer games , gambling , and spend the whole night with friends is not the best thing that you can do during holidays. For me, I need to balance between spending time with family/friends and reading and enhance my knowledge.

I would love to hear from you on this topic, Please share your thoughts on this topic by commenting on this article

Outsourcing What and When?

Outsourcing becoming part of the core business of any successful business these days, one of the very nice articles I read couple of weeks ago was about outsourcing. It is explaining the outsourcing in a very good way and explain what to Outsource and when to do that. The subject of this article was "Outsourcing: What and When?" I strongly recommend to have couple of minutes reading this site.

Date different in SQL server Vs Oracle

 

While setting back in my chair today and thinking of the power that MS tools giving to us , I decided to do a very small compare of things I can do in SQL server and how can I do the same thing in Oracle.

I decided to do a very primitive operation on both DBs… something is very silly. Just to get the differences between 2 dates in Weeks. This is very easy thing

In SQL Server I could do that in single line of SQL Statement

SELECT DATEDIFF (ww, ’03/20/1983′, ’11/03/2010′) DiffInWeeks_SQLServer

While I could do the same operation in Oracle by a long equation comparing with the one I have for SQL Serer:

SELECT   (to_date(’03/20/1983′,’mm/dd/yyyy’)  – to_date(’11/03/2010′,’mm/dd/yyyy’) 

             )  / 7.0) DiffInWeeks_Oracle

FROM DUAL;

 

I still like working on Microsoft platforms.