Summary


Utilizing the Windows PowerShell connector for FIM 2010 R2 it is possible to manage group membership of cloud-based (not synchronized) groups within Office365 that exceed 15,000 members. This guide will show the basics of utilizing the PowerShell connector to create a management agent that imports users and groups for metaverse synchronization and also exporting of a multivalued reference attribute of the members of the group back to the cloud based group.


Metaverse Requirements


The metaverse objects for users must contain the base-64 encoded string attribute of the Active Directory user objectGUID attribute. This is commonly referred to as sourceAnchor or ImmutableID. This attribute is used to join the Office365 user to the Active Directory user. The how-to of synchronizing this attribute to the metaverse is outside the scope of this document.

The metaverse objects for groups must contain the accountName/displayName of the Active Directory user sAMAccountName attribute. This attribute is used to join the Office365 group to the Active Directory group. The member attribute must also be imported into the metaverse so that the members can be synchronized to the Office365 group and exported to Windows Azure Active Directory (WAAD).


Configuration


To create the connector described in this section, configure the tabs in the Management Agent Designer as described in the Windows PowerShell Connector for FIM 2010 R2 Technical Reference.

Connectivity


Parameter Value
 Server <blank>
 Domain <blank>
 User <UserAdmin>@<domain>.onmicrosoft.com
 Password <password>
 Impersonate Connector Account Unchecked
 Load User Profile When Impersonating Unchecked
 Logon Type When Impersonating None
 Signed Scripts Only Unchecked
 Common Module Script Name (with extension) FIM.O365.psm1
 Common Module Script Paste FIM.O365.ps1m code
 Validation Script <blank>
 Schema Script Past FIM.O365.Schema.ps1 code
 Additional Config Parameter Names <blank>
 Additional Encrypted Config Parameter Names <blank>

Capabilities

Note: The Distinguished Name Style is Ldap because currently there is a bug (as of April 8th, 2014) with the PowerShell connector where selecting None produces an error that does not allow the management agent to be created.

Parameter Value
 Distinguished Name Style Ldap
 Export Type AttributeUpdate
 Data Normalization None
 Object Confirmation Normal
 Use DN as Anchor Checked
 Concurrent Operations of Several Connectors Checked
 Partitions Unchecked
 Hierarchy Unchecked
 Enable Import Checked
 Enable Delta Import Unchecked
 Enable Export Checked
 Enable Full Export Unchecked
 No Reference Values In First Export Pass Unchecked
 Enable Object Rename Unchecked
 Delete-Add As Replace Unchecked
 Enable Password Operations Unchecked
 Enable Export Password in First Pass Unchecked

Global Parameters


Parameter Value
 Partition Script <blank>
 Hierarchy Script <blank>
 Begin Import Script Paste FIM.O365.Import.Begin.ps1 code
 Import Script Paste FIM.O365.Import.ps1 code
 End Import Script Paste FIM.O365.Import.End.ps1 code
 Begin Export Script Paste FIM.O365.Export.Begin.ps1 code
 Export Script Paste FIM.O365.Export.ps1 code
 End Export Script <blank>
 Begin Password Script <blank>
 Password Extension Script <blank>
 End Password Script <blank>


Back to top

Configure Provisioning Hierarchy


Configure the hierarchy with no mapping as shown below.



Select Object Types


Select the user and group object types as show below.



Select Attributes


Select each of the attributes (DisplayName, ImmutableId, Member, ObjectID, UserPrincipalName) as show below.




Back to top

Configure Join and Projection Rules


User objects are matched to the metaverse person object by the ImmutableID (cs) to sourceAnchor (mv) attribute as shown below.



Group objects are matches to the metaverse group object by DisplayName (cs) to accountName (mv) attribute as shown below.



Configure Attribute Flow


Configure the group export of the member attribute as shown below.



Run Profiles


Once the connector has been created, create three run profiles:
  • Full Import (Stage Only)
  • Full Synchronization
  • Export


Back to top

PowerShell Scripts


FIM.O365.psm1

Set-StrictMode -Version 3            
            
function New-FIMSchema {            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.Schema])]            
    param()            
            
    [Microsoft.MetadirectoryServices.Schema]::Create()            
}            
            
