Jun 3, 2014 10:49:10 AM
Deleting a Large Number of Objects from the FIM Service with PowerShell

Deleting a large number of objects from the FIM Service can be accomplished in several ways:

  1. Create a custom workflow activity to delete the object that is triggered on a set transition MPR.
  2. Configure an MA to be authoritative for object deletion, then un-join the objects from the FIM MA.
  3. PowerShell scripts.

The PowerShell script seemed to be the least intrusive approach to us since it didn’t entail changing the configuration of the workflows or sync engine.

When enumerating a large number of objects via PowerShell, the script can time out—often after having run for a few hours, and you can be right back where you started from.

To avoid this, we wrote the following—which launches several independent windows to run the script, which are filtered by the starting letter of the last name.

cmd /c start powershell -NoExit -Command {$Host.UI.RawUI.WindowTitle = "Delete User - A"; .\DeleteUser.ps1 'A'}
cmd /c start powershell -NoExit -Command {$Host.UI.RawUI.WindowTitle = "Delete User - B"; .\DeleteUser.ps1 'B'}
cmd /c start powershell -NoExit -Command {$Host.UI.RawUI.WindowTitle = "Delete User - C"; .\DeleteUser.ps1 'C'}
cmd /c start powershell -NoExit -Command {$Host.UI.RawUI.WindowTitle = "Delete User - D"; .\DeleteUser.ps1 'D'}

Etc. to Z.

The deletion script will generate a request to the FIM Service for each object deleted, so that will generate a large queue if there are 26 scripts running at the same time. To minimize the performance impact on the FIM Service, we ran about 5-8 letters at a time.

Here is the code to delete the user.

param (

[string]$Letter = $(throw "Specify last letter"))

#----------------------------------------------------------------------------------------------------------

Set-Variable -Name URI -Value "http://localhost:5725/resourcemanagementservice" -Option Constant

#----------------------------------------------------------------------------------------------------------

Function DeletePerson

{

Param($ObjectId)

End

{

$ImportObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject

$ImportObject.ObjectType = "Person"

$ImportObject.TargetObjectIdentifier = $ObjectId

$ImportObject.SourceObjectIdentifier = $ObjectId

$ImportObject.State = 2

$ImportObject | Import-FIMConfig -uri $URI -ErrorVariable Err -ErrorAction SilentlyContinue

If($Err){Throw $Err}

}

}

#----------------------------------------------------------------------------------------------------------

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

#clear-host

$ExportObject = Export-FIMConfig -uri $URI `

–onlyBaseResources `

-customconfig "(/Person[starts-with(LastName, '$Letter')])" `

-ErrorVariable Err `

-ErrorAction SilentlyContinue

If($Err){Throw $Err}

If($ExportObject -eq $null) {throw "L:There are no persons in your environment"}

$iMax = @($ExportObject).Count

$i = 1

$ExportObject | ForEach{

$pctComp = ([int]($i/$iMax * 100))

Write-Progress -activity "Deleting As" `

-status "Please wait" -percentcomplete $pctComp `

-currentoperation "$i of $iMax Persons processed"

$ObjectId = (($_.ResourceManagementObject.ObjectIdentifier).split(":"))[2]

DeletePerson -ObjectId $ObjectId

$i++

}

Write-Host "`nCommand completed successfully`n"

#----------------------------------------------------------------------------------------------------------

Trap

{

$exMessage = $_.Exception.Message

If($exMessage.StartsWith("L:"))

{write-host "`n" $exMessage.substring(2) "`n" -foregroundcolor white -backgroundcolor darkblue}

Else {write-host "`nError: " $exMessage "`n" -foregroundcolor white -backgroundcolor darkred}

Exit 1

}

#