Tuesday, August 30, 2011

Using PowerShell to Modify a FIM RCDC

Ever need to automate the deployment of a new UI control to a FIM Portal? 
A quick search of the FIM wiki for Resource Control Display Configuration will show you the pre-requisites you need to appreciate before fully grasping the challenge at hand :-|
In short: RCDCs are a handy way of allowing FIM Portal customization by adding controls as XML stuffed into an attribute in an object that resides in the FIM Service.  One challenge here is that the XML can be rather large, and it is not validated on import which leads to some pretty fun troubleshooting.  Using this script approach you can prevent people from doing this manually by providing them with a script that automates the process.

The approach I took with this script was to edit an RCDC in place by adding the new control’s XML to the existing RCDC XML.  I could have finished a lot sooner with a heavier hand if I’d just replaced the whole RCDC XML, instead of grafting my single control in.  There’s something to be said for finishing earlier but I wanted to see if this could easily be done, and that is what I’m trying to show in this blog post.

Working with Namespaces
The main challenge I found in this script was working with namespaces.  RCDC schema uses a few namespaces declared at the top of the document.  Adding a new control by hand you don’t typically include these namespaces because they are already at the top of the document.  I couldn’t find an easy way to do this, so I had to include the namespace declaration in my new control’s XML.  It is redundant but AFAIK it is not incorrect (at least it doesn’t seem to make the server angry).  Skipping this little trick took the simplicity out of the script and made it pretty ugly because I really wanted to use the XML functionality in .NET instead of doing string manipulation.

There’s one trick/function in the script below that I haven’t posted about yet.  It is basically another wrapper for Import-FimConfig.  Look for more on that later as I want to share and demo it at TEC Europe.

Anyhow, on with the script.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
###
### Update the RCDC for User Edit
###

### Get the existing User Edit RCDC

$userEditRcdc = Export-FIMConfig -OnlyBaseResources -CustomConfig "/ObjectVisualizationConfiguration[DisplayName='Configuration for User Editing']" | Convert-FimExportToPSObject
[XML]$rcdcXml = $userEditRcdc.ConfigurationData

### This is the new control we want to add
$newRcdcControl = 
@"
<my:Control
xmlns:my="http://schemas.microsoft.com/2006/11/ResourceManagement"
    my:Name='MyNewCheckBox'
    my:TypeName='UocCheckBox'
    my:Caption='HoofHearted?'
    my:Description=''
    my:RightsLevel='{Binding Source=rights, Path=isStinky}'>
    <my:Properties>
        <my:Property
            my:Name='Checked'
            my:Value='{Binding Source=object, Path=isStinky, Mode=TwoWay}'/>
    </my:Properties>
</my:Control>
"@


### Put the new Control into an XML fragment
$fraggle = $rcdcXml.CreateDocumentFragment()
$fraggle.InnerXML = $newRcdcControl

### Find the Tab where we want to place this Control
$WorkInfoTab = $rcdcXml.ObjectControlConfiguration.Panel.Grouping | Where-Object {$_.Name -eq 'WorkInfo'}

### Find the Control to place this one AFTER
$namespace = @{my="http://schemas.microsoft.com/2006/11/ResourceManagement"}
$EmployeeIDControl = Select-Xml $rcdcXml -XPath "//my:Control[@my:Name='EmployeeID']" -Namespace $namespace

### Insert our new control
[Void]$WorkInfoTab.InsertAfter($fraggle,$EmployeeIDControl.Node) 

### Update the RCDC in FIM with our updated XML
$rcdcUpdate = New-FimImportObject -ObjectType ObjectVisualizationConfiguration -State Put -AnchorPairs @{DisplayName='Configuration for User Editing'-Changes
 @(
   
New-FimImportChange -Operation Replace -AttributeName ConfigurationData -AttributeValue ($rcdcXml.
OuterXml) 
)

$rcdcUpdate | Import-FIMConfig

###
### Cycle FIM and IIS
###

Restart-Service fimservice
iisreset

Before



After (notice the new HoofHearted item)


4 comments:

Wesley Riley said...

This is awesome! Can you provide more information about the "New-FimImportObject" function. I cannot seem to find any references to it online. Thanks! Great work!

Craig Martin said...

Good find ;-) I am actually working on getting that function posted and hope to have something soon. In a nutshell that function is just a wrapper for the object types in the FIMAutomation snap-in. the FIM cmdlets don't make it easy to create the inputs for Import-FIMConfig so I wrote a generic wrapper and use it all over the place. More soon.

Scott said...

Hey Craig :) Just came across your blog. You wouldn't happen to have those wrapper functions published yet would you? I had a quick flick through your blog and couldn't find them

Craig Martin said...

My goal is to have them published THIS week actually - in time for the TEC 2012 FIM Workshop. Check back soon!