function New-FIMSchemaType            
{            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.SchemaType])]            
    param            
    (            
        [ValidateNotNullOrEmpty()]            
        [string] $Name,            
        [switch] $LockAnchorAttributeDefinition            
    )            
            
    [Microsoft.MetadirectoryServices.SchemaType]::Create($Name, $LockAnchorAttributeDefinition.ToBool())            
}            
            
function Add-FIMSchemaAttribute            
{            
    [CmdletBinding(DefaultParameterSetName = 'SingleValued')]            
    [OutputType([Microsoft.MetadirectoryServices.SchemaAttribute])]            
    param            
    (            
        [Parameter(Mandatory, ValueFromPipeline)]            
        [ValidateNotNull()]            
        [Microsoft.MetadirectoryServices.SchemaType] $InputObject,            
            
        [Parameter(Mandatory, ParameterSetName='Anchor')]            
        [Parameter(Mandatory, ParameterSetName = 'MultiValued')]            
        [Parameter(Mandatory, ParameterSetName = 'SingleValued')]            
        [ValidateNotNullOrEmpty()]            
        [string] $Name,            
            
        [Parameter(ParameterSetName='Anchor')]            
        [switch] $Anchor,            
            
        [Parameter(ParameterSetName = 'MultiValued')]            
        [switch] $Multivalued,            
            
        [Parameter(Mandatory, ParameterSetName='Anchor')]            
        [Parameter(Mandatory, ParameterSetName = 'MultiValued')]            
        [Parameter(Mandatory, ParameterSetName = 'SingleValued')]            
        [ValidateSet('Binary', 'Boolean', 'Integer', 'Reference', 'String')]            
        [string] $DataType,            
            
        [Parameter(Mandatory, ParameterSetName='Anchor')]            
        [Parameter(Mandatory, ParameterSetName = 'MultiValued')]            
        [Parameter(Mandatory, ParameterSetName = 'SingleValued')]            
        [ValidateSet('ImportOnly', 'ExportOnly', 'ImportExport')]            
        [string] $SupportedOperation            
    )            
                
    switch ($PSCmdlet.ParameterSetName) {            
        'SingleValued' {            
            $InputObject.Attributes.Add([Microsoft.MetadirectoryServices.SchemaAttribute]::CreateSingleValuedAttribute($Name, $DataType, $SupportedOperation))            
        }            
            
        'MultiValued' {            
            if ($Multivalued) {            
                $InputObject.Attributes.Add([Microsoft.MetadirectoryServices.SchemaAttribute]::CreateMultiValuedAttribute($Name, $DataType, $SupportedOperation))            
            } else {            
                $InputObject.Attributes.Add([Microsoft.MetadirectoryServices.SchemaAttribute]::CreateSingleValuedAttribute($Name, $DataType, $SupportedOperation))            
            }            
        }            
            
        'Anchor' {            
            if ($Anchor) {            
                $InputObject.Attributes.Add([Microsoft.MetadirectoryServices.SchemaAttribute]::CreateAnchorAttribute($Name, $DataType, $SupportedOperation))            
            } else {            
                $InputObject.Attributes.Add([Microsoft.MetadirectoryServices.SchemaAttribute]::CreateSingleValuedAttribute($Name, $DataType, $SupportedOperation))            
            }            
        }            
    }            
}            
            
function New-FIMCSEntryChange            
{            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.CSEntryChange])]            
    param            
    (            
        [Parameter(Mandatory)]            
        [ValidateNotNullOrEmpty()]            
        [string] $ObjectType,            
            
        [Parameter(Mandatory)]            
        [ValidateSet('Add', 'Delete', 'Update', 'Replace', 'None')]            
        [string] $ModificationType,            
            
        [ValidateNotNullOrEmpty()]            
        [Alias('DistinguishedName')]            
        [string] $DN            
    )            
            
    $CSEntry = [Microsoft.MetadirectoryServices.CSEntryChange]::Create()            
    $CSEntry.ObjectModificationType = $ModificationType            
    $CSEntry.ObjectType = $ObjectType            
            
    if ($DN) {            
        $CSEntry.DN = $DN            
    }            
            
    $CSEntry            
}            
            
