Sunday, October 14, 2012

Mapping DateTime properties in SharePoint User Profile using BCS

Just a quick one this time.

When importing a field to a SharePoint UserProfile DateTime type in the User Profile. You normaly have a BCS model with a property of System.DateTime and map that to the UserProfile. However this won't work, you will get errors like this:
"Microsoft.Office.Server.UserProfiles.PropertyInvalidFormatException: Invalid Date Format: Input must match smalldatetime data type, or be a string that parses to match the Guid data type ---> System.FormatException: String was not recognized as a valid DateTime.   
at System.DateTimeParse.ParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style)   
at Microsoft.Office.Server.UserProfiles.UserProfileGlobal.ValidatedDate(Object value, PropertyDataType propDataType, SiteContext si)     -
-- End of inner exception stack trace ---   
at Microsoft.Office.Server.UserProfiles.UserProfileGlobal.ValidatedDate(Object value, PropertyDataType propDataType, SiteContext si)   
at Microsoft.Office.Server.UserProfiles.UserProfileGlobal.ValidatedSingleValue(Object value, ProfileSubtypeProperty prop, PropertyDataType

propDataType, UserFormat userFormat, UserProfileApplicationProxy userProfileApplicationProxy, Guid partitionID, SiteContext si)   
at Microsoft.Office.Server.UserProfiles.UserProfile.BulkPropertiesUpdate(Int64 importExportId, Hashtable properties, String strAccountName)."

To fix you need to do the following:

- The property in your BCS model should still be 'System.DateTime'. Otherwise you cannot map the BCS to the UserProfile Date typed property.
- However make sure your BCS code outputs a string in the following format: yyyyMMddHHmmss.0Z (like: .ToString("yyyyMMddHHmmss.0Z", CultureInfo.InvariantCulture);
This will make sure the output can be converted to a DateTime.

If you want more details use reflector on:
- class Microsoft.Office.Server.UserProfiles.UserProfileGlobal
- method private static DateTime ValidatedDate(object value, PropertyDataType propDataType, SiteContext si)

Tuesday, April 24, 2012

How to add a Windows account to Security Group in a claims based SharePoint 2010 environment

In a timer job I added users to a certain SPGroup and added this group to some libraries with contribute rights. When I logged is with that user account it didn’t have the contribute rights. The problem was that the Windows account was added instead of the claims based user.

At first I just used the following code:

   1: String loginName = "SP2010\user1";
   2: SPGroup group = web.SiteGroups["somegroup"];
   3:  
   4: SPUser user = web.EnsureUser(loginName);
   5: if (user != null)
   6: {
   7:   group.AddUser(user);
   8: }

However this added a user as formatted in this XML:

<User ID="442" Sid="S-1-5-21-4190988674-4107964418-2216591577-1137" Name="Some name" LoginName="SP2010\user1" Email="test@test.com" Notes="" IsSiteAdmin="False" IsDomainGroup="False" Flags="0" />

I changed it to look for the correct SPUser using this code snippet:
   1: String loginName = "SP2010\user1";
   2:  
   3: SPClaimProviderManager mgr = SPClaimProviderManager.Local;
   4: if (mgr != null)
   5: {
   6:   SPClaim claim = new SPClaim(SPClaimTypes.UserLogonName, loginName, "http://www.w3.org/2001/XMLSchema#string", SPOriginalIssuers.Format(SPOriginalIssuerType.Windows));
   7:   claimLoginName = mgr.EncodeClaim(claim);
   8: }
   9:  
  10:  
  11: SPGroup group = web.SiteGroups["somegroup"];
  12: SPUser user = web.EnsureUser(claimLoginName);
  13: if (user != null)
  14: {
  15:   group.AddUser(user);
  16: }

This will generate a claim that represents the windows account “SP2010\user1”. This will find the correct SPUser, the XML is:

<User ID="255" Sid="" Name="Some name" LoginName="i:0#.w|SP2010\user1" Email="test@test.com" Notes="" IsSiteAdmin="False" IsDomainGroup="False" Flags="0" />

Notice the formatting of the LoginName.

Now the correct user account (in claims format) is added to the library with contribute rights the user logging in with SP2010\user1 can contribute.

Monday, April 16, 2012

Remote Hyper-V Management from client in different Domain

Recently the employees of Yellow & Red migrated the laptops to another domain. However the Hyper-V was left as-is and still run in the Yellow & Red domain. The problem is that you cannot manage the Hyper-V using the standard Hyper-V Remote Manager as you are not in the same domain.

You need to configure a lot of stuff. Thanks to John Howard we just need to run a few scripts.

Follow these steps:

Download: HVRemote.wsf from the Hyper-V Remote Management Configuration Utility

On Hyper-V server execute the following commands:

cscript hvremote.wsf /add:domain\user

On Client: (in elevated mode)

cscript hvremote.wsf /mmc:enable

cscript hvremote.wsf /anondcom:grant

Important note for the next steps:
ServerComputerName should be the name as shown in Hyper-V server, run “sconfig.cmd” and see “Computer name” at number 2. Otherwise you’ll get issues trying to query the root\cimv2 WMI namespace).

Add credentials to your credential store:
cmdkey /add:ServerComputerName /user:ServerComputerName\UserName /pass

- add a line to hosts file. In my case I cannot resolve ServerComputerName.

192.1.3.4   ServerComputerName

To test the communication run this line on the client:

cscript hvremote.wsf /show /target:ServerComputerName

You should now be able to connect to your Hyper-V server.