Sunday, December 12, 2010

In Search of Export-Not-Reimported Errors

Lately I’ve been scripted the heck out of the Run-History.  This facility has been in the product forever but now PowerShell makes it a lot easier to slice and dice thanks to the way PowerShell makes WMI and XML very easy.

The oddity here is that the CSObject in the Sync engine contains a lot of useful error detail, as well as the holograms.  There’s a lot of data packed into those CSObjects, and pretty much the only facilities for getting at them are WMI and CSExport.exe.

The MIIS_CSObject WMI class allows easy access to the CSObjects but unfortunately the query functionality is very limited.  You need to know the DN or the GUID of the CSObject in order to find it with WMI.  My guess is that this is because the rest of the attributes in the CSObject are packed away as binary blobs in the underlying SQL database.

Anyhow, my point is that there is a lot of detail on the CSObject but the Export-Not-Reimported details are stored in RunHistory, not on the CSObject.

The script below is a sample for getting the run history from the server, then getting the RunDetails XML.  The RunDetails XML can then be parsed to dig out the export-not-reimported errors, which I’ll show in another post.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023

### Use WMI to get the Management Agent
$managementAgent = Get-WmiObject -Class MIIS_ManagementAgent -Namespace root/MicrosoftIdentityIntegrationServer -Filter "name='HoofHearted'"

### Construct a filter to get the management agent's last run
$filter = ("RunNumber='{0}'" -F $managementAgent.RunNumber().ReturnValue)

### Use WMI to get the RunHistory
$theRun = Get-WmiObject -Class MIIS_RunHistory -Namespace root/MicrosoftIdentityIntegrationServer -Filter $filter

### Call the RunDetails() method to get the RunHistory RunDetails XML
[xml]$runHistoryDetails = $theRun.RunDetails().ReturnValue
if ($runHistoryDetails -ne $null)
{
    Write-Host " ...Success" -ForegroundColor Green
}
else
{
    ### There have been bugs with the WMI provider for ILM/FIM
    ### When it fails it usually returns null
    ### But on rare occasions I've also seen it fail with out-of-memory errors (even though the box had 128GB, and over 100GB free)
    Write-Host " ...Error" -ForegroundColor Red
    Continue
}

2 comments:

Bob Bradley said...

Thanks for this post Craig - I am now revisiting my thoughts around using CSExport and audit drop files in lieu of parsing RunDetails() in the hope this is way more efficient. I am not 100% sure yet if it will cover all bases, but we will see.

In the meantime I just ran into a problem where I had a failure with your script which turned out to be multiple MAs with the same RunNumber. In this case there are 2 XML documents returned instead of just the 1, and of course the ReturnValue fails the type cast to [xml].

I found that I was easily able to resolve this with the extra filter component:

### Construct a filter to get the management agent's last run
$filter = ("RunNumber='{0}' and MAName='{1}'" -F $managementAgent.RunNumber().ReturnValue, $managementAgent.Name)

Craig Martin said...

Hi Bob! You should also check out the PowerShell commands that target RunHistory:
http://fimpowershellmodule.codeplex.com/wikipage?title=Summarize%20Run%20History%20Details

RunNumber is unique to an MA, not to RunHistory.

FYI: there is even more detail in those CSEntry objects but unfortunately WMI only shows a subset of it. I don't think hacking the database or Sync APIs is a great idea for production systems, you will find a lot more detail there.