function Add-FIMCSAttributeChange            
{            
    [CmdletBinding(DefaultParameterSetName = 'Replace')]            
    param            
    (            
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='Add')]            
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='Update')]            
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='Delete')]            
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='Replace')]            
        [Parameter(Mandatory, ValueFromPipeline, ParameterSetName='Rename')]            
        [ValidateNotNull()]            
        [Microsoft.MetadirectoryServices.CSEntryChange] $InputObject,            
            
        [Parameter(Mandatory, ParameterSetName='Add')]            
        [switch] $Add,            
            
        [Parameter(Mandatory, ParameterSetName='Update')]            
        [switch] $Update,            
            
        [Parameter(Mandatory, ParameterSetName='Delete')]            
        [switch] $Delete,            
            
        [Parameter(Mandatory, ParameterSetName='Replace')]            
        [switch] $Replace,            
            
        [Parameter(Mandatory, ParameterSetName='Rename')]            
        [switch] $Rename,            
                    
        [Parameter(Mandatory, ParameterSetName='Add')]            
        [Parameter(Mandatory, ParameterSetName='Update')]            
        [Parameter(Mandatory, ParameterSetName='Delete')]            
        [Parameter(Mandatory, ParameterSetName='Replace')]            
        [ValidateNotNullOrEmpty()]            
        [string] $Name,            
            
        [Parameter(Mandatory, ParameterSetName='Add')]            
        [Parameter(Mandatory, ParameterSetName='Update')]            
        [Parameter(Mandatory, ParameterSetName='Replace')]            
        [Parameter(Mandatory, ParameterSetName='Rename')]            
        $Value,            
            
        [switch] $PassThru            
    )            
            
    process {            
        switch ($PSCmdlet.ParameterSetName) {            
            'Add' {            
                $InputObject.AttributeChanges.Add([Microsoft.MetadirectoryServices.AttributeChange]::CreateAttributeAdd($Name, $Value))            
            }            
            
            'Update' {            
                $InputObject.AttributeChanges.Add([Microsoft.MetadirectoryServices.AttributeChange]::CreateAttributeUpdate($Name, $Value))            
            }            
            
            'Delete' {            
                $InputObject.AttributeChanges.Add([Microsoft.MetadirectoryServices.AttributeChange]::CreateAttributeDelete($Name))            
            }            
            
            'Replace' {            
                $InputObject.AttributeChanges.Add([Microsoft.MetadirectoryServices.AttributeChange]::CreateAttributeReplace($Name, $Value))            
            }            
            
            'Rename' {            
                $InputObject.AttributeChanges.Add([Microsoft.MetadirectoryServices.AttributeChange]::CreateNewDN($Value))            
            }            
        }            
            
        if ($PassThru) {            
            $InputObject            
        }            
    }            
}            
            
function New-FIMPutExportEntriesResults            
{            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.PutExportEntriesResults])]            
    param            
    (            
        [ValidateNotNullOrEmpty()]            
        [Microsoft.MetadirectoryServices.CSEntryChangeResult[]] $Results            
    )            
            
    if ($Results) {            
        New-Object Microsoft.MetadirectoryServices.PutExportEntriesResults (New-Object System.Collections.Generic.List[Microsoft.MetadirectoryServices.CSEntryChangeResult] (,$Results))            
    } else {            
        New-Object Microsoft.MetadirectoryServices.PutExportEntriesResults            
    }            
}            
            
function New-FIMCloseImportConnectionResults            
{            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.CloseImportConnectionResults])]            
    param            
    (            
        [ValidateNotNullOrEmpty()]            
        [string] $CustomData            
    )            
            
    if ($CustomData) {            
        New-Object Microsoft.MetadirectoryServices.CloseImportConnectionResults $CustomData            
    } else {            
        New-Object Microsoft.MetadirectoryServices.CloseImportConnectionResults            
    }            
}            
            
function New-FIMOpenImportConnectionResults            
{            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.OpenImportConnectionResults])]            
    param            
    (            
        [ValidateNotNullOrEmpty()]            
        [string] $CustomData            
    )            
            
    if ($CustomData) {            
        New-Object Microsoft.MetadirectoryServices.OpenImportConnectionResults $CustomData            
    } else {            
        New-Object Microsoft.MetadirectoryServices.OpenImportConnectionResults            
    }            
}            
            
