A script to create Sets and MPRs from Templates

Here’s a new script thet I’m pretty pleased with myself about!

To make the most of the delegation flexibility in the FIM Portal, and to target your workflows correctly, you can find yourself creating a lot of Sets and MPRs. A lot. You also might find that many of them are very similar, with only the Requestor and Target Sets differing in predictable ways. This script should help with that.

The Idea

In my environment I have groups of users and groups of people who adminster those users. I’m using a lot of union sets that limit the applicable actions, with corresponding numbers of MPRs to tie it all together. I want each group of users/admins to be set up in exactly the same way, and I want to be able to update the config in the future with minimum fuss.

So what I’ve done is to create a bunch of Sets and MPRs that all start with the word “TEMPLATE”. I’ve then written a script that will replicate these to versions that start with some other word, eg., “PARIS”, at the same time sorting out all the references, so that “TEMPLATE Users” becomes “PARIS Users” etc.

Later I can modify the TEMPLATE objects and re-run the script, updating the PARIS objects to match whatever additions and changes have been made.

The Templates

In Sets, I have my basic “Users” and “IT Admins”, and then I have various union sets which will limit available actions to the right circumstances. (I think the union sets are better than explicitly listing rules each time because then if, for example, my definition of what makes a “Resigned User” changes I only have to modify it in one place.)

So it looks a bit like this:

 

Set Name Member Selection Comments
TEMPLATE Users All users where Department = “TEMPLATE” The rule here doesn’t really mater, You will replace it with your real rule in the generated Users set. After that the script explicitly ignores this set.
TEMPLATE IT Admins Manually populated set If you want to do rules-based IT Admin sets as well then you will need to modify the script to also explicitly ignore them after creation.
TEMPLATE Active Users ResourceID in “TEMPLATE Users” and ResourceID in “Active Users” Use to permit actions only relevant to Active Users in this Users set.
TEMPLATE Resigned Users ResourceID in “TEMPLATE Users” and ResourceID in “Resigned Users” Use to permit actions only relevant to Resigned Users in this Users set.

Next I create varous MPRs, using the TEMPLATE Sets, and selecting my Workflows. Some examples:

MPR Name Sets Function
TEMPLATE IT Admins can read extra details about TEMPLATE Users Reqestor: “TEMPLATE IT Admins”
Target: “TEMPLATE Users”
Grants read rights to extra attributes an IT Admin needs to see about the users they administer.
TEMPLATE IT Admins can modify TEMPLATE Active Users Reqestor: “TEMPLATE IT Admins”
Target: “TEMPLATE Active Users”
Grants modify permission to attributes only relevant to Active users, and potentially triggers Workflow activities.
TEMPLATE IT Admins can delete TEMPLATE Resigned Users Reqestor: “TEMPLATE IT Admins”
Target: “TEMPLATE Resigned Users”
All an IT Admin to triger the workflows that will clean up accounts for people who’ve left.

Remember these are just examples – your template Sets and MPRs will be different, though be aware my script has made an assumption about the existence of a “TEMPLATE Users” group, and you may need to modify that if you don’t have one.

Bugs/Features

The main point to be aware of with this script is that you may need to run it twice, particularly the first time you create a new group of Sets and MPRs. This is because dependencies will probably exist on Sets being created in the same operation. You could manually create the dependecy Sets first, but it’s probably easiest to just run the script twice.

This script does not delete Sets and MPRs – it only adds and modifies. So if you delete one of your TEMPLATE Sets and re-run the script you will find that the Sets that were generated off that TEMPLATE Set before will still be there. However deleting objects in the Portal is nowhere near as arduous as creating them, so I’d rather avoid scripted deletes.

And here it is

PARAM($tag,$FIMServer="localhost")

