November 27, 2010

Check Replicating Directory Changes permission via PowerShell

So, as you know, we need ‘Replicating Directory Changes’ permissions for correct work of a User Profiles synchronization (ForeFront Identity Manager).

How to set these permission you can read some other articles:

But how to check that these permission was granted for some user? Of course, we can accomplish this task via PowerShell.

Just change the $userName variable in the script below and run it.

Output like:

User ‘EXAMPLE\User’:
    has a 'Replicating Directory Changes' permission on 'DC=example,DC=local'
    has no a 'Replicating Directory Changes' permission on 'CN=Configuration,DC=example,DC=local'

Check-ADReplicatingChangesPermission.ps1

function Check-ADUserPermission(
   
[System.DirectoryServices.DirectoryEntry]$entry,
 
   
[string]$user,
 
   
[string]$permission
)
{
   
$dse = [ADSI]"LDAP://Rootdse"
    $ext = [ADSI]("LDAP://CN=Extended-Rights," + $dse.
ConfigurationNamingContext)

   
$right = $ext.psbase.Children |
 
       
? { $_.DisplayName -eq $permission
 }
   
   
if($right -ne $null
)
    {
       
$perms = $entry.psbase.ObjectSecurity.Access |
            ? { $_.IdentityReference -eq $user } |
            ? { $_.ObjectType -eq [GUID]$right.RightsGuid.
Value }

       
return ($perms -ne $null
)
    }
   
else
    {
       
Write-Warning "Permission '$permission' not found."
        return $false
    }
}


# Globals

$userName = "EXAMPLE\User"
$replicationPermissionName = "Replicating Directory Changes"

# Main()

$dse = [ADSI]"LDAP://Rootdse"

$entries =
 @(
   
[ADSI]("LDAP://" + $dse.defaultNamingContext),
    [ADSI]("LDAP://" + $dse.configurationNamingContext));

