Jorge's Quest For Knowledge!

All About Identity And Security On-Premises And In The Cloud – It's Just Like An Addiction, The More You Have, The More You Want To Have!

(2013-02-08) Unused SETs, Unused Workflows, Unused Mail Templates – Keeping FIM Portal Clean From Unused Configuration Objects

Posted by Jorge on 2013-02-08


As soon as you have installed FIM you start configuring it according to your application design, which is based upon the data model and the usage scenarios. In case of the FIM Portal you configure it with configuration objects (MPRs, SETs, Workflows, Mail Templates, etc.) that in the end will be the technical components that give you the desired logic to do whatever you need it to do. At least I hope so! Smile

During the usage of the FIM Portal, stuff changes because requirements change and logic change. Because of that objects are added and changed to accommodate the new requirements and therefore the required logic. BUT….. where’s the part about deleting unused objects, in other words CLEAN UP! By default there is nothing in FIM that will tell you if objects are not used. Is it impossible to get that information? No, but you need to do it yourself! I want to keep my FIM Portal configuration clean, therefore I have created the following PowerShell script to help me with that. And I do hope it helps you too!

# Jorge de Almeida Pinto [MVP-DS] # https://jorgequestforknowledge.wordpress.com/ # # +++ Finding UnUsed Objects In The FIM Portal +++ Param ( [string] $URI = "http://localhost:5725/resourcemanagementservice", [parameter(Mandatory=$true)] [string] $objectType ) # Clear The Screen Clear-Host # Import The FIM 2010 (R2) Snap-In If Available $SnapIn = "FIMAutomation" If(@(Get-PSSnapin | Where-Object {$_.Name -eq $SnapIn} ).count -eq 0) { If(@(Get-PSSnapin -Registered | Where-Object {$_.Name -eq $SnapIn} ).count -ne 0) { Add-PSSnapin $SnapIn Write-Host "" Write-Host "Snap-In '$SnapIn' Has Been Loaded..." -ForeGroundColor Green Write-Host "Continuing Script..." -ForeGroundColor Green Write-Host "" } Else { Write-Host "" Write-Host "Snap-In '$SnapIn' Is NOT Available To Load..." -ForeGroundColor Red Write-Host "Aborting Script..." -ForeGroundColor Red Write-Host "" Exit } } Else { Write-Host "" Write-Host "Snap-In '$SnapIn' Has Already Been Loaded..." -ForeGroundColor Green Write-Host "Continuing Script..." -ForeGroundColor Green Write-Host "" } # Convert a FIM ExportObject to a PowerShell PSObject # http://www.identitytrench.com/2011/07/convert-fim-exportobject-to-powershell.html Function Convert-FimExportToPSObject { Param ( [parameter(Mandatory=$true, ValueFromPipeline = $true)] [Microsoft.ResourceManagement.Automation.ObjectModel.ExportObject] $ExportObject ) Process { $psObject = New-Object PSObject $ExportObject.ResourceManagementObject.ResourceManagementAttributes | ForEach-Object { if ($_.Value -ne $null) { $value = $_.Value } elseif($_.Values -ne $null) { $value = $_.Values } else { $value = $null } $psObject | Add-Member -MemberType NoteProperty -Name $_.AttributeName -Value $value } Write-Output $psObject } } # Current Folder $currentFolder = (Get-Location).Path # Searching For Unused SETs # SETs Can Be Used In: # * MPRs # * Referenced By Other SETs # * Referenced By Search Scopes # * Referenced By RCDCs If ($objectType.ToUpper() -eq "SET") { Write-Host "" Write-Host "+++ CHECKING USAGE OF SETS +++" -ForeGroundColor Cyan Write-Host "" # Files $listOfSETsUsed = "List-Of-Sets-Used.txt" $listOfSETsUnUsed = "List-Of-Sets-UnUsed.txt" # Check Current Files If (Test-Path $($currentFolder + "\" + $listOfSETsUsed)) { Remove-Item $($currentFolder + "\" + $listOfSETsUsed) -Force } If (Test-Path $($currentFolder + "\" + $listOfSETsUnUsed)) { Remove-Item $($currentFolder + "\" + $listOfSETsUnUsed) -Force } # Get All The SETs $SETsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/Set" $SETsInFIMPSObject = $SETsInFIM | Convert-FimExportToPSObject # Get All The MPRs $MPRsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/ManagementPolicyRule" $MPRsInFIMPSObject = $MPRsInFIM | Convert-FimExportToPSObject # Get All The SearchScopes $SearchScopesInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/SearchScopeConfiguration" $SearchScopesInFIMPSObject = $SearchScopesInFIM | Convert-FimExportToPSObject # Get All The RCDCs $RCDCsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/ObjectVisualizationConfiguration" $RCDCsInFIMPSObject = $RCDCsInFIM | Convert-FimExportToPSObject # For Each SET Check If It Is Used Somewhere ForEach ($SETInFIMPSObject In $SETsInFIMPSObject) { $setDisplayName = $SETInFIMPSObject.DisplayName $setObjectID = $SETInFIMPSObject.ObjectID $setIsUsed = $false # For Each SET Check If It Is Used In Some MPR If (!$setIsUsed) { ForEach ($MPRInFIMPSObject In $MPRsInFIMPSObject) { If ($MPRInFIMPSObject.PrincipalSet -eq $setObjectID -Or $MPRInFIMPSObject.ResourceCurrentSet -eq $setObjectID -Or $MPRInFIMPSObject.ResourceFinalSet -eq $setObjectID) { # Object Is Used $setIsUsed = $true Break } Else { # Object Is NOT Used $setIsUsed = $false } } } # For Each SET Check If It Is Used In Some Other SET If (!$setIsUsed) { ForEach ($SETInFIMPSObject In $SETsInFIMPSObject) { If ($SETInFIMPSObject.Filter -match $($setObjectID.TrimStart("urn:uuid:")) -Or $SETInFIMPSObject.Filter -match $setDisplayName) { # Object Is Used $setIsUsed = $true Break } Else { # Object Is NOT Used $setIsUsed = $false } } } # For Each SET Check If It Is Used In Some Workflow If (!$setIsUsed) { ForEach ($SearchScopeInFIMPSObject In $SearchScopesInFIMPSObject) { If ($SearchScopeInFIMPSObject.SearchScope -match $($setObjectID.TrimStart("urn:uuid:")) -Or $SearchScopeInFIMPSObject.SearchScope -match $setDisplayName) { # Object Is Used $setIsUsed = $true Break } Else { # Object Is NOT Used $setIsUsed = $false } } } # For Each SET Check If It Is Used In Some RCDC If (!$setIsUsed) { ForEach ($RCDCInFIMPSObject In $RCDCsInFIMPSObject) { If ($RCDCInFIMPSObject.ConfigurationData -match $($setObjectID.TrimStart("urn:uuid:")) -Or $RCDCInFIMPSObject.ConfigurationData -match $setDisplayName) { # Object Is Used $setIsUsed = $true Break } Else { # Object Is NOT Used $setIsUsed = $false } } } # If The SET Is Used If ($setIsUsed) { Write-Host "In Use: '$setDisplayName'..." -ForeGroundColor Green Add-Content $($currentFolder + "\" + $listOfSETsUsed) $setDisplayName } # If The SET Is UnUsed If (!$setIsUsed) { Write-Host "Not In Use: '$setDisplayName'..." -ForeGroundColor Red Add-Content $($currentFolder + "\" + $listOfSETsUnUsed) $setDisplayName } } } # Searching For Unused WorkFlows # WorkFlows Can Be Used In: # * MPRs # * Referenced By SETs If ($objectType.ToUpper() -eq "Workflow") { Write-Host "" Write-Host "+++ CHECKING USAGE OF WORKFLOWS +++" -ForeGroundColor Cyan Write-Host "" # Files $listOfWorkflowsUsed = "List-Of-Workflows-Used.txt" $listOfWorkflowsUnUsed = "List-Of-Workflows-UnUsed.txt" # Check Current Files If (Test-Path $($currentFolder + "\" + $listOfWorkflowsUsed)) { Remove-Item $($currentFolder + "\" + $listOfWorkflowsUsed) -Force } If (Test-Path $($currentFolder + "\" + $listOfWorkflowsUnUsed)) { Remove-Item $($currentFolder + "\" + $listOfWorkflowsUnUsed) -Force } # Get All The Workflows $WorkflowsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/WorkflowDefinition" $WorkflowsInFIMPSObject = $WorkflowsInFIM | Convert-FimExportToPSObject # Get All The MPRs $MPRsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/ManagementPolicyRule" $MPRsInFIMPSObject = $MPRsInFIM | Convert-FimExportToPSObject # Get All The SETs $SETsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/Set" $SETsInFIMPSObject = $SETsInFIM | Convert-FimExportToPSObject # For Each Workflow Check If It Is Used Somewhere ForEach ($WorkflowInFIMPSObject In $WorkflowsInFIMPSObject) { $workflowDisplayName = $WorkflowInFIMPSObject.DisplayName $workflowObjectID = $WorkflowInFIMPSObject.ObjectID $workflowIsUsed = $false # For Each Workflow Check If It Is Used In Some MPR If (!$workflowIsUsed) { ForEach ($MPRInFIMPSObject In $MPRsInFIMPSObject) { If ($MPRInFIMPSObject.ActionWorkflowDefinition -contains $WorkflowObjectID -Or $MPRInFIMPSObject.AuthenticationWorkflowDefinition -contains $setObjectID -Or $MPRInFIMPSObject.AuthorizationWorkflowDefinition -contains $WorkflowObjectID) { # Object Is Used $workflowIsUsed = $true Break } Else { # Object Is NOT Used $workflowIsUsed = $false } } } # For Each Workflow Check If It Is Used In Some SET If (!$workflowIsUsed) { ForEach ($SETInFIMPSObject In $SETsInFIMPSObject) { If ($SETInFIMPSObject.Filter -match $($workflowObjectID.TrimStart("urn:uuid:")) -Or $SETInFIMPSObject.Filter -match $workflowDisplayName) { # Object Is Used $workflowIsUsed = $true Break } Else { # Object Is NOT Used $workflowIsUsed = $false } } } # If The Workflow Is Used If ($workflowIsUsed) { Write-Host "In Use: '$workflowDisplayName'..." -ForeGroundColor Green Add-Content $($currentFolder + "\" + $listOfWorkflowsUsed) $workflowDisplayName } # If The Workflow Is UnUsed If (!$workflowIsUsed) { Write-Host "Not In Use: '$workflowDisplayName'..." -ForeGroundColor Red Add-Content $($currentFolder + "\" + $listOfWorkflowsUnUsed) $workflowDisplayName } } } # Searching For Unused Mail Templates # Mail Templates Can Be Used In: # * Workflows # * Referenced By SETs If ($objectType.ToUpper() -eq "MailTemplate") { Write-Host "" Write-Host "+++ CHECKING USAGE OF MAIL TEMPLATES +++" -ForeGroundColor Cyan Write-Host "" # Files $listOfMailTemplatesUsed = "List-Of-MailTemplates-Used.txt" $listOfMailTemplatesUnUsed = "List-Of-MailTemplates-UnUsed.txt" # Check Current Files If (Test-Path $($currentFolder + "\" + $listOfMailTemplatesUsed)) { Remove-Item $($currentFolder + "\" + $listOfMailTemplatesUsed) -Force } If (Test-Path $($currentFolder + "\" + $listOfMailTemplatesUnUsed)) { Remove-Item $($currentFolder + "\" + $listOfMailTemplatesUnUsed) -Force } # Get All The Mail Templates $MailTemplatesInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/EmailTemplate" $MailTemplatesInFIMPSObject = $MailTemplatesInFIM | Convert-FimExportToPSObject # Get All The Workflows $WorkflowsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/WorkflowDefinition" $WorkflowsInFIMPSObject = $WorkflowsInFIM | Convert-FimExportToPSObject # Get All The SETs $SETsInFIM = Export-FIMConfig -Uri $URI –OnlyBaseResources -CustomConfig "/Set" $SETsInFIMPSObject = $SETsInFIM | Convert-FimExportToPSObject # For Each Mail Template Check If It Is Used Somewhere ForEach ($MailTemplateInFIMPSObject In $MailTemplatesInFIMPSObject) { $mailTemplateDisplayName = $MailTemplateInFIMPSObject.DisplayName $mailTemplateObjectID = $MailTemplateInFIMPSObject.ObjectID $mailTemplateIsUsed = $false # For Each Mail Template Check If It Is Used In Some Workflow If (!$mailTemplateIsUsed) { ForEach ($WorkflowInFIMPSObject In $WorkflowsInFIMPSObject) { If ($WorkflowInFIMPSObject.XOML -match $($mailTemplateObjectID.TrimStart("urn:uuid:"))) { # Object Is Used $mailTemplateIsUsed = $true Break } Else { # Object Is NOT Used $mailTemplateIsUsed = $false } } } # For Each Mail Template Check If It Is Used In Some SET If (!$mailTemplateIsUsed) { ForEach ($SETInFIMPSObject In $SETsInFIMPSObject) { If ($SETInFIMPSObject.Filter -match $($mailTemplateObjectID.TrimStart("urn:uuid:")) -Or $SETInFIMPSObject.Filter -match $mailTemplateDisplayName) { # Object Is Used $mailTemplateIsUsed = $true Break } Else { # Object Is NOT Used $mailTemplateIsUsed = $false } } } # If The Mail Template Is Used If ($mailTemplateIsUsed) { Write-Host "In Use: '$mailTemplateDisplayName'..." -ForeGroundColor Green Add-Content $($currentFolder + "\" + $listOfMailTemplatesUsed) $mailTemplateDisplayName } # If The Mail Template Is UnUsed If (!$mailTemplateIsUsed) { Write-Host "Not In Use: '$mailTemplateDisplayName'..." -ForeGroundColor Red Add-Content $($currentFolder + "\" + $listOfMailTemplatesUnUsed) $mailTemplateDisplayName } } }