# Create-DefaultPolicy.ps1
#
# Written by Carol Wapshere
# http://www.wapshere.com/missmiis/a-script-to-create-sets-and-mprs-from-templates
#
# Usage: Create-DefaultPolicy.ps1 -FIMServer "myserver.mydomain.net" -tag "MyDesc"
#
# This will search for all Sets and MPRs starting with the word "TEMPLATE" and attempt to create new objects
# with all instances of "TEMPLATE" changed to "MyDesc", including references.
#
# The script may need to be run twice when creating new objects that are depended on by other objects.
#

#----------------------------------------------------------------------------------------------------------
 Function SetAttribute
 {
    Param($object, $attributeName, $attributeValue, $isMultiValued=$false)
    End
    {
        $importChange = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportChange
        if ($isMultiValued) {$importChange.Operation = 0}
        else {$importChange.Operation = 1}
        $importChange.AttributeName = $attributeName
        $importChange.AttributeValue = $attributeValue
        $importChange.FullyResolved = 1
        $importChange.Locale = "Invariant"
        If ($object.Changes -eq $null) {$object.Changes = (,$importChange)}
        Else {$object.Changes += $importChange}
    }
}
#----------------------------------------------------------------------------------------------------------
 Function CreateObject
 {
    Param($objectType)
    End
    {
       $newObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject
       $newObject.ObjectType = $objectType
       $newObject.SourceObjectIdentifier = [System.Guid]::NewGuid().ToString()
       $newObject
    }
 }
#----------------------------------------------------------------------------------------------------------
 Function UpdateObject
 {
    Param($objectType, $objectID)
    End
    {
       $updObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject
       $updObject.ObjectType = $objectType
       $updObject.SourceObjectIdentifier = $objectID
       $updObject.TargetObjectIdentifier = $objectID
       $updObject.State = [Microsoft.ResourceManagement.Automation.ObjectModel.ImportState]::Put
       $updObject
    }
 }
#----------------------------------------------------------------------------------------------------------
Function CorrectedSet
{
    Param($objectID)
    End
    {
      $returnID = $objectID

      if ($SetIDs.Contains($objectID))
      {
        $objectName = $SetIDs.Get_Item($objectID)

        if ($objectName.Contains("TEMPLATE"))
        {
          $returnName = $objectName -replace "TEMPLATE",$tag
          if ($SetNames.Contains($returnName))
          {
            $returnID = $SetNames.Get_Item($returnName)
            write-host "    Replacing Set '$objectName' with '$returnName'"
          }
          else
          {
            $query = "/Set[DisplayName ='" + $returnName + "']"
            write-host "Searching for new Set $returnName..."
            if ($objSet = Export-FIMConfig -uri $URI -customConfig $query)
            {
              write-host "    Found $returnName"
              $returnID = $objSet.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ObjectID'}
              $SetIDs.Add($returnID.Value,$returnName)
              $SetNames.Add($returnName,$returnID.Value)
            }
          }
        }
      }
      $returnID
    }
}
#----------------------------------------------------------------------------------------------------------
Function AddSetValues
{
    Param($newSet,$oldSet,$templateSet)
    End
    {
      $templateDescription = $templateSet.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'Description'}
      $oldDescription = $oldSet.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'Description'}
      if ($templateDescription) {$newDescriptionValue = $templateDescription.Value -replace "TEMPLATE",$tag}
      if ($newDescriptionValue -ne $oldDescription.Value) {SetAttribute -object $newSet -attributeName  "Description" -attributeValue $newDescriptionValue}

      $templateFilter = $templateSet.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'Filter'}
      $oldFilter = $oldSet.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'Filter'}
      if ($templateFilter) {$newFilterValue = $templateFilter.Value.Replace('TEMPLATE',$tag)}
      if ($newFilterValue -ne "" -and $newFilterValue.Contains("Set[ObjectID") )
      {
        $regex = [regex]"Set\[ObjectID = '[\w-]*'\]/ComputedMember"
        $matches = $regex.Matches($newFilterValue)
        foreach ($match in $matches)
        {
          $objectID = $match.Value -replace "Set\[ObjectID = '", ""
          $objectID = $objectID  -replace("'\]/ComputedMember","")
          $SetID = CorrectedSet -objectType "Set" -objectID "urn:uuid:$objectID"
          $SetID = $SetID -replace "urn:uuid:",""
          $newFilterValue = $newFilterValue -replace $objectID, $SetID
        }
      }
      if ($newFilterValue -ne $oldSetFilter.Value) {SetAttribute -object $newSet -attributeName  "Filter" -attributeValue $newFilterValue}

      $newSet
    }
 }
