0
Completed

Identity Broker PowerShell Connector begin/process/end sections

Bob Bradley 10 years ago updated by anonymous 9 years ago 3

Further to an email thread with Adam van Vliet 2 days ago, and the linked issue MCS-30, the following is an idea on how export performance for the PowerShell connector might be improved.

FYI only - the script below is the O365 update connector script from QBE hosted by Soren’s PowerShell MA. The 3 outer section headings correspond to the FIM MA SDK methods (BEGIN=Initialize, PROCESS=Export, END=Terminate).

I am thinking that the IdB PowerShell connector could be substantially improved if it were to adopt the same approach for exports, whereby the overhead of setting up/tearing down a single export each time (establishing connections, loading libraries, etc.) can be done once per export batch instead.

param 
(
                $Username = "",
                $Password = "",
    $AccountSkuId = "qbetest:ENTERPRISEPACK",
    $LogFilePath = "E:\Packages\FIM.Synchronisation\SvN\FIM2\Operations\Scripts\Logs",
    $LogFileName = ""
)

BEGIN
{
                Import-Module MSOnline -Force

    $ErrHandle = "" 

    $SecurePassword = ConvertTo-SecureString $Password -AsPlainText -Force
    $Creds = New-Object System.Management.Automation.PSCredential $Username, $SecurePassword

                Connect-MsolService -Credential $Creds

    if ($ErrHandle -ne "")
    { 
        # handle any logon errors 
        $message = 'Could not log on O365 with ' + $($Username) + ' to update licenses. ' + $ErrHandle 
        exit 
    } 

    #List of Service Plans

    #ServicePlan                             ProvisioningStatus
    #-----------                             ------------------
    #YAMMER_ENTERPRISE                       Success
    #RMS_S_ENTERPRISE                        Success
    #OFFICESUBSCRIPTION                      Success
    #MCOSTANDARD                             Success
    #SHAREPOINTWAC                           Success
    #SHAREPOINTENTERPRISE                    Success
    #EXCHANGE_S_ENTERPRISE                   Success
                    
    # Create MsolLicenseOptions only for OFFICESUBSCRIPTION
    #$O365Licences = New-MsolLicenseOptions $AccountSkuId -DisabledPlans SHAREPOINTWAC, SHAREPOINTENTERPRISE

    $MAName = "PowerShell Connector"
    $FIMRegKey = "hklm:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\FIMSynchronizationService\Parameters"
    $FIMParameters = Get-ItemProperty $FIMRegKey
    $cacheFileName = "cachedExports.xml"
    $office365MappingFile = "office365LicenseProfileGroupMapping.xml"

    # Set up hash table of cached exports for loading exported MemberOf property (to obsolete export)
    $cachePath = [System.IO.Path]::Combine($FIMParameters.Path, "MaData", $MAName, $cacheFileName)
    $office365MappingPath = [System.IO.Path]::Combine($FIMParameters.Path, "Extensions", $office365MappingFile)
    [xml]$office365Mapping = Get-Content -Path $office365MappingPath

    $cachedExports = @{}
    if (Test-Path $cachePath)
    {
        $cachedExports = Import-Clixml -Path $cachePath
    }

}

