Sunday, 15 June 2014

User Profile Synchronization reporting script

User Profile Synchronization Service in SharePoint have always been a sensitive topic. For the full featured User SharePoint Profile Synchronization we need to have this service instance running. In SharePoint 2013 we have lightweight "mode" called SharePoint Active Directory Import that is leveraging the System.DirectoryServices .NET classes and when we use this mode we don't need User Profile Synchronization Service running .
Under the hood SharePoint relies on a version of Forefront Identity Management to do the profile synchronization. Unfortunately sometimes the headache does not stop when you manage to properly start/restart the service instance. The profile information synchronization issues can be very visible for the users.
So we have a customer that is using the classic SharePoint Profile Synchronization with SharePoint 2013 to sync from AD.
The customer have a large number of domains that are hosted on remote sites around the globe. There isn't  something like Read-Only DCs  to be closer to the SharePoint and that can replicate from the remote domains and the SharePoint have to contact the remote DCs to do the profile synchronization.
Because of the distance between the SharePoint and the domains that should sync from, we often end up with unsuccessful profile sync. operations for some of the domains.
In this case we need to find a way to be notified for such issue on time and take some actions. It would be nice if SherePoint provide something like the crawl log  where you can see the status of the operation.
We can see the status if we go to the server where the User Profile Synchronization Service is running and open "C:\Program Files\Microsoft Office Servers\15.0\Synchronization Service\UIShell\miisclient.exe".

Some of the events can also be logged in the Event Viewer of the server.

I did some research and found that there is WMI Namespace for Microsoft Identity Integration Server (MIIS), there are some promising classes like ManagementAgent and RunHistory, also the WMI query can be executed remotely. For each Synchronization Connection in the User Profile Application we have a FIM Management Agent (MA) that link specific connected data source to FIM. Management Agent is responsible for moving the data source to FIM. For the usual setup where SharePoint is synchronizing profile information from AD DS the naming of the agent is MOSSAD-*CONNECTION_NAME*. For example, if we have synchronization connection named CONTOSO.COM, the name of the MA will be MOSSAD-CONTOSO.COM.
So I wrote a script that can do a report on the sync. operations for a given time. The report is in a form of CSV file and it can be mailed like an HTML table. Let say that you have scheduled an Incremental Synchronization  at 1:00 AM and usually entire process finishes for 1 hour and you want to have the status of the operation when it finish. You can schedule the script to run at 2:30 AM with this parameters:

.\Fim-SyncReport.ps1 -ServerName '' -Hours 3 `
-FromMailAdress '' `
-MailAdress '','' `
-SMTPServer '' `
-ReportLoction '\\fileserver\fimnightreport'

This will do the WMI query on the server where the User Profile Synchronization Service instance is running, will save the report for the last 3 hours on a fileshare and will send the report via mail. The report will contain the MA name, status, synchronization profile, when the operation started, the number of sync. errors, discovery errors and retry errors. The status field is very important the script will take all the operations that are not with status "success", the status can be very helpful when you troubleshoot synchronization issue. Complete list of the RunStatus return string can be found in this MSDN Article . If all operations are in success no report will be generated and no mail will be send.
The report looks like this when it is sent via mail :

The key function from the script is :

function Get-FimMARuns
    $timeSpan = New-TimeSpan -Hours $Hours
    $nowUTC = (Get-Date).ToUniversalTime()
    $timeToStart = $nowUTC.Add(-$timeSpan)
    $filter = ("MaName = '{0}'" -F $MaName)
    $allHistory = Get-WmiObject -ComputerName $ComputerName `
                  -Class MIIS_RunHistory `
                  -Namespace root/MicrosoftIdentityIntegrationServer `
                  -Filter $filter
    ForEach ($history in $allHistory)
        $startTimeinDateTime = $history.RunStartTime | Get-Date
        if ($startTimeinDateTime -gt $timeToStart)
            Write-Output $history

In this function we are utilizing the MIIS_RunHistory class to get all the runs for given MA name (we get all MAs staring with 'MOSS' in different function ). Then we are calculating a filter based on the start time so we can get the one that fit to the timeframe for our report.
When we have all operation that we need we can read the information from them. The class return objects for every run (run history entry). We can see the full information with this method:

[xml]$asXML = $faultyOp.RunDetails().ReturnValue

The history entry has method RunDetails that has property ReturnValue . When we get this property we are receiving an XML with all details from the run, then we can get whatever value we want. You can get the script from the link below and edit it (specific filtering by MA,Sync Profile, Status ...etc.) as you find useful in your case. Just remove the underscore from the file extension, this is a zip file with the script and mail body template.

Download From: TechNet Gallery

No comments:

Post a Comment