#----------------------------------------------------------------------------------------------------------
Function AddMPRValues
{
    Param($newMPR,$oldMPR,$templateMPR)
    End
    {
      $templateActionParameter = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ActionParameter'}
      $oldActionParameter = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ActionParameter'}
      foreach ($attribName in $templateActionParameter.Values)
      {if ($oldActionParameter.Values -notcontains $attribName) {
        write-host "  Adding ActionParameter $attribName"
        SetAttribute -object $newMPR -attributeName  "ActionParameter" -attributeValue $attribName -isMultiValued $true
      }}

      $templateActionType = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ActionType'}
      $oldActionType = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ActionType'}
      foreach ($action in $templateActionType.Values)
      {if ($oldActionType.Values -notcontains $action) {
        write-host "  Adding ActionType $action"
        SetAttribute -object $newMPR -attributeName  "ActionType" -attributeValue $action -isMultiValued $true
      }}

      $templateDescription = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'Description'}
      $oldDescription = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'Description'}
      if ($templateDescription) {$newDescriptionValue = $templateDescription.Value -replace "TEMPLATE",$tag}
      if ($oldDescription.Value -ne $newDescriptionValue)
      {
        write-host "  Adding Description '$newDescription'"
        SetAttribute -object $newMPR -attributeName  "Description" -attributeValue $newDescriptionValue
      }

      $templateAuthenticationWorkflowDefinition = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'AuthenticationWorkflowDefinition'}
      $oldAuthenticationWorkflowDefinition = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'AuthenticationWorkflowDefinition'}
      foreach ($authn in $templateAuthenticationWorkflowDefinition.Values) 
      {if ($oldAuthenticationWorkflowDefinition -notcontains $authn) {
        write-host "  Adding AuthenticationWorkflowDefinition" $authn
        SetAttribute -object $newMPR -attributeName  "AuthenticationWorkflowDefinition" -attributeValue $authn -isMultiValued $true
      }}

      $templateAuthorizationWorkflowDefinition = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'AuthorizationWorkflowDefinition'}
      $oldAuthorizationWorkflowDefinition = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'AuthorizationWorkflowDefinition'}
      foreach ($authz in $templateAuthorizationWorkflowDefinition.Values) 
      {if ($oldAuthorizationWorkflowDefinition -notcontains $authz) {
        write-host "  Adding AuthorizationWorkflowDefinition" $authz
        SetAttribute -object $newMPR -attributeName  "AuthorizationWorkflowDefinition" -attributeValue $authz -isMultiValued $true
      }}

      $templateActionWorkflowDefinition = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ActionWorkflowDefinition'}
      $oldActionWorkflowDefinition = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ActionWorkflowDefinition'}
      foreach ($action in $templateActionWorkflowDefinition.Values)
      {if ($oldActionWorkflowDefinition -notcontains $action) {
        write-host "  Adding ActionWorkflowDefinition" $action
        SetAttribute -object $newMPR -attributeName  "ActionWorkflowDefinition" -attributeValue $action -isMultiValued $true
      }}

      $templateGrantRight = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'GrantRight'}
      $oldGrantRight = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'GrantRight'}
      if ($oldGrantRight.Value -ne $templateGrantRight.Value)
      {
        write-host "  Adding GrantRight" $templateGrantRight.Value
        SetAttribute -object $newMPR -attributeName  "GrantRight" -attributeValue $templateGrantRight.Value
      }

      $templateManagementPolicyRuleType = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ManagementPolicyRuleType'}
      $oldManagementPolicyRuleType = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ManagementPolicyRuleType'}
      if ($oldManagementPolicyRuleType.Value -ne $templateManagementPolicyRuleType.Value)
      {
        write-host "  Adding MPRType" $templateManagementPolicyRuleType.Value
        SetAttribute -object $newMPR -attributeName  "ManagementPolicyRuleType" -attributeValue $templateManagementPolicyRuleType.Value
      }

      $templatePrincipalSet = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'PrincipalSet'}
      $oldPrincipalSet = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'PrincipalSet'}
      if ($templatePrincipalSet.Value)
      {
        $SetID = ""
        $SetID = CorrectedSet -objectID $templatePrincipalSet.Value
        if ($SetID -ne $oldPrincipalSet.Value) {write-host "  Adding PrincipalSet"; SetAttribute -object $newMPR -attributeName  "PrincipalSet" -attributeValue $SetID}
      }

      $templateResourceCurrentSet = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ResourceCurrentSet'}
      $oldResourceCurrentSet = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ResourceCurrentSet'}
      if ($templateResourceCurrentSet)
      {
        $SetID = ""
        $SetID = CorrectedSet -objectID $templateResourceCurrentSet.Value
        if ($SetID -ne $oldResourceCurrentSet.Value) {write-host "  Adding ResourceCurrentSet"; SetAttribute -object $newMPR -attributeName  "ResourceCurrentSet" -attributeValue $SetID}
      }

      $templateResourceFinalSet = $templateMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ResourceFinalSet'}
      $oldResourceFinalSet = $oldMPR.ResourceManagementObject.ResourceManagementAttributes | where {$_.AttributeName -eq 'ResourceFinalSet'}
      if ($templateResourceFinalSet)
      {
        $SetID = ""
        $SetID = CorrectedSet -objectID $templateResourceFinalSet.Value
        if ($SetID -ne $oldResourceFinalSet.Value) {write-host "  Adding ResourceFinalSet"; SetAttribute -object $newMPR -attributeName  "ResourceFinalSet" -attributeValue $SetID}
      }

      $newMPR
    }
}
#----------------------------------------------------------------------------------------------------------