Write-Host "User '$userName': "
foreach($entry in $entries
)
{
   
$result = Check-ADUserPermission $entry $userName $replicationPermissionName
   
   
if($result
)
    {
       
Write-Host "`thas a '$replicationPermissionName' permission on '$($entry.distinguishedName)'"
 `
           
-ForegroundColor Green
    }
   
else
    {
       
Write-Host "`thas no a '$replicationPermissionName' permission on '$($entry.distinguishedName)'"
 `
           
-ForegroundColor Red
    }
}

And, of course, I hate it!

Sincerely yours,

Andrew MossHater.

October 27, 2010

The SharePoint 2010 search privileges issue

One of our clients took place the following situation. All users can’t find anything via SharePoint Search center.

The SharePoint Search Service Application was successfully created, The Content was crawled and indexed (index contains about 10 thousands documents).

Symptoms:

  • If you try to find something search results always is empty,
  • Search results is not empty only If you run a browser with the SharePoint Central Administration Pool Account.
  • You can also observe empty scopes in site collection’s options except the People Scope (Url: /_layouts/viewscopes.aspx),

Screenshot: Empty scopes except People Scope

The solution was found here.

This is an insufficient privileges issue. An account which was used for the Search Service Application Pool had no privileges to read user properties from Active Directory. This information need for a security trimming feature of the SharePoint Search.

For resolving the issue you need to add the SharePoint Search Application Pool Account to the Windows Authorization Access group by using the Active Directory Users and Computers snap-in.

And, as usual, I hate it!

October 12, 2010

HOWTO: Create BSC connection with User Profiles via PowerShell

As I described earlier, you can create synchronization connection with User Profiles for Active Directory via PowerShell. And what about the Business Connectivity Services? It’s also possible, of course!

As well as in the previous post, the core of our script is the UserProfileConfigManager class that contains the ConnectionManager property with several methods for adding new connections with user profiles.

Screenshot: UserProfileConfigManager class

The main difference that this time we'll use the AddBusinessCatalogConnection method which has eight parameters (it’s much more than almost any method in the .Net BCL).

public BusinessDataCatalogConnection AddBusinessDataCatalogConnection(
string
displayName,
string
systemName,
string
entityName,
string
entityNamespace,
string
profilePropertyName,
string
filterName,
string
mappedPropertyAttributeName, List<DSMLAttribute> attributeList )

There are simple parameters, except the last: the list of instances of DSMLAttribute (non-documented) class. This class is a simple set of properties, as you can see in the picture below.

Screenshot: DSMLAttribute class

Note: DSML – an acronym that means the Directory Services Markup Language. You can find more information about that on Wikipedia.

Before we begin, I assume that we already have an entity in the BCS model that has at least one method “Read Item” (Specific Finder). Identifier of the entity is a field containing a user account name (it will be mapped to the profile property “Account Name”).

Now, we can code our script. Listing below:

Add-BCSConnection.ps1

Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue

function Get-First { return @($input)[ 0] }
function Get-Last  { return @($input)[-1] }

function Convert-ToList($inputObject, [System.String]$Type
)
{
   
begin
    {
       
if($type -eq $null -or $type -eq ''
) 
        {
           
$type = [string]
        }
   
       
$list = New-Object System.Collections.Generic.List[$type]
    }
   
   
process { $list.Add($_
) }
   
   
end { return ,$list
 }
}


function Get-SPServiceContext
(
   
[Microsoft.SharePoint.Administration.SPServiceApplication]$profileApp
)
{
   
if($profileApp -eq $null
)
    {
       
# Get first User Profile Service Application
        $profileApp = Get-SPServiceApplication |
 
           
? { $_.TypeName -eq "User Profile Service Application" } |
 
           
Get-First
    }
   
   
return [Microsoft.SharePoint.SPServiceContext]::
GetContext(
       
$profileApp.ServiceApplicationProxyGroup,
 
       
[Microsoft.SharePoint.SPSiteSubscriptionIdentifier]::
Default)
}


function Convert-ToDSMLSyntax([System.String]$typeName
) 
{
   
$DSMLSyntaxType = [Microsoft.Office.Server.UserProfiles.Synchronization.DSMLSyntax, Microsoft.Office.Server.UserProfiles.Synchronization, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c]
   
   
if($typeName -match "System.DateTime"
)
    {
       
return $DSMLSyntaxType::
Date
    }
       
   
if($typeName -match "System.Int32"
)
    {
       
return $DSMLSyntaxType::
Integer
    }
   
   
if($typeName -match "System.Byte"
)
    {
       
return $DSMLSyntaxType::
Binary
    }
   
   
if($typeName -match "System.Boolean"
)
    {
       
return $DSMLSyntaxType::
Boolean
    }
       
   
return $DSMLSyntaxType::
String
}


# Global

$DSMLSyntaxType = [Microsoft.Office.Server.UserProfiles.Synchronization.DSMLSyntax, Microsoft.Office.Server.UserProfiles.Synchronization, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c]
$DSMLAttributeType = [Microsoft.Office.Server.UserProfiles.Synchronization.DSMLAttribute, Microsoft.Office.Server.UserProfiles.Synchronization, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c]

$connectionName = "BCS Connection"
$entityName = "ExternalUserInfo"
$entityNamespace = "ExternalUserInfoDatabase"
$profilePropertyName = "AccountName"

# Main()

$serviceContext = Get-SPServiceContext

# Prepare parameters

$entity = Get-SPBusinessDataCatalogMetadataObject -BdcObjectType Entity
 `
                                                 
-ServiceContext $serviceContext
 `
                                                 
-Name $entityName
 `
                                                 
-Namespace $entityNamespace
   
$entityIdentifier = $entity.Identifiers | Get-First

$specificFinder = $entity.Methods |
 
   
% { $_.MethodInstances } |
    ? { $_.MethodInstanceType -eq "SpecificFinder" } |
 
   
Get-First

$attrList = $specificFinder.ReturnTypeDescriptor.ChildTypeDescriptors |
 
   
%
 {
       
$attribute = New-Object $DSMLAttributeType
       
       
$attribute.ID = $_.
Name
       
$attribute.Name = $_.
Name
       
$attribute.Indexible = $false
        $attribute.SingleValued = $true
        $attribute.Syntax = Convert-ToDSMLSyntax($_.
TypeName)
       
       
$attribute
    } | Convert-ToList -Type $DSMLAttributeType

# Important: Special property for BCS connection!

$attribute = New-Object $DSMLAttributeType
   
$attribute.ID = "SPS-DistinguishedName"
$attribute.Name = "SPS-DistinguishedName"
$attribute.Indexible = 
$true
$attribute
.SingleValued = 
$true
$attribute
.Syntax = Convert-ToDSMLSyntax("System.String")

$attrList.Add($attribute);

# Create BCS Connection

$configMgr = New-Object Microsoft.Office.Server.UserProfiles.UserProfileConfigManager($serviceContext)
$connectionMgr = $configMgr.ConnectionManager

if(!$connectionMgr.Contains($connectionName
))
{
   
$connectionMgr.
AddBusinessDataCatalogConnection(
       
<# displayName: #> $connectionName,
 
       
<# systemName: #> $entity.LobSystem.Name,
 
       
<# entityName: #> $entity.Name,
 
       
<# entityNamespace: #> $entity.Namespace,
 
       
<# profilePropertyName: #> $profilePropertyName,
 
       
<# filterName: #> $null,
 
       
<# mappedPropertyAttributeName: #> $entityIdentifier.Name,
 
       
<# attributeList: #> $attrList)
}

Note: If you try to execute code and get error:

Exception calling "AddBusinessDataCatalogConnection" with "8" argument(s): "Could not connect to http://[server-name]:[random-port]/ResourceManagementService/MEX. TCP error co
de 10061: No connection could be made because the target machine actively refused it [ip-address]:[random-port]. "
At C:\[some-path]\Add-BCSConnection.ps1:+     $connectionMgr.AddBusinessDataCatalogConnection <<<< (
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

You must start Forefront Identity Manager Service (via services.msc console) and try again.

That’s all.

And, of course, I hate it!

October 10, 2010

CryptographicException from OWSTIMER.EXE

How often have you seen this window?

CryptographicException

Every day, I believe. So, this is not a bug! This is a feature. Some quotes from our gurus:

Stefan Goßner: The problem here is that the encryption key was created on a specific thread which was impersonated under a specific users account. When the .NET Finalizer processes the encryption key while the timer service shuts down it executed on a different thread which is not impersonated - so the key does not exist and you get an exception like "keyset does not exist".

Paul Andrew: If you see this error message from SharePoint 2010 you can relax, nothing bad is happening. When SharePoint 2010 and Visual Studio 2010 are both installed on the same machine you may see this error every 24 hours. This occurs when the OWSTimer service has a regular process recycle and in the shutdown of the old process an exception is raised. The exception doesn’t interfere with the normal process shutdown and recycle and is only ever seen if you have a JIT debugger installed on the machine. You should never see this error on a production SharePoint 2010 server, because you should not be installing Visual Studio 2010 on those servers. You can safely ignore these exceptions and close the window, or leave it there. You actually cannot debug the process, because it will already have been closed by the time you click the button and start your debugger.

And you can only disable visual studio debugging feature If you want to get rid of this annoying thing.

More information:

And, of course, I hate it!