{"id":1295,"date":"2011-02-02T11:39:39","date_gmt":"2011-02-02T11:39:39","guid":{"rendered":"https:\/\/www.wapshere.com\/missmiis\/?p=1295"},"modified":"2011-02-02T11:47:09","modified_gmt":"2011-02-02T11:47:09","slug":"using-powershell-to-update-fim-portal-objects-from-a-csv","status":"publish","type":"post","link":"https:\/\/www.wapshere.com\/missmiis\/using-powershell-to-update-fim-portal-objects-from-a-csv","title":{"rendered":"Using powershell to update FIM Portal objects from a CSV"},"content":{"rendered":"<p>I&#8217;ve just posted\u00c2\u00a0this script to the <a href=\"http:\/\/social.technet.microsoft.com\/wiki\/contents\/articles\/how-to-use-powershell-to-update-resources-from-a-csv-file.aspx\">FIM Forum Scriptbox<\/a>. It helped me do a bulk update of attributes in the FIM Portal that, for various reasons, I didn&#8217;t want to export through the Sync Service. I tried to make the script as flexible as possible, so it reads the attribute names from the header row of the CSV. I&#8217;ve only tested it wth single-valued string attributes so far.<\/p>\n<p>While developing this script I came across an issue\u00c2\u00a0with the Import-FIMConfig cmdlet where it\u00c2\u00a0uses a cached copy of the FIM schema\u00c2\u00a0(and considering, in retrospect,\u00c2\u00a0how long it takes to export the schema, I&#8217;m not surprised it does this). If you&#8217;ve just added a new attribute to the schema you\u00c2\u00a0will need to restart your powershell session. The error I was getting was System.NullReferenceException (<a href=\"http:\/\/social.technet.microsoft.com\/Forums\/en-US\/ilm2\/thread\/5d7dbc5e-2020-4ae2-8f94-99c39184c0da\">forum thread<\/a>).<\/p>\n<p><!--more--><\/p>\n<h3>Summary<\/h3>\n<p>This script will update resources in the FIM Portal using values in a CSV file.<\/p>\n<p>The CSV file must have the following:<\/p>\n<ul>\n<li>A\u00c2\u00a0header row,<\/li>\n<li>The first three columns must be as follows:\n<ul>\n<li>ObjectType &#8211; the resource type name as used in the Portal,<\/li>\n<li>IDAttribute &#8211; the name of the attribute used to identity the target resource,<\/li>\n<li>IDValue &#8211; that value of the attribute used to identify the target resource.<\/li>\n<\/ul>\n<\/li>\n<li>The remaining columns have the target Attribute Name from the FIM Portal as header.<\/li>\n<\/ul>\n<p>For example:<\/p>\n<div><\/div>\n<p><code><\/p>\n<pre>ObjectType,IDAttribute,IDValue,Department,JobTitle\r\nPerson,Email,carol@myorg.com,IT,Engineer\r\nPerson,Email,bob@myorg.com,HR,Advisor<\/pre>\n<p>\u00c2\u00a0<\/p>\n<p><\/code><\/p>\n<h3>Script Code<\/h3>\n<div><\/div>\n<p><code><\/p>\n<pre>PARAM($CSVFile,$FIMServer=\"localhost\",$Delimiter=\";\",$LogFile=\"ImportCSV-Attributes.log\")\r\n\r\nfunction GetAttribute\r\n{\r\n  PARAM($exportObject,[string] $name)\r\n  END\r\n  {\r\n    $attribute = $exportObject.ResourceManagementObject.ResourceManagementAttributes |\r\n        Where-Object {$_.AttributeName -eq $name}\r\n    if ($attribute -ne $null -and $attribute.Value) {\r\n        $attribute.Value\r\n    }\r\n  }\r\n}\r\n\r\nfunction SetAttribute\r\n{\r\n    PARAM($object, $attributeName, $attributeValue)\r\n    END\r\n    {\r\n        $importChange = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportChange\r\n        $importChange.Operation = 1\r\n        $importChange.AttributeName = $attributeName\r\n        $importChange.AttributeValue = $attributeValue\r\n        $importChange.FullyResolved = 1\r\n        $importChange.Locale = \"Invariant\"\r\n        if ($object.Changes -eq $null) {$object.Changes = (,$importChange)}\r\n        else {$object.Changes += $importChange}\r\n    }\r\n} \r\n\r\nfunction WriteLog\r\n{\r\n    PARAM($msg)\r\n    END\r\n    {\r\n        Add-Content -Path $LogFile -Encoding ASCII -value $msg\r\n        write-host $msg\r\n    }\r\n}\r\n\r\nif (Test-Path $LogFile) {Remove-Item $LogFile}\r\n\r\nif(@(get-pssnapin | where-object {$_.Name -eq \"FIMAutomation\"} ).count -eq 0) {add-pssnapin FIMAutomation}\r\n\r\n$URI = \"http:\/\/\" + $FIMServer + \":5725\/ResourceManagementService\"\r\n\r\n# Parse CSV file. Note we're not using import-csv because we don't know what the column headers will be.\r\n$csv = Get-Content $CSVFile\r\n$header = $csv[0].split($Delimiter)\r\n$numcols = $header.length\r\n$rowcount = 1\r\n\r\nwhile ($rowcount -lt $csv.length)\r\n{\r\n  $rowvals = $csv[$rowcount].split($Delimiter)\r\n  $filter = \"\/\" + $rowvals[0] + \"[\" + $rowvals[1] + \"='\" + $rowvals[2] + \"']\"\r\n  WriteLog -msg \"Searching on $filter\"\r\n\r\n  $FIMObject = $null\r\n  $FIMObject = export-fimconfig -uri $URI -customconfig ($filter) -ErrorVariable Err -ErrorAction SilentlyContinue\r\n  if ($FIMObject.length -gt 1) {$FIMObject = $FIMObject[0]}\r\n  $FIMObjectID = GetAttribute $FIMObject \"ObjectID\"\r\n  $FIMObjectType = GetAttribute $FIMObject \"ObjectType\"\r\n\r\n  if (($FIMObject -eq $null) -or ($FIMObjectID -eq $null))\r\n  {\r\n    WriteLog -msg \"  Not found\"\r\n  }\r\n  else\r\n  {\r\n    $bUpdateNeeded = $false\r\n\r\n    # Create Import object that will update object in FIM\r\n    $importObject = New-Object Microsoft.ResourceManagement.Automation.ObjectModel.ImportObject\r\n    $importObject.ObjectType = $FIMObjectType\r\n    $importObject.TargetObjectIdentifier = $FIMObjectID\r\n    $importObject.SourceObjectIdentifier = $FIMObjectID\r\n    $importObject.State = [Microsoft.ResourceManagement.Automation.ObjectModel.ImportState]::Put\r\n\r\n    # Add the attributes\r\n    $colcount = 3\r\n    while ($colcount -lt $rowvals.length)\r\n    {\r\n      $currentVal = $null\r\n      $currentVal = $FIMObject.ResourceManagementObject.ResourceManagementAttributes | where-object {$_.AttributeName -eq $header[$colcount]}\r\n\r\n      if ($rowvals[$colcount].length -eq 0)\r\n      {\r\n        $message = \"  No value to set for \" + $header[$colcount]\r\n        WriteLog -msg $message\r\n      }\r\n      elseif (($currentVal -ne $null) -and ($rowvals[$colcount] -eq $currentVal.Value))\r\n      {\r\n        $message = \"  Value for \" + $header[$colcount] + \" is already correct\"\r\n        WriteLog -msg $message\r\n      }\r\n      else\r\n      {\r\n        $bUpdateNeeded = $true\r\n        $message = \"  Setting \" + $header[$colcount] + \" to \" + $rowvals[$colcount]\r\n        WriteLog -msg $message\r\n        SetAttribute -object $importObject -attributeName $header[$colcount] -attributeValue $rowvals[$colcount]\r\n      }\r\n      $colcount += 1\r\n    }\r\n\r\n    # Import the changes into FIM\r\n    if ($bUpdateNeeded)\r\n    {\r\n      WriteLog -msg \"    Importing changes\"\r\n      $importObject | Import-FIMConfig -uri $URI\r\n    }\r\n  }\r\n\r\n  $rowcount += 1\r\n}<\/pre>\n<p>\u00c2\u00a0<\/p>\n<p><\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve just posted\u00c2\u00a0this script to the FIM Forum Scriptbox. It helped me do a bulk update of attributes in the FIM Portal that, for various reasons, I didn&#8217;t want to export through the Sync Service. I tried to make the script as flexible as possible, so it reads the attribute names from the header row&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[42,23],"tags":[],"class_list":["post-1295","post","type-post","status-publish","format-standard","hentry","category-fim-2010","category-powershell"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pkp1o-kT","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/comments?post=1295"}],"version-history":[{"count":3,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1295\/revisions"}],"predecessor-version":[{"id":1297,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/posts\/1295\/revisions\/1297"}],"wp:attachment":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/media?parent=1295"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/categories?post=1295"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/tags?post=1295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}