FIM, XPath, PowerShell

This topic contains 1 reply, has 2 voices, and was last updated by  Craig Martin 2 years, 6 months ago.

  • Author
    Posts
  • #24056

    Anonymous

    Hello Everyone.

    I am working with FIM 2010 and need some help with a script.
    Most of this is from the online community as I am trying to learn as fast as I can.

    If you could review the script and provide any suggestions or feedback on lines 448 through 512.

    Basically the goal is to search FIM via PowerShell and XPath and search for groups that do not meet a specific length in their name. For example, any group that has a name that is 8 characters or less in length, I would like to export the:
    1. Owner
    2. Security Group Name
    3. UUID (URL to FIM Managed Security Group)
    a. This will be concatenated (ex: iam.jones.com/identitymanagement/xx_P1 )
    4. Description of the Security Group

    Please note that on lines...
    370 #Script starts
    470 #Get Owner, DisplayName and Description based on ObjectID
    472 #If DisplayName is less than 8, If Owner is not null – iterate each Owner
    474 #Print Owner, DisplayName, Url, Description to CSV file.

    The current script is listed below:

    .\Update-FIMConfiguration.ps1 -ConfigurationFile .\Update-FIMConfiguration-20140108changes.ps1

    .NOTES

    #>

    [CmdletBinding(SupportsShouldProcess=$True)]
    param(
    [string]$ConfigurationFile = ".\FIM-GetGroups-Cfg.ps1",
    [string]$Uri = "http://localhost:5725",
    [string]$VerboseLogPath
    )
    set-psdebug -strict

    #*=============================================================================
    #* FUNCTION LISTINGS
    #*=============================================================================

    function CreateOutput($MyText) {
    If ($VerboseLogPath -eq "") {
    Write-Output ($MyText)
    } else {
    Write-Output ($MyText)
    Out-File -filepath $VerboseLogPath -Encoding "ASCII" -Append -inputObject $MyText
    }
    } #CreateOutput

    function Get-FIMObjectWithComparisonResults
    {

    param
    (

    [parameter(Mandatory=$true)]
    [String]
    $ObjectType,

    [parameter(Mandatory=$false)]
    [String]
    $XPathPredicate,

    [parameter(Mandatory=$false)]
    $SourceObjectIdentifier = [Guid]::Empty,

    [parameter(Mandatory=$false)]
    $TargetObjectIdentifier = [Guid]::Empty,

    [parameter(Mandatory=$true)]
    [ValidateScript({$_ -is [Hashtable]})]
    $KeyValuePair,

    [parameter(Mandatory=$false)]
    [ValidateScript({$_ -is [Microsoft.ResourceManagement.Automation.ObjectModel.ExportObject]})]
    $CachedExportObject = $null,

    [parameter(Mandatory=$false)]
    [Switch]
    $MultiValued = $false,

    [String]
    $Uri = "http://localhost:5725"

    )
    end
    {
    $Results = @{}
    $Results.CompareResult = $false
    $Results.LogData = @()
    $Results.ExportObject = $null

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

    $XPathFilter = "/" + $ObjectType + $XPathPredicate

    If ($CachedExportObject -eq $null) {
    $RetrievalType = "authoritative"
    $Results.ExportObject = Export-FIMConfig -Uri $Uri -OnlyBaseResources -CustomConfig $XPathFilter -ErrorAction SilentlyContinue
    } else {
    $RetrievalType = "cached"
    $Results.ExportObject = $CachedExportObject
    }

    if ($Results.ExportObject -eq $null) {
    Write-Error ("An object was not found with this criteria: $XPathFilter")
    $Results.LogData += ("An object was not found with this criteria: $XPathFilter")
    }
    else {
    $Results.LogData += ("Retrieved $RetrievalType object: $XPathFilter")

    $AttributeName = @($KeyValuePair.Keys)[0]

    $exportedKVP = $Results.ExportObject.ResourceManagementObject.ResourceManagementAttributes | Where-Object { $_.AttributeName -eq $AttributeName }

    If ($MultiValued) {
    If ($exportedKVP -eq $null) {
    $Results.LogData += ("Current values of {0} is NULL" -f $AttributeName)
    } else {
    $Results.LogData += ("Current values of {0} is {1}" -f $AttributeName, [string]::Join(",", $exportedKVP.Values))
    }
    If ($exportedKVP -ne $null){
    ForEach ($value in $exportedKVP.Values) {
    If ($value -eq $KeyValuePair[$AttributeName]) {
    $Results.LogData += ("This contains value {0}" -f $KeyValuePair[$AttributeName])
    $Results.CompareResult = $true
    } ElseIf ($value.StartsWith("urn:uuid:")) {
    If ($value.Substring(9) -eq $KeyValuePair[$AttributeName]) {
    $Results.LogData += ("This contains value {0}" -f $KeyValuePair[$AttributeName])
    $Results.CompareResult = $true
    }
    }
    }
    }
    If (-not $Results.CompareResult) {
    $Results.LogData += ("This does not contain value {0}" -f $KeyValuePair[$AttributeName])
    }
    } else {
    If ($exportedKVP -eq $null) {
    $Results.LogData += ("Current value of {0} is [null]" -f $AttributeName)
    If ($KeyValuePair[$AttributeName] -eq $null) {
    $Results.CompareResult = $true
    }
    } else {
    $Results.LogData += ("Current value of {0} is {1}" -f $AttributeName, $exportedKVP.Value)
    If ($exportedKVP.Value -eq ($KeyValuePair[$AttributeName] -Split "`r`n" -join "`n")) {
    $Results.CompareResult = $true
    } ElseIf ($exportedKVP.Value.StartsWith("urn:uuid:")) {
    If ($exportedKVP.Value.Substring(9) -eq $KeyValuePair[$AttributeName]) {
    $Results.CompareResult = $true
    }
    }
    }
    }
    }
    Write-Output $Results
    }
    } #Get-FIMObjectWithComparisonResults

    function Get-FIMObjectIDUsingXPath($ObjectType, $XPathPredicate) {

    $ObjectID = $null
    CreateOutput ("In FIMObjectIDXpath " +$ObjectType + ","+$XPathPredicate)
    #$XPathFilter = "/" + $ObjectType + $XPathPredicate
    $XPathFilter = "/Group" + $XPathPredicate
    CreateOutput ("In FIMObjectIDXpath " +$XPathFilter)
    $ExportResults = Export-FIMConfig -Uri $Uri -OnlyBaseResources -CustomConfig $XPathFilter -ErrorAction SilentlyContinue
    if ($ExportResults -eq $null) {
    Write-Error ("An object was not found with this criteria: $XPathFilter")
    }
    else {
    $exportedKVP = $ExportResults.ResourceManagementObject.ResourceManagementAttributes | Where-Object { $_.AttributeName -eq 'ObjectID' }
    $ObjectID = $exportedKVP.Value
    }

    $ObjectID

    } #Get-FIMObjectIDUsingXPath

    function Update-FIMObjectIfNecessary($ObjectType, $XPathPredicate, $KeyValuePair) {
    $ReachedDesiredState = $false
    [string]$Key = $KeyValuePair.Keys
    If ($KeyValuePair[$Key] -ne $null) {
    [string]$Value = $KeyValuePair.Values
    $KeyValuePair = @{$Key=$Value.Replace("%FORESTROOTDN%", $ForestRootDN).Replace("%FORESTROOTNETBIOS%", $ForestRootNetBIOS)}
    }
    Do {
    CreateOutput (get-date -UFormat "%Y.%m.%d.%H.%M.%S")
    $ReturnValues = Get-FIMObjectWithComparisonResults -Uri $Uri -ObjectType $ObjectType -XPathPredicate $XPathPredicate -KeyValuePair $KeyValuePair
    CreateOutput ($ReturnValues.LogData)
    If ($ReturnValues.CompareResult) {
    $ReachedDesiredState = $true
    } else {
    $ObjectID = $ReturnValues.ExportObject.ResourceManagementObject.ObjectIdentifier.Replace('urn:uuid:',")
    CreateOutput ("Updating /$ObjectType$XPathPredicate")
    CreateOutput ($KeyValuePair)
    #See if we're updating to a value or null
    $AttributeName = @($KeyValuePair.Keys)[0]
    If ($KeyValuePair[$AttributeName] -eq $null) {
    $Change = New-FimImportChange -Uri $Uri -Operation 'Replace' -AttributeName $AttributeName
    } else {
    $Change = New-FimImportChange -Uri $Uri -Operation 'Replace' -AttributeName $AttributeName -AttributeValue $KeyValuePair[$AttributeName]
    }
    $ImportObject = New-FimImportObject -Uri $Uri -ObjectType $ObjectType -State 'Put' -SourceObjectIdentifier $ObjectID -TargetObjectIdentifier $ObjectID -Changes $Change -PassThru
    If ($pscmdlet.ShouldProcess("/$ObjectType$XPathPredicate")) {
    $ImportObject | Import-FIMConfig -Uri $Uri
    } else {
    $ReachedDesiredState = $true
    }
    }
    } While (-not $ReachedDesiredState)
    } #Update-FIMObjectIfNecessary

    function Update-FIMObjectMultiValueIfNecessary($ObjectType, $XPathPredicate, $ChangeType, $KeyValuePair) {
    $ReachedDesiredState = $false
    [string]$Key = $KeyValuePair.Keys
    If ($KeyValuePair[$Key] -ne $null) {
    [string]$Value = $KeyValuePair.Values
    $KeyValuePair = @{$Key=$Value.Replace("%FORESTROOTDN%", $ForestRootDN).Replace("%FORESTROOTNETBIOS%", $ForestRootNetBIOS)}
    }
    Do {
    CreateOutput (get-date -UFormat "%Y.%m.%d.%H.%M.%S")
    $ReturnValues = Get-FIMObjectWithComparisonResults -Uri $Uri -ObjectType $ObjectType -XPathPredicate $XPathPredicate -KeyValuePair $KeyValuePair -MultiValued $true
    CreateOutput ($ReturnValues.LogData)

    If ($ChangeType -eq 'Add') {
    $DesiredComparisionResult = $true
    } else {
    $DesiredComparisionResult = $false
    }

    If ($ReturnValues.CompareResult -eq $DesiredComparisionResult) {
    $ReachedDesiredState = $true
    } else {
    $ObjectID = $ReturnValues.ExportObject.ResourceManagementObject.ObjectIdentifier.Replace('urn:uuid:',")
    CreateOutput ("Updating /$ObjectType$XPathPredicate $ChangeType")
    CreateOutput ($KeyValuePair)
    $AttributeName = @($KeyValuePair.Keys)[0]
    $Change = New-FimImportChange -Uri $Uri -Operation $ChangeType -AttributeName $AttributeName -AttributeValue $KeyValuePair[$AttributeName]
    $ImportObject = New-FimImportObject -Uri $Uri -ObjectType $ObjectType -State 'Put' -SourceObjectIdentifier $ObjectID -TargetObjectIdentifier $ObjectID -Changes $Change -PassThru
    If ($pscmdlet.ShouldProcess("/$ObjectType$XPathPredicate")) {
    $ImportObject | Import-FIMConfig -Uri $Uri
    } else {
    $ReachedDesiredState = $true
    }
    }
    } While (-not $ReachedDesiredState)
    } #Update-FIMObjectMultiValueIfNecessary

    function Add-FIMObjectIfNecessary($ObjectType, $XPathPredicate, $CreationCommand) {
    $ReachedDesiredState = $false
    Do {
    CreateOutput (get-date -UFormat "%Y.%m.%d.%H.%M.%S")
    $ReturnValues = Get-FIMObjectWithComparisonResults -Uri $Uri -ObjectType $ObjectType -XPathPredicate $XPathPredicate -KeyValuePair @{'TestingForCreation'='IgnoreAttributeFailure'}
    CreateOutput ($ReturnValues.LogData | Where-Object { $_ -ne 'Current value of TestingForCreation is [null]' })
    If ($ReturnValues.ExportObject -ne $null) {
    $ReachedDesiredState = $true
    } else {
    CreateOutput ("Creating /$ObjectType$XPathPredicate as $CreationCommand")
    If ($pscmdlet.ShouldProcess("/$ObjectType$XPathPredicate")) {
    Invoke-Expression -Command $CreationCommand
    } else {
    $ReachedDesiredState = $true
    }
    }
    } While (-not $ReachedDesiredState)
    } #Add-FIMObjectIfNecessary

    function Remove-FIMObjectIfNecessary($ObjectType, $XPathPredicate) {
    $ReachedDesiredState = $false
    Do {
    CreateOutput (get-date -UFormat "%Y.%m.%d.%H.%M.%S")
    $ReturnValues = Get-FIMObjectWithComparisonResults -Uri $Uri -ObjectType $ObjectType -XPathPredicate $XPathPredicate -KeyValuePair @{'TestingForCreation'='IgnoreAttributeFailure'}
    CreateOutput ($ReturnValues.LogData | Where-Object { $_ -ne 'Current value of TestingForCreation is [null]' })
    If ($ReturnValues.ExportObject -eq $null) {
    $ReachedDesiredState = $true
    } else {
    CreateOutput ("Deleting /$ObjectType$XPathPredicate")
    $AttributeName = ($XPathPredicate.Split("="))[0].Replace("[", "")
    $AttributeValue = ($XPathPredicate.Split("="))[1].Replace("]", "").Replace("'","")
    If ($pscmdlet.ShouldProcess("/$ObjectType$XPathPredicate")) {
    $deleteRequest = New-FimImportObject -Uri $Uri -ObjectType $ObjectType -State Delete -AnchorPairs @{$AttributeName=$AttributeValue} -PassThru
    $deleteRequest | Import-FIMConfig
    } else {
    $ReachedDesiredState = $true
    }
    }
    } While (-not $ReachedDesiredState)
    } #Remove-FIMObjectIfNecessary

    function Test-VariableDefinedAndNotNull ($MyVar) {
    If (Test-Path variable:\$MyVar) {
    If ($MyVar -eq $null) {
    $false
    } else {
    $true
    }
    } else {
    $false
    }
    }

    #*=============================================================================
    #* SCRIPT BODY
    #*=============================================================================

    $ScriptVersion = "Date – Name"
    $ThisScript = Get-Item $MyInvocation.MyCommand.Definition

    If ($VerboseLogPath.Contains("?")) {
    get-help $MyInvocation.MyCommand.Definition -detailed
    exit
    }

    #The add-pssnapin in FimPowerShellModule.psm1 breaks the FIMAutomation cmdlets.
    #The snapin MUST be added BEFORE the module is imported
    if(-not (get-pssnapin | Where-Object {$_.Name -eq 'FIMAutomation'})) {
    add-pssnapin FIMAutomation
    }
    if((get-pssnapin | Where-Object {$_.Name -eq 'FIMAutomation'})) {
    }

    $Imported = $false
    If (-not $Imported) {
    CreateOutput ("In Powrshell import module before " +$Imported)
    Import-Module FimPowerShellModule -ErrorAction SilentlyContinue

    If ((get-module | where-object { $_.Name -eq 'FimPowerShellModule' }) -ne $null) {
    $Imported=$true
    }
    }

    If (-not $Imported) {
    Import-Module .\FimPowerShellModule.psm1 -ErrorAction SilentlyContinue
    If ((get-module | where-object { $_.Name -eq 'FimPowerShellModule' }) -ne $null) {
    $Imported=$true
    }
    }

    If (-not $Imported) {
    Import-Module FimPowerShellModule
    Import-Module .\FimPowerShellModule.psm1
    Write-Error "Module Import Failed"
    exit 1
    }

    #
    #Establish our replacement variable values
    #%FORESTROOTDN% = $ForestRootDN
    #%FORESTROOTNETBIOS% = $ForestRootNetBIOS
    #

    $RootDSE = [ADSI]("LDAP://RootDSE")
    $ForestRootDN = $RootDSE.rootDomainNamingContext
    $SearchConfigForObject = New-Object DirectoryServices.DirectorySearcher
    $SearchConfigForObject.SearchRoot = "LDAP://" + $RootDSE.configurationNamingContext
    $SearchConfigForObject.filter = "(&(objectclass=crossref)(ncname=$ForestRootDN))"
    $SearchConfigForObject.PropertiesToLoad.Add("netbiosname") | out-Null
    $CrossRef = $SearchConfigForObject.FindOne()
    If ($CrossRef -ne $null) {
    $ForestRootNetBIOS = $CrossRef.Properties.netbiosname.item(0)
    }

    #
    #Read in and execute external configuration
    #
    If (-not (Test-Path -Path $ConfigurationFile -PathType Leaf)) {
    exit 1
    }

    # Load configuration file – comment out on 4/2/15
    #. $ConfigurationFile

    $GroupName= 'SampleGroupName'
    $ObjectType = 'Group'
    $XPathPredicate = ""
    $XPathPredicate = "[DisplayName='$GroupName']"
    #$XPathPredicate = "[DisplayName.Length -eq 8]"
    #ak-$XPathPredicate = "[(Type = 'Security') and ((DisplayName.Length 8) or (AccountName.Length -le 8))]"
    #ak-$XPathPredicate = "[(Type = 'Security') and ((string-length(DisplayName()) < 8) or (string-length(AccountName()) < 8))]" #$XPathPredicate = "[(Type = 'Security') and ((string-length(DisplayName()) <= 8) or (string-length(AccountName()) <= 8))]" $AllGroupObjects = Get-FIMObjectIDUsingXPath $ObjectType $XPathPredicate foreach ($GroupObject in $AllGroupObjects) { If ($GroupObject.XPathFilter.Length < 8) { {$objItem = $GroupObject.Properties "Name: " + $objItem.name "Title: " + $objItem.jobTitle "Description: " + $objItem.description "URI: " + $objItem.Uri If($objItem.name not eq $null) { If ($FileExists -eq $True) {Write-Output $objItem "True"} Else {Write-Output $objItem "False"} | export-csv C:\scripts\output.csv -Append } else {} #else for the objItem.name not being null } } else {} #else for the container being more than 8 characters #Get Owner, DisplayName and Description based on ObjectID #If DisplayName is less than 8, If Owner is not null – iterate each Owner #Print Owner, DisplayName, Url, Description to CSV file. # https://powershell.org/forums/topic/ad-export-group-members-but-with-a-twist/
    # This will allow to you put all seven group names in and run it as a scheduled task.
    # It'll plop the timestamped csv file out onto a share of your choice for whoever you want to share it with.
    # Note: $ADUser.Manager returns a super long distinguished name so I used some crude string manipulation tricks
    # to get just the alias so I didn't have to do another Get-ADUser query.

    $Groups = 'Group1','Group2','Group3','Group4','Group5','Group6','Group7'
    $FileName = "ADGroupMem_$(Get-Date -Format "yyyyMMddmmss")"
    $SavePath = "c:\ps\$FileName.csv"

    Foreach ($Group in $Groups){

    $ADGroup = Get-ADGroup -Identity $Group
    $ADGroupMem = Get-ADGroupMember -Identity $ADGroup

    ForEach ($Member in $ADGroupMem){

    $ADUser = $Member | Get-ADUser -Properties SamAccountName,Department,Title,Manager
    if ($ADUser.Manager){
    #$ManagerName = ($ADUser.Manager).Split(",") | Select-Object -Index 0 | ForEach-Object {$_ -replace "CN=",""}
    $ManagerName = Get-ADUser -LDAPFilter "(DistinguishedName=$($ADUser.Manager))" -Properties DisplayName | Select-Object -Expand DisplayName
    } else {
    $ManagerName = "None listed"
    }
    [PSCustomObject]@{
    GroupName = $ADGroup.Name
    SAMAccountName = $ADUser.SamAccountName
    Department = $ADUser.Department
    Title = $ADUser.Title
    Manager = $ManagerName

    } | Export-Csv -Path $SavePath -Append -NoTypeInformation
    }

    }

    }

    #Boolean Expressions listed below https://msdn.microsoft.com/en-us/library/ms256081(v=vs.90).aspx
    #< * Less than # * Greater than #<= * Greater than or equal #//*[string-length(DisplayName()) < 8] #http://zvon.org/xxl/XPathTutorial/Output/paths.html #Get-FimObjectID -ObjectType 'Group' -Uri $Uri -AttributeName -AttributeName 'DisplayName' -AttributeValue 'SampleGroupName' -AttributeName 'Owner' -AttributeValue '

  • #24057

    Craig Martin
    Member

    Sometimes it is just easier to dump ALL the objects then use a PowerShell Where-Object command to do the filtering.

    For example:

    ### Get all the FIM Groups
    $AllFimGroups = Export-FimConfig -Only -Custom "/Group" | Convert-FimExportToPSObject
    
    ### Get just the offenders
    $OffensiveGroups = $AllFimGroups | Where-Object {$_.AccountName.Length -lt 8}
    

    NOTE: Convert-FimExportToPSObject is from the FimPowerShellModule on CodePlex.

You must be logged in to reply to this topic.