function New-FIMCSEntryChanges            
{            
    [CmdletBinding()]            
    [OutputType([System.Collections.Generic.List[Microsoft.MetaDirectoryServices.CSEntryChange]])]            
    param()            
            
    New-Object System.Collections.Generic.List[Microsoft.MetaDirectoryServices.CSEntryChange]            
}            
            
function New-FIMGetImportEntriesResults            
{            
    [CmdletBinding()]            
    [OutputType([Microsoft.MetadirectoryServices.GetImportEntriesResults])]            
    param            
    (            
        [string] $CustomData,            
            
        [switch] $MoreToImport,            
            
        [System.Collections.Generic.List[Microsoft.MetaDirectoryServices.CSEntryChange]] $CSEntries            
    )            
            
    if ($CustomData -or $CSEntries -or $MoreToImport) {            
        New-Object Microsoft.MetadirectoryServices.GetImportEntriesResults $CustomData,$MoreToImport.ToBool(),($CSEntries)            
    } else {            
        New-Object Microsoft.MetadirectoryServices.GetImportEntriesResults            
    }            
}            
            
Export-ModuleMember -Function * -Verbose:$false -Debug:$false
 


Back to top

FIM.O365.Schema.ps1

[CmdletBinding()]            
param            
(                
    [System.Collections.ObjectModel.KeyedCollectionstring], [Microsoft.MetadirectoryServices.ConfigParameter] $ConfigParameters,            
            
    [PSCredential] $PSCredential            
)            
            
Set-StrictMode -Version 3            
            
Import-Module (Join-Path -Path ([Environment]::GetEnvironmentVariable('TEMP', [EnvironmentVariableTarget]::Machine)) -ChildPath 'FIM.O365.psm1') -Verbose:$false            
            
$Schema = New-FIMSchema            
            
$SchemaType = New-FIMSchemaType -Name 'user'            
$SchemaType | Add-FIMSchemaAttribute -Name 'ObjectID' -Anchor -DataType 'String' -SupportedOperation ImportOnly            
$SchemaType | Add-FIMSchemaAttribute -Name 'UserPrincipalName' -DataType 'String' -SupportedOperation ImportOnly            
$SchemaType | Add-FIMSchemaAttribute -Name 'ImmutableId' -DataType 'String' -SupportedOperation ImportOnly            
            
$Schema.Types.Add($SchemaType)            
            
$SchemaType = New-FIMSchemaType -Name 'group'            
$SchemaType | Add-FIMSchemaAttribute -Name 'ObjectID' -Anchor -DataType 'String' -SupportedOperation ImportOnly            
$SchemaType | Add-FIMSchemaAttribute -Name 'DisplayName' -DataType 'String' -SupportedOperation ImportOnly            
$SchemaType | Add-FIMSchemaAttribute -Name 'Member' -DataType 'Reference' -MultiValued -SupportedOperation ImportExport            
            
$Schema.Types.Add($SchemaType)            
            
$Schema
 

FIM.O365.Import.Begin.ps1

[CmdletBinding()]            
param(                
    [System.Collections.ObjectModel.KeyedCollectionstring], [Microsoft.MetadirectoryServices.ConfigParameter] $ConfigParameters,            
                
    [ValidateNotNull()]            
    [PSCredential] $PSCredential,            
            
    [Microsoft.MetadirectoryServices.OpenImportConnectionRunStep] $OpenImportConnectionRunStep,            
                
    [Microsoft.MetadirectoryServices.Schema] $Schema            
)            
            
Set-StrictMode -Version 3            
            
Import-Module (Join-Path -Path ([Microsoft.MetadirectoryServices.MAUtils]::MAFolder) -ChildPath 'FIM.O365.psm1') -Verbose:$false -ErrorAction Stop            
Import-Module MSOnline -Verbose:$false -ErrorAction Stop            
            
Connect-MsolService -Credential $PSCredential -ErrorAction Stop            
            