The script supports the check for SET, Workflow and Mail Template objects. The script accepts two parameters, being -URI and -objectType. -URI is only mandatory if you are not running the script on the server with the FIM service. -objectType is always mandatory and accepts the values SET, Workflow or MailTemplate.

To find used and unused SETs, execute the following:

.\Finding-Unused-Objects-In-FIM-Portal.ps1 -objectType SET

The output can be seen below.

SNAGHTML352f4120

Figure 1: Finding Used And Unused SETS

To find used and unused Workflows, execute the following:

.\Finding-Unused-Objects-In-FIM-Portal.ps1 -objectType Workflow

The output can be seen below.

SNAGHTML353e7621

Figure 2: Finding Used And Unused Workflows

To find used and unused Mail Templates, execute the following:

.\Finding-Unused-Objects-In-FIM-Portal.ps1 -objectType MailTemplate

The output can be seen below.

SNAGHTML353f3aba

Figure 3: Finding Used And Unused Mail Templates

In addition to the output on screen, the script will also provide the output to a text file. For each object type 2 files are created when applicable. One file contains the objects used and the other file contains the unused objects.

SNAGHTML353e2b9b

Figure 4: Text Files Listing The Used And Unused Objects

Now, the script does NOT delete anything! It just enumerates the information and presents it to you. It is now up to you to delete an object or not based upon the information presented to you. As a suggestion, I would never delete an object that by default is in the FIM Portal.