PROCESS
{

    function log( $message )
    {
                    if ( $LogFileName -and $message )
                    {
                                    $message | out-file ([System.IO.Path]::Combine($LogFilePath, $LogFileName)) -append
                    }
    }
        
    #Initialise values
                $Errorstatus = "success"
    $ErrorDetail = $null
    $IsLicensed = $null
    $IsLicensedChg = $null

    #Get UPN of the user
    $Anchor = $_."[Anchor]"

    #Get Identifier
    $Identifier = $_."[Identifier]"
    
    #Get Group Membership
    $MemberOf = $_.MemberOf

    
    #Get Object Modification Type
    $Action = $_."[ObjectModificationType]"

    $IsLicensedChg = $_.IsLicensed
    #$IsLicensedChg = $false

    #log $_

    $error.clear()

    try
                {
           $msoluser = Get-MsolUser -userprincipalname $Anchor -ErrorAction SilentlyContinue
           $IsLicensed = $msoluser.IsLicensed
           # Loop through each of the registered DNs in the hash table at the top of this script to find a match
           $profileToAssign = "none"
           # Loop through each configured profile to find a match in the MemberOf dn collection
           foreach ($group in $office365Mapping.o365LicenseProfiles.profiles.profile.group) {
                if ($MemberOf.Contains($group.dn)) {
                    #$IsLicensedChg = $true
                    $_.IsLicensed = $true
                    $profileToAssign = $group.parentNode.name
                    break;
                }
           }
           #foreach ($dn in $defaultProfileGroupDNs.Keys) {
           #     if ($MemberOf.Contains($dn)) {
           #         $IsLicensedChg = $true
           #         break;
           #     }
           #}
           log ("IsLicensed:" + $IsLicensed)
           log ("IsLicensedChg:" + $IsLicensedChg)
                      
           #region unsupported operations
                                   if ($Action -eq 'Add')
                                   {
                                                    throw "Add is not supported. Will be processed when Active Directory user is added/joined."
                                   }
                                   if ($Action -eq 'Delete')
                                   {
                                                    throw "Delete is not supported. Will be processed when Active Directory user is removed."
                                   }
                                   #endregion

           if ($Action -eq 'Replace')
                                   {               
               if($IsLicensedChg)
               {
                    if(!$IsLicensed)
                    {
                        ## Execute to get the list of SKU's for the client environment
                        $Skus = Get-MsolAccountSku

                        switch ($profileToAssign) {
                            "default" {
                                $O365Licences = New-MsolLicenseOptions -AccountSkuId $Skus[0].AccountSkuId -DisabledPlans $Skus[0].ServiceStatus[4].ServicePlan.ServiceName, `
                                                                                                    $Skus[0].ServiceStatus[5].ServicePlan.ServiceName
               
                                Set-MsolUserLicense -UserPrincipalName $Anchor -AddLicenses $AccountSkuId -LicenseOptions $O365Licences  
                                #Assigned new license
                                log "Assigned new license"
                            }
                            "TBA" {
                                # TODO: Copy the "default" section above and adjust according to the name configured in the xml mapping file
                            }
                            "none" {
                                # Do nothing
                            }
                            default { 
                                throw "undefined Office 365 License Profile configured: $profileToAssign"
                            }
                        }
                    }
                    else
                    {
                        #Already licensed
                        log "Already assigned license"
                    }                    
               }
               else
               {
                    log "No change ..."
                    if($IsLicensed)
                    {
                        #Remove any Previous Licenses
                        Set-MsolUserLicense -UserPrincipalName $Anchor -RemoveLicenses $msoluser.Licenses.AccountSkuId
                        log "Removed any Previous Licenses"
                    }
               }                
                # Cache export
                if (-not $cachedExports.ContainsKey($Anchor)) {
                    log ("Caching new export" + $Anchor)
                    $cachedExports.Add($Anchor, @{})
                    $cachedExports.($Anchor).Add("MemberOf", $MemberOf)
                    $cachedExports.($Anchor).Add("PendingDelta", $true)
                } else {
                    log ("Caching existing export " + $Anchor)
                    $cachedExports.($Anchor).("MemberOf") = $MemberOf
                    $cachedExports.($Anchor).("PendingDelta") = $true
                }
            }
    }
    catch
                {
                                $Errorstatus = "powershell-script-error"
                                $ErrorDetail =  $error[0] 
                }

   

    # return status about export operation
                $status = @{}
    $status."[Anchor]" = $Anchor
                $status."[Identifier]" = $Identifier
                $status."[ErrorDetail]" = $ErrorDetail
}


END
{
    $cachedExports | Export-Clixml -Path $cachePath
}

Waiting on results from v5.0 testing on MCS-30. If batched exports have already solved this problem then the argument for this issue is lessened.

I am on 4 and can't move to 5 on this project yet so will have to solve this another way for now Adam van Vliet

Migrated to Visual Studio Online.