##  MAIN

if(@(get-pssnapin | where-object {$_.Name -eq "FIMAutomation"} ).count -eq 0) {add-pssnapin FIMAutomation}

$URI = "http://" + $FIMServer + ":5725/ResourceManagementService"

##  Enumerate existing Sets and MPRs

$FIMPolicyObjects = export-fimconfig -uri $URI -customconfig ('/Set','/ManagementPolicyRule')

$TemplateSets = @{}
$TagSets = @{}
$TemplateMPRs = @{}
$TagMPRs = @{}
$SetIDs = @{}
$SetNames = @{}
$MPRIDs = @{}
$MPRNames = @{}

write-host "Enumerating objects:"

foreach ($fimobject in $FIMPolicyObjects)
{
  $attributes = $fimobject.ResourceManagementObject.ResourceManagementAttributes

  if ($attributes | where {$_.AttributeName -eq 'ObjectType' -and $_.Value -eq 'Set'})
  {
    $objectID = $attributes | where {$_.AttributeName -eq 'ObjectID'}
    $displayName = $attributes | where {$_.AttributeName -eq 'DisplayName'}
    if ($objectID.Value -and $displayName.Value)
    {
      #write-host "  Set: " $displayName.Value
      $SetIDs.Add($objectID.Value,$displayName.Value)
      $SetNames.Add($displayName.Value,$objectID.Value)
      if ($displayName.Value.StartsWith('TEMPLATE')) {$TemplateSets.Add($displayName.Value, $fimobject)}
      if ($displayName.Value.StartsWith($tag)) {$TagSets.Add($displayName.Value, $fimobject)}
    }
  }

  if ($attributes | where {$_.AttributeName -eq 'ObjectType' -and $_.Value -eq 'ManagementPolicyRule'})
  {
    $objectID = $attributes | where {$_.AttributeName -eq 'ObjectID'}
    $displayName = $attributes | where {$_.AttributeName -eq 'DisplayName'}
    if ($objectID.Value -and $displayName.Value)
    {
      #write-host "  MPR: " $displayName.Value
      $MPRIDs.Add($objectID.Value,$displayName.Value)
      $MPRNames.Add($displayName.Value,$objectID.Value)
      if ($displayName.Value.StartsWith('TEMPLATE')) {$TemplateMPRs.Add($displayName.Value, $fimobject)}
      if ($displayName.Value.StartsWith($tag)) {$TagMPRs.Add($displayName.Value, $fimobject)}
    }
  }
}
write-host