$MsolObjects = @(Get-MsolUser -All -ErrorAction Stop | Where-Object { $_.ImmutableId } | Select-Object @{Name='Type';Expression={'User'}},ObjectId,UserPrincipalName,ImmutableId)             
$MsolObjects += @(Get-MsolGroup -All -ErrorAction Stop | Where-Object { !$_.LastDirSyncTime } | Select-Object @{Name='Type';Expression={'Group'}},ObjectId,DisplayName,@{Name='Members';Expression={@(Get-MsolGroupMember -GroupObjectId $_.ObjectID -MemberObjectTypes User -All | Select-Object -ExpandProperty ObjectID)}})            
            
$FilePath = Join-Path -Path ([Microsoft.MetadirectoryServices.MAUtils]::MAFolder) -ChildPath 'MsolObjects.xml'            
            
Write-Verbose "MsolObjects '$FilePath': $($MsolObjects.Count.ToString('#,##0'))"            
            
$MsolObjects | Export-Clixml -Path $FilePath -ErrorAction Stop            
            
New-FIMOpenImportConnectionResults
 

FIM.O365.Import.ps1

[CmdletBinding()]            
param(                
    [System.Collections.ObjectModel.KeyedCollectionstring], [Microsoft.MetadirectoryServices.ConfigParameter] $ConfigParameters,            
                
    [PSCredential] $PSCredential,            
            
    [ValidateNotNull()]            
    [Microsoft.MetadirectoryServices.ImportRunStep] $GetImportEntriesRunStep,            
            
    [ValidateNotNull()]            
    [Microsoft.MetadirectoryServices.OpenImportConnectionRunStep] $OpenImportConnectionRunStep,            
                
    [Microsoft.MetadirectoryServices.Schema] $Schema            
)            
            
Set-StrictMode -Version 3            
            
$FilePath = Join-Path -Path ([Microsoft.MetadirectoryServices.MAUtils]::MAFolder) -ChildPath 'MsolObjects.xml'            
            
if (!(Test-Path $FilePath)) {            
    throw "Could not locate import file: $FilePath"            
}            
            
if ($GetImportEntriesRunStep.CustomData) {            
    $Skip = [int]$GetImportEntriesRunStep.CustomData            
} else {            
    $Skip = 0            
}            
            
$MsolObjects = @(Import-Clixml -Path $FilePath -Skip $Skip -First $OpenImportConnectionRunStep.PageSize -ErrorAction Stop)            
            
$Changes = New-FIMCSEntryChanges            
            
$MsolObjects | ForEach-Object {            
    $MsolObj = $_            
    $CSEntry = $null            
            
    switch ($MsolObj.Type) {            
        'User' {            
            $CSEntry = New-FIMCSEntryChange -ObjectType 'user' -ModificationType Add -DN "USER=$($MsolObj.ObjectID)" |            
                            Add-FIMCSAttributeChange -Add -Name 'ObjectID' -Value $MsolObj.ObjectID.ToString() -PassThru |            
                            Add-FIMCSAttributeChange -Add -Name 'UserPrincipalName' -Value $MsolObj.UserPrincipalName -PassThru |            
                            Add-FIMCSAttributeChange -Add -Name 'ImmutableId' -Value $MsolObj.ImmutableId -PassThru            
        }            
                
        'Group' {            
            $CSEntry = New-FIMCSEntryChange -ObjectType 'group' -ModificationType Add -DN "GROUP=$($MsolObj.ObjectID)" |            
                            Add-FIMCSAttributeChange -Add -Name 'ObjectID' -Value $MsolObj.ObjectID.ToString() -PassThru |            
                            Add-FIMCSAttributeChange -Add -Name 'DisplayName' -Value $MsolObj.DisplayName -PassThru |            
                            Add-FIMCSAttributeChange -Add -Name 'Member' -Value ($MsolObj.Members | ForEach-Object {"USER=$_"}) -PassThru            
        }            
    }            
            
    $Changes.Add($CSEntry)            
}            
            
New-FIMGetImportEntriesResults -CustomData "$($Skip + $OpenImportConnectionRunStep.PageSize)" -MoreToImport:($MsolObjects.Count -ge $OpenImportConnectionRunStep.PageSize) -CSEntries $Changes
 

FIM.O365.Import.End.ps1

