Thursday, May 9, 2013

ResolveGrammarActivity doesn't like ma-data SyncConfig-id


I tried to set up a workflow that grabs the MA ID and display name whenever an MA changes, but the grammar resolver doesn't like the SyncConfig-id attribute of the ma-data object.

This seemed so close to an error I troubleshot before, but this time I have no control over the attribute type (which is an indexed string, BTW).

Grammar expression: [//Target/SyncConfig-id]

Error:
System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.ResourceManagement.WFActivities.Resolver.GetDisplayStringFromGuid(Guid id, String[] expansionAttributes) at Microsoft.ResourceManagement.WFActivities.Resolver.ReplaceGuidWithTemplatedString(Match m) at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator) at Microsoft.ResourceManagement.WFActivities.Resolver.GetStringAttributeValue(Object attribute) at Microsoft.ResourceManagement.WFActivities.Resolver.ResolveEvaluatorWithoutAntiXSS(String match, ResolverOptions resolveOptions) at Microsoft.ResourceManagement.WFActivities.Resolver.ResolveEvaluatorForWithAntiXSS(String match, ResolverOptions resolveOptions) at Microsoft.ResourceManagement.WFActivities.Resolver.ReplaceMatches(String input, Boolean useAntiXssEncoding, ResolverOptions resolveOptions) at Microsoft.ResourceManagement.Workflow.Hosting.ResolverEvaluationServiceImpl.ResolveLookupGrammar(Guid requestId, Guid targetId, Guid actorId, Dictionary`2 workflowDictionary, Boolean encodeForHTML, String expression) at Microsoft.ResourceManagement.Workflow.Activities.ResolveGrammarActivity.Execute(ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime) at System.Workflow.Runtime.Scheduler.Run()

Wednesday, April 17, 2013

The term 'Export-FIMConfig' is not recognized as the name of a cmdlet, function, script file, or operable program

This one had me stumped for a little while.  Turns out, there were four versions of the following files hanging out in the GAC.  I guess the uninstall process didn't clean these up.  I removed all of the older ones, and my scripts started working!

C:\windows\assembly
Microsoft.IdentityManagement.Logging
Microsoft.ResourceManagement

Monday, March 25, 2013

One small addition to Powershell module for end-to-end attribute flows

Here are some tweaks to the Get-FimSyncConfiguration.psm1 module to include export attribute flows with empty metaverse values in the end-to-end attribute flows. See highlighted sections below.

Reference version:
FIM PowerShell Modules v2.1
http://fimpowershellmodule.codeplex.com/releases/view/98374

Get-ExportAttributeFlow

<#
   .SYNOPSIS
   Gets the Export Attribute Flow Rules from Sync Server Configuration

   .DESCRIPTION
   Reads the server configuration from the XML files, and outputs the Export Attribute Flow rules as PSObjects

   .OUTPUTS
   PSObjects containing the synchronization server export attribute flow rules
  
   .EXAMPLE
   Get-ExportAttributeFlow-ServerConfigurationFolder"E:\sd\IAM\ITAuthorize\Source\Configuration\FimSync\ServerConfiguration"

#>
Function Get-ExportAttributeFlow
{
   Param
   (       
        [parameter(Mandatory=$false)]
             [String]
             [ValidateScript({Test-Path $_})]
             $ServerConfigurationFolder
   )
   End
   {        
             ### This is where the rules will be aggregated before we output them
             $rules =@()
            
             ### Export attribute flow rules are contained in the ma-data nodes of the MA*.XML files
             $maFiles = @(get-item (Join-Path $ServerConfigurationFolder "MA-*.xml"))
            
            
             foreach ($maFile in $maFiles)
             {
                    ### Get the MA Name and MA ID
                   $maName = (select-xml $maFile -XPath "//ma-data/name").Node.InnerText
               
                foreach($exportFlowSet in (Select-Xml -path $maFile -XPath "//export-flow-set" | select -ExpandProperty Node))
                {
                     $mvObjectType = $exportFlowSet.'mv-object-type'
                     $cdObjectType = $exportFlowSet.'cd-object-type'
                    
                     foreach($exportFlow in $exportFlowSet.'export-flow')
                     {
                         $cdAttribute = $exportFlow.'cd-attribute'
                         [bool]$allowNulls = $false
                                 if ([bool]::TryParse($exportFlow.'suppress-deletions', [ref]$allowNulls))
                                 {
                                        $allowNulls = -not $allowNulls
                                 }
                        
                         if ($exportFlow.'direct-mapping' -ne $null)
                         {
                        ###
                        ### Handle src-attribute that are intrinsic (<src-attribute intrinsic="true">object-id</src-attribute>)
                        ###
                        if ($exportFlow.'direct-mapping'.'src-attribute'.intrinsic)
                        {
                            $srcAttribute = "<{0}>" -F $exportFlow.'direct-mapping'.'src-attribute'.'#text'
                        }
                        else
                        {
                                 $srcAttribute = $exportFlow.'direct-mapping'.'src-attribute'
                        }
                            
                             $rule = New-Object PSObject
                             $rule | Add-Member -MemberType noteproperty -name 'RuleType' -value 'DIRECT'
                             $rule | Add-Member -MemberType noteproperty -name 'MAName' -value $maName               
                             $rule | Add-Member -MemberType noteproperty -name 'MVObjectType' -value $mvObjectType
                             $rule | Add-Member -MemberType noteproperty -name 'MVAttribute' -value $srcAttribute
                             $rule | Add-Member -MemberType noteproperty -name 'CDObjectType' -value $cdObjectType
                             $rule | Add-Member -MemberType noteproperty -name 'CDAttribute' -value $cdAttribute
                                        $rule | Add-Member -MemberType noteproperty -name 'ScriptContext' -value $null
                                        $rule | Add-Member -MemberType noteproperty -name 'AllowNulls' -value $allowNulls
                            
                             $rules += $rule
                         }
                         elseif ($exportFlow.'scripted-mapping' -ne $null)
                         {               
                             $scriptContext = $exportFlow.'scripted-mapping'.'script-context'                       
                                        $srcAttributes = @()
                                       
                        ###
                        ### Handle src-attribute that are intrinsic (<src-attribute intrinsic="true">object-id</src-attribute>)
                        ###
                        $exportFlow.'scripted-mapping'.'src-attribute' | ForEach-Object {
                            if ($_.intrinsic)
                            {
                                $srcAttributes += "<{0}>" -F $_.'#text'
                            }
                            elseif ($_) # Do not add empty values.
                            {
                                     $srcAttributes += $_
                            }
                        }
                        # (Commented) Leave as collection.
                        #if ($srcAttributes.Count-eq 1)
                        #{
                        #    $srcAttributes = $srcAttributes -as[String]
                        #}
                                
                             $rule = New-Object PSObject
                             $rule | Add-Member -MemberType noteproperty -name 'RuleType' -value 'SCRIPTED'
                             $rule | Add-Member -MemberType noteproperty -name 'MAName' -value $maName
                                        $rule | Add-Member -MemberType noteproperty -name 'MVObjectType' -value $mvObjectType
                             $rule | Add-Member -MemberType noteproperty -name 'MVAttribute' -value $srcAttributes
                             $rule | Add-Member -MemberType noteproperty -name 'CDObjectType' -value $cdObjectType
                             $rule | Add-Member -MemberType noteproperty -name 'CDAttribute' -value $cdAttribute
                             $rule | Add-Member -MemberType noteproperty -name 'ScriptContext' -value $scriptContext
                                        $rule | Add-Member -MemberType noteproperty -name 'AllowNulls' -value $allowNulls
                                            
                             $rules += $rule                       
                         }
                                 elseif ($exportFlow.'sync-rule-mapping' -ne $null)
                                 {
                                        $srcAttribute = $exportFlow.'sync-rule-mapping'.'src-attribute'
                                        if($exportFlow.'sync-rule-mapping'.'mapping-type' -eq 'direct')
                                        {
                                               $rule = New-Object PSObject
                                               $rule | Add-Member -MemberType noteproperty -name 'RuleType' -value 'OSR-Direct'
                                               $rule | Add-Member -MemberType noteproperty -name 'MAName' -value $maName
                                               $rule | Add-Member -MemberType noteproperty -name 'MVObjectType' -value $mvObjectType
                                               $rule | Add-Member -MemberType noteproperty -name 'MVAttribute' -value $srcAttribute
                                               $rule | Add-Member -MemberType noteproperty -name 'CDObjectType' -value $cdObjectType
                                               $rule | Add-Member -MemberType noteproperty -name 'CDAttribute' -value $cdAttribute                                                                                       
                                               $rule | Add-Member -MemberType noteproperty -name 'ScriptContext' -value $null
                                               $rule | Add-Member -MemberType noteproperty -name 'AllowNulls' -value $allowNulls
                                                                        
                                               $rules += $rule            
                                        }
                                        elseif ($exportFlow.'sync-rule-mapping'.'mapping-type' -eq 'expression')
                                        {
                                               $scriptContext = $exportFlow.'sync-rule-mapping'.'sync-rule-value'.'export-flow'.InnerXml
                                               $srcAttribute = $exportFlow.'sync-rule-mapping'.'sync-rule-value'.'export-flow'.dest
                                               $rule = New-Object PSObject
                                               $rule | Add-Member -MemberType noteproperty -name 'RuleType' -value 'OSR-Expression'
                                               $rule | Add-Member -MemberType noteproperty -name 'MAName' -value $maName
                                               $rule | Add-Member -MemberType noteproperty -name 'MVObjectType' -value $mvObjectType
                                               $rule | Add-Member -MemberType noteproperty -name 'MVAttribute' -value $srcAttribute
                                               $rule | Add-Member -MemberType noteproperty -name 'CDObjectType' -value $cdObjectType
                                               $rule | Add-Member -MemberType noteproperty -name 'CDAttribute' -value $cdAttribute                                                                                       
                                               $rule | Add-Member -MemberType noteproperty -name 'ScriptContext' -value $scriptContext
                                               $rule | Add-Member -MemberType noteproperty -name 'AllowNulls' -value $allowNulls
                                                                        
                                               $rules += $rule            
                                        }
                                        else
                                        {
                                               throw "Unsupported Export Flow type"
                                        }
                              
                                 }
                     }
                }
             }
            
             Write-Output $rules
   }#End
}

Join-ImportToExportAttributeFlow


<#
   .SYNOPSIS
   Gets the Joined Rules where the IAF rules are joined to the EAF rules based on the MV Attributes and Object Types

   .DESCRIPTION
   Reads the server configuration from the XML files, and outputs the Joined IAF and EAF Rules as PSObjects

   .OUTPUTS
   PSObjects containing the synchronization server attribute flow rules
  
   .EXAMPLE
   Join-ImportToExportAttributeFlow-ServerConfigurationFolder"E:\sd\IAM\ITAuthorize\Source\Configuration\FimSync\ServerConfiguration"
  
#>
Function Join-ImportToExportAttributeFlow
{
    [CmdletBinding()]
       Param
       (       
        [parameter(Mandatory=$false)]
             [String]
             [ValidateScript({Test-Path $_})]
              $ServerConfigurationFolder
       )
       End
       {
             ### Get the Import Attribute Flow Rules
             $IAF = Get-ImportAttributeFlow -ServerConfigurationFolder $ServerConfigurationFolder
            
             ### Get the Export Attribute Flow Rules
             $EAF = Get-ExportAttributeFlow -ServerConfigurationFolder $ServerConfigurationFolder

             ### This is where the rules will be aggregated before we output them
             $e2eFlowRules =@()
             foreach ($iafRule in $IAF)
             {
                ### Look for a corresponding EAF rule   
                $eafMatches = @($EAF | where {$_.'MVAttribute' -contains $iafRule.'MVAttribute' -and $_.'MVObjectType' -eq $iafRule.'MVObjectType'})

                    ### There may be multiple EAF rule for each IAF rules
                if ($eafMatches.count -gt 0)
                {
                     foreach($eafRule in $eafMatches)
                     {                       
                         $e2eFlowRuleProperties =@{           
                             'IAFRuleType'          = $iafRule.'RuleType'
                             'IAFSourceMA'          = $iafRule.'SourceMA'
                             'IAFCDObjectType'      = $iafRule.'CDObjectType'
                             'IAFCDAttribute'       = $iafRule.'CDAttribute'
                             'IAFScriptContext'     = $iafRule.'ScriptContext'
                             'IAFPrecedenceType'    = $iafRule.'PrecedenceType'
                             'IAFPrecedenceRank'    = $iafRule.'PrecedenceRank'
                             'MVObjectType'         = $iafRule.'MVObjectType'
                             'MVAttribute'          = $iafRule.'MVAttribute'
                             'EAFMVAttribute'       = $eafRule.'MVAttribute'
                             'EAFCDAttribute'       = $eafRule.'CDAttribute'
                             'EAFTargetMA'          = $eafRule.'MAName'
                             'EAFCDObjectType'      = $eafRule.'CDObjectType'
                             'EAFRuleType'          = $eafRule.'RuleType'
                              'EAFScriptContext'     = $eafRule.'ScriptContext'
                         }
                        
                         $e2eFlowRules += New-Object PSObject -Property $e2eFlowRuleProperties
                     }
                }
                    ### It is possible there are NO EAF rules for an IAF rule
                    ### here we stuff $null into the EAF side to make our output easy to consume for Out-GridView and Compare-Object
                    ### otherwise jagged objects seem to confuse things
                    ###
                    ### In this case the rule may be useless
                    ### Or the use of that MV attribute may not be visible here because some rules extension calls it (need to check the source code to confirm)
                else
                {
                    $e2eFlowRuleProperties =@{           
                             'IAFRuleType'          = $iafRule.'RuleType'
                             'IAFSourceMA'          = $iafRule.'SourceMA'
                             'IAFCDObjectType'      = $iafRule.'CDObjectType'
                             'IAFCDAttribute'       = $iafRule.'CDAttribute'
                             'IAFScriptContext'     = $iafRule.'ScriptContext'
                             'IAFPrecedenceType'    = $iafRule.'PrecedenceType'
                             'IAFPrecedenceRank'    = $iafRule.'PrecedenceRank'
                             'MVObjectType'         = $iafRule.'MVObjectType'
                             'MVAttribute'          = $iafRule.'MVAttribute'
                             'EAFMVAttribute'       = $null
                             'EAFCDAttribute'       = $null
                             'EAFTargetMA'          = $null
                             'EAFCDObjectType'      = $null
                             'EAFRuleType'          = $null
                             'EAFScriptContext'     = $null
                         }
                        
                    $e2eFlowRules += New-Object PSObject -Property $e2eFlowRuleProperties
                }
             }

        ### There's one more case in which the MV attribute is blank for an EAF.
       foreach ($eafRule in @($EAF | where {$_.'MVAttribute'.count -eq 0}))
       {
            Write-Verbose $eafRule
            $e2eFlowRuleProperties = @{           
                'IAFRuleType'          = $null
                'IAFSourceMA'          = $null
                'IAFCDObjectType'      = $null
                'IAFCDAttribute'       = $null
                'IAFScriptContext'     = $null
                'IAFPrecedenceType'    = $null
                'IAFPrecedenceRank'    = $null
                'MVObjectType'         = $null
                'MVAttribute'          = $null
                'EAFMVAttribute'       = $eafRule.'MVAttribute'
                'EAFCDAttribute'       = $eafRule.'CDAttribute'
                'EAFTargetMA'          = $eafRule.'MAName'
                'EAFCDObjectType'      = $eafRule.'CDObjectType'
                'EAFRuleType'          = $eafRule.'RuleType'
                'EAFScriptContext'     = $eafRule.'ScriptContext'
            }
                         
              $e2eFlowRules += New-Object PSObject -Property $e2eFlowRuleProperties
       }

             $e2eFlowRules | select `
             'IAFSourceMA',`
             'IAFCDObjectType',`
             'IAFCDAttribute',`
             'IAFRuleType',`
             'IAFScriptContext',`
             'IAFPrecedenceType',`
             'IAFPrecedenceRank',`
             'MVObjectType',`
             'MVAttribute',`
             'EAFMVAttribute',`
             'EAFTargetMA',`
             'EAFCDObjectType',`
             'EAFCDAttribute',`
             'EAFRuleType',`
             'EAFScriptContext'`
       }
}