## Process Sets
## The "Tag Users" set is only created, not modified.

foreach ($setName in $TemplateSets.Keys)
{
  write-host
  $tagDisplayName = $setName.Replace('TEMPLATE',$tag)

  if ($TagSets.Contains($tagDisplayName))
  {
    write-host "Checking Set $tagDisplayName for updates..."
    $SetID = $SetNames.Get_Item($tagDisplayName)
    $SetID = $SetID -replace "urn:uuid:",""
    $newSet = UpdateObject  -objectType "Set" -objectID $SetID
    if ($setName -ne "TEMPLATE Users")
      {$newSet = AddSetValues -newSet $newSet -oldSet $TagSets.Get_Item($tagDisplayName) -templateSet $TemplateSets.Get_Item($setName)}
  }
  else
  {
    write-host "Adding Set $tagDisplayName..."
    $newSet = CreateObject -objectType "Set"
    SetAttribute -object $newSet -attributeName  "DisplayName" -attributeValue $tagDisplayName
    $newSet = AddSetValues -newSet $newSet -oldSet $newSet -templateSet $TemplateSets.Get_Item($setName)
  }

  if ($newSet.Changes.Count -gt 0)
  {
    $newSet.Changes
    $newSet | Import-FIMConfig -uri $URI
  } else {write-host "No changes to import."}
}

## Process MPRs

foreach ($MPRName in $TemplateMPRs.Keys)
{
  write-host
  $tagDisplayName = $MPRName.Replace('TEMPLATE',$tag)

  if ($TagMPRs.Contains($tagDisplayName))
  {
    write-host "Updating MPR $tagDisplayName"
    $MPRID = $MPRNames.Get_Item($tagDisplayName)
    $MPRID = $MPRID -replace "urn:uuid:",""
    $newMPR = UpdateObject  -objectType "ManagementPolicyRule" -objectID $MPRID
    $newMPR = AddMPRValues -newMPR $newMPR -oldMPR $TagMPRs.Get_Item($tagDisplayName) -templateMPR $TemplateMPRs.Get_Item($MPRName)
  }
  else
  {
    write-host "Adding MPR $tagDisplayName"
    $newMPR = CreateObject -objectType "ManagementPolicyRule"
    SetAttribute -object $newMPR -attributeName  "DisplayName" -attributeValue $tagDisplayName
    $newMPR = AddMPRValues -newMPR $newMPR -oldMPR $newMPR -templateMPR $TemplateMPRs.Get_Item($MPRName)
}

  $newMPR.Changes

  if ($newMPR.Changes.Count -gt 0)
  {
    write-host "Importing changes."
    $newMPR | Import-FIMConfig -uri $URI
  } else {write-host "No changes to import."}

}

 

About: Carol

I've been doing IT for 30 years, and IdM for 15. I live in Australia and build IdM solutions based on Microsoft Identity Manager. I also play the violin, but that doesn't help much with the IdM solutions.


Leave a Reply

Your email address will not be published. Required fields are marked *


*