[CmdletBinding()]            
param(                
    [System.Collections.ObjectModel.KeyedCollectionstring], [Microsoft.MetadirectoryServices.ConfigParameter] $ConfigParameters,            
                
    [PSCredential] $PSCredential,            
            
    [Microsoft.MetadirectoryServices.OpenImportConnectionRunStep] $OpenImportConnectionRunStep,            
                
    [ValidateNotNull()]            
    [Microsoft.MetadirectoryServices.CloseImportConnectionRunStep] $CloseImportConnectionRunStep,            
                
    [Microsoft.MetadirectoryServices.Schema] $Schema            
)            
            
Set-StrictMode -Version 3            
            
$FilePath = Join-Path -Path ([Microsoft.MetadirectoryServices.MAUtils]::MAFolder) -ChildPath 'MsolObjects.xml'            
            
if ($CloseImportConnectionRunStep.Reason -eq [Microsoft.MetadirectoryServices.CloseReason]::Normal) {            
    if (Test-Path $FilePath) {            
        Remove-Item $FilePath -Confirm:$false -Force            
    }            
}            
            
New-FIMCloseImportConnectionResults
 

FIM.O365.Export.Begin.ps1

[CmdletBinding()]            
param(                
    [ValidateNotNull()]            
    [System.Collections.ObjectModel.KeyedCollectionstring], [Microsoft.MetadirectoryServices.ConfigParameter] $ConfigParameters,            
                
    [ValidateNotNull()]            
    [PSCredential] $PSCredential,            
            
    [Microsoft.MetadirectoryServices.OpenExportConnectionRunStep] $OpenExportConnectionRunStep,            
                
    [ValidateNotNull()]            
    [Microsoft.MetadirectoryServices.Schema] $Schema            
)            
            
Set-StrictMode -Version 3            
            
Import-Module (Join-Path -Path ([Microsoft.MetadirectoryServices.MAUtils]::MAFolder) -ChildPath 'FIM.O365.psm1') -Verbose:$false -ErrorAction Stop            
Import-Module MSOnline -Verbose:$false -ErrorAction Stop            
            
Connect-MsolService -Credential $PSCredential -ErrorAction Stop
 

FIM.O365.Export.ps1

[CmdletBinding()]            
param            
(                
    [ValidateNotNull()]            
    [System.Collections.ObjectModel.KeyedCollectionstring], [Microsoft.MetadirectoryServices.ConfigParameter] $ConfigParameters,            
            
    [PSCredential] $PSCredential,            
            
    [System.Collections.Generic.IList[Microsoft.MetaDirectoryServices.CSEntryChange]] $CSEntries,            
                
    [Microsoft.MetadirectoryServices.OpenExportConnectionRunStep] $OpenExportConnectionRunStep,            
            
    [Microsoft.MetadirectoryServices.Schema] $Schema            
)            
            
Set-StrictMode -Version 3            
            
foreach($CSEntry in $CSEntries) {            
    switch ($CSEntry.ObjectType) {            
        'group' {            
            switch ($CSEntry.ObjectModificationType) {            
                'Update' {            
                    $GroupObjectID = $CSEntry.DN.ToString().Substring('GROUP='.Length)            
                        
                    if ($CSEntry.AttributeChanges.Contains('Member')) {            
                        $CSEntry.AttributeChanges['Member'].ValueChanges | ForEach-Object {            
                            if ($_.Value -like 'USER=*') {            
                                $ObjectID = $_.Value.Substring('USER='.Length)            
                                        
                                switch ($_.ModificationType) {            
                                    'Add' {            
                                        Add-MsolGroupMember -GroupObjectId $GroupObjectID -GroupMemberObjectId $ObjectID -ErrorAction Continue            
                                    }            
            
                                    'Delete' {            
                                        Remove-MsolGroupMember -GroupObjectId $GroupObjectID -GroupMemberObjectId $ObjectID -ErrorAction Continue            
                                    }            
                                }            
                            }            
                        }            
                    }            
                }            
            }            
        }            
    }            
}            
            
New-FIMPutExportEntriesResults


Back to top

See Also

  • Windows PowerShell Connector for FIM 2010 R2 Technical Reference
  • Forefront Identity Manager 2010 TechNet Forum
  • FIM Community Information Center