Cheers,

Jorge

———————————————————————————————

* This posting is provided "AS IS" with no warranties and confers no rights!

* Always evaluate/test yourself before using/implementing this!

* DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

———————————————————————————————

############### Jorge’s Quest For Knowledge #############

######### http://JorgeQuestForKnowledge.wordpress.com/ ########

———————————————————————————————

3 Responses to “(2013-02-08) Unused SETs, Unused Workflows, Unused Mail Templates – Keeping FIM Portal Clean From Unused Configuration Objects”

  1. Nice post, and thanks for sharing!
    I’ve done something similar but treat the output as a suggestion for things that require investigation. The reason is that I have some code that makes use of FIM configuration objects, so would have to crawl the code to really determine if something is not being used.

    Also, I’ve found the performance of Export-FimConfig quite sluggish for this analysis so instead use a PowerShell module similar to the one on CodePlex that Gil posted a long time ago.

    Like

  2. […] by RCDCs. If you want to see if SETs are being used at all or not, you should have a look at this blog post. In this case we are interested to find out in WHICH MPRs a specific SET is being used. By default […]

    Like

  3. […] If you want to see if WorkflowDefinitions are being used at all or not, you should have a look at this blog post. In this case we are interested to find out in WHICH MPRs a specific WorkflowDefinition is being […]

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.