зеркало из https://github.com/microsoft/MIMDSC.git
adds functions for generating DSC configuration from MIM Service objects
This commit is contained in:
Родитель
b56ef645f2
Коммит
779e72d878
|
@ -0,0 +1,29 @@
|
|||
function Convert-MimSvcObjectToDscDependsOnString
|
||||
{
|
||||
param
|
||||
(
|
||||
<#
|
||||
A MIM Service Object to convert
|
||||
#>
|
||||
[parameter(Mandatory=$true, ValueFromPipeline = $true)]
|
||||
$MimObject
|
||||
)
|
||||
begin
|
||||
{
|
||||
$dependsOnStrings = @()
|
||||
}
|
||||
process
|
||||
{
|
||||
$dscConfigurationItemName = Convert-MimSvcObjectToDscItemName -MimObject $MimObject
|
||||
Write-Verbose " DependsOn [$($MimObject.ObjectType)]$($dscConfigurationItemName)"
|
||||
$dependsOnStrings += ("'[{0}]{1}'" -F ($MimObject.ObjectType -replace '-'), $dscConfigurationItemName)
|
||||
}
|
||||
end
|
||||
{
|
||||
### Only output if we have items
|
||||
if ($dependsOnStrings.Count -gt 0)
|
||||
{
|
||||
Write-Output ($dependsOnStrings -join ',')
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
function Convert-MimSvcObjectToDscItemName
|
||||
{
|
||||
param
|
||||
(
|
||||
<#
|
||||
A MIM Service Object to convert
|
||||
#>
|
||||
[parameter(Mandatory=$true, ValueFromPipeline = $true)]
|
||||
$MimObject
|
||||
)
|
||||
|
||||
###
|
||||
### Get the attribute that is unique for this object type
|
||||
if ($MimObject.ObjectType -in 'ObjectTypeDescription','AttributeTypeDescription')
|
||||
{
|
||||
$mimKeyAttributeValue = $MimObject.Name
|
||||
}
|
||||
elseif($MimObject.ObjectType -eq 'BindingDescription')
|
||||
{
|
||||
### Custom Configuration AttributeName for BindingDescription
|
||||
$BoundAttribute = Get-Resource -ID $MimObject.BoundAttributeType
|
||||
$BoundObject = Get-Resource -ID $MimObject.BoundObjectType
|
||||
|
||||
$mimKeyAttributeValue = "{0}{1}" -F $BoundObject.Name, $BoundAttribute.Name
|
||||
}
|
||||
elseif($MimObject.ObjectType -in 'HomePageConfiguration','SearchScopeConfiguration')
|
||||
{
|
||||
$mimKeyAttributeValue = "{0}{1}" -F $MimObject.DisplayName, $MimObject.Order
|
||||
}
|
||||
else
|
||||
{
|
||||
$mimKeyAttributeValue = $MimObject.DisplayName
|
||||
}
|
||||
## Do some sanitizing for the DSC item name
|
||||
Write-Output ($mimKeyAttributeValue -replace ' ' -replace '\)' -replace '\(' -replace '-' -replace "'" -replace ':' -replace "’" -replace '&' -replace '/' -replace ',')
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
function Convert-MimSvcObjectToDscScript
|
||||
{
|
||||
param
|
||||
(
|
||||
[parameter(Mandatory=$true, ValueFromPipeline = $true)]
|
||||
$MimObject,
|
||||
[Switch]$SkipGuidConversion,
|
||||
[Switch]$SkipDependsOnForSchema
|
||||
)
|
||||
begin
|
||||
{
|
||||
$includedAttributes = @('Description','Filter','AccountName','DisplayName','FirstName','LastName','DisplayedOwner','MembershipAddWorkflow','MembershipLocked','Owner','Scope','Type','Domain')
|
||||
$mimReferenceValues = @()
|
||||
}
|
||||
process
|
||||
{
|
||||
Write-Verbose "[$(Get-Date)] MIM Object: [$($MimObject.ObjectType)]$($MimObject.ObjectID)"
|
||||
$mimObjectType = $MimObject.ObjectType
|
||||
|
||||
$supportedObjectTypes = @(
|
||||
'ActivityInformationConfiguration'
|
||||
'AttributeTypeDescription'
|
||||
'BindingDescription'
|
||||
'DomainConfiguration'
|
||||
'EmailTemplate'
|
||||
'FilterScope'
|
||||
'ForestConfiguration'
|
||||
'Group'
|
||||
'HomepageConfiguration'
|
||||
#'ma-data'
|
||||
'ManagementPolicyRule'
|
||||
'msidmSystemConfiguration'
|
||||
'NavigationBarConfiguration'
|
||||
'ObjectTypeDescription'
|
||||
'ObjectVisualizationConfiguration'
|
||||
'Person'
|
||||
'PortalUIConfiguration'
|
||||
'Resource'
|
||||
'SearchScopeConfiguration'
|
||||
'Set'
|
||||
'SynchronizationFilter'
|
||||
'SynchronizationRule'
|
||||
'SystemResourceRetentionConfiguration'
|
||||
'TimeZoneConfiguration'
|
||||
'WorkflowDefinition'
|
||||
)
|
||||
if ($MimObject.ObjectType -notin $supportedObjectTypes)
|
||||
{
|
||||
Write-Warning " Object type not currently supported: $($MimObject.ObjectType)"
|
||||
return
|
||||
}
|
||||
|
||||
###
|
||||
### Check to see if we've already processed this item
|
||||
###
|
||||
if ($mimObject.ObjectID -in $global:processedObjectIDs)
|
||||
{
|
||||
Write-Warning (" This objectID has already been processed already: {0}" -F $mimObject.ObjectID)
|
||||
return
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Debug (" Adding ObjectID to the list of items already processed: {0}" -F $mimObject.ObjectID)
|
||||
$global:processedObjectIDs += $mimObject.ObjectID
|
||||
}
|
||||
|
||||
### Get the DSC type and DSC item name for this object
|
||||
$dscResourceType = "$($MimObject.ObjectType)" -replace '-'
|
||||
$dscItemName = Convert-MimSvcObjectToDscItemName -MimObject $MimObject
|
||||
$mimDscString = "$dscResourceType $dscItemName`n{`n"
|
||||
|
||||
### Find the longest attribute name to determine the column width
|
||||
$columnWidth = $mimObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty Name | Select-Object -ExpandProperty Length | Sort-Object| Select-Object -Last 1
|
||||
Write-Debug "Using a column width of $columnWidth"
|
||||
|
||||
<#
|
||||
### Get the DSC resource for this object type
|
||||
if ($Script:DscResourceProperties.ContainsKey($dscResourceType))
|
||||
{
|
||||
$dscResourcePropertyNames = $Script:DscResourceProperties[$dscResourceType]
|
||||
}
|
||||
else
|
||||
{
|
||||
$dscResource = Get-DscResource -Name $dscResourceType
|
||||
$dscResourcePropertyNames = $dscResource.Properties | Select-Object -ExpandProperty Name
|
||||
|
||||
$Script:DscResourceProperties.Add($dscResourceType, $dscResourcePropertyNames)
|
||||
}
|
||||
#>
|
||||
|
||||
##HACK - rename 'Scope' to 'GroupScope'
|
||||
if (($mimObject | Get-Member -MemberType NoteProperty).Name -contains 'Scope')
|
||||
{
|
||||
#$scopeAttribute = $mimObject | Get-Member -MemberType NoteProperty | Where AttributeName -eq 'Scope'
|
||||
#$scopeAttribute.AttributeName = 'GroupScope'
|
||||
Write-Warning "Hacked out hack - this could break something"
|
||||
}
|
||||
|
||||
$mimDependsOnValues = @()
|
||||
|
||||
foreach($mimAttribute in ($mimObject | Get-Member -MemberType NoteProperty))
|
||||
{
|
||||
Write-Debug " Processing attribute: $($mimAttribute.AttributeName)"
|
||||
if ($mimAttribute.Name -in 'AuthNWFLockedOut','AuthNWFRegistered','AuthNLockoutRegistrationID','DomainConfiguration','ObjectID','CreatedTime','Creator','ResourceTime','DeletedTime','ObjectType','DetectedRulesList','ExpectedRulesList','ExpirationTime','MVObjectID')
|
||||
{
|
||||
Write-Debug " Skipping system-owned attribute: $($mimAttribute.Name)"
|
||||
continue
|
||||
}
|
||||
|
||||
if ($mimAttribute.Name -in 'ExplicitMember','ComputedMember')
|
||||
{
|
||||
Write-Debug " Skipping user-owned attribute: $($mimAttribute.Name)"
|
||||
continue
|
||||
}
|
||||
|
||||
<#
|
||||
if ($mimAttribute.Name -notin $dscResourcePropertyNames)
|
||||
{
|
||||
Write-Warning " Skipping attribute because there is no matching property in the DSC resource: $($mimAttribute.Name)"
|
||||
}
|
||||
#>
|
||||
$attributeType = Search-Resources -XPath "/AttributeTypeDescription[Name = '$($mimAttribute.Name)']" -AttributesToGet Name, DataType,Multivalued
|
||||
|
||||
$mimDscAttributeString = ''
|
||||
if ($attributeType.MultiValued -and $attributeType.DataType -eq 'Reference')
|
||||
{
|
||||
$mimAttributeValues = @()
|
||||
foreach($mimAttributeValue in $mimObject.($mimAttribute.Name))
|
||||
{
|
||||
|
||||
$mimAttributeValues += Convert-MimSvcReferenceToDscLookupString -ReferenceString $mimAttributeValue
|
||||
$mimDependsOnValues += Convert-MimSvcReferenceToMimObject -ReferenceString $mimAttributeValue -SkipDependsOnForSchema:$SkipDependsOnForSchema | Convert-MimSvcObjectToDscDependsOnString
|
||||
$mimReferenceValues += $mimAttributeValue
|
||||
}
|
||||
$mimDscAttributeString = $mimAttributeValues -join ','
|
||||
}
|
||||
elseif ($attributeType.MultiValued)
|
||||
{
|
||||
$mimAttributeValues = @()
|
||||
foreach($mimAttributeValue in $mimObject.($mimAttribute.Name))
|
||||
{
|
||||
$mimAttributeValues += "'$mimAttributeValue'"
|
||||
}
|
||||
$mimDscAttributeString = $mimAttributeValues -join ','
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($attributeType.DataType -eq 'Reference')
|
||||
{
|
||||
if ([String]::IsNullOrEmpty($mimObject.($mimAttribute.Name)))
|
||||
{
|
||||
Write-Debug " Skipping attribute because there is no attribute value: $($mimAttribute.Name)"
|
||||
}
|
||||
else
|
||||
{
|
||||
$mimDscAttributeString = Convert-MimSvcReferenceToDscLookupString -ReferenceString $mimObject.($mimAttribute.Name)
|
||||
$mimDependsOnValues += Convert-MimSvcReferenceToMimObject -ReferenceString $mimObject.($mimAttribute.Name) -SkipDependsOnForSchema:$SkipDependsOnForSchema | Convert-MimSvcObjectToDscDependsOnString
|
||||
$mimReferenceValues += $mimObject.($mimAttribute.Name)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$tryParseResult = $false
|
||||
if ([boolean]::TryParse($mimObject.($mimAttribute.Name),[ref]$tryParseResult))
|
||||
{
|
||||
$mimDscAttributeString = '${0}' -F $tryParseResult
|
||||
}
|
||||
else
|
||||
{
|
||||
$mimDscAttributeString = "'$($mimObject.($mimAttribute.Name) -replace "'","''" -replace "’","''")'"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### Only output the property if there is a property value
|
||||
if ([String]::IsNullOrEmpty($mimObject.($mimAttribute.Name)))
|
||||
{
|
||||
Write-Debug " Skipping attribute because there is no attribute value: $($mimAttribute.Name)"
|
||||
}
|
||||
else
|
||||
{
|
||||
$mimDscString += "`t{0,-$columnWidth} = {1}`n" -F $mimAttribute.Name, $mimDscAttributeString
|
||||
}
|
||||
}
|
||||
|
||||
if ($mimDependsOnValues.Count -gt 0)
|
||||
{
|
||||
$mimDscString += "`t{0,-$columnWidth} = {1}`n" -F 'DependsOn', (($mimDependsOnValues | Select-Object -Unique) -join ',')
|
||||
}
|
||||
$mimDscString += "`t{0,-$columnWidth} = '{1}'`n" -F 'Ensure', 'Present'
|
||||
$mimDscString += "}`n"
|
||||
|
||||
Write-Output ([PSCustomObject]@{
|
||||
ObjectType = $mimObjectType
|
||||
ObjectIdentifier = $mimObject.ObjectID
|
||||
DscItemScript = $mimDscString
|
||||
})
|
||||
}
|
||||
end
|
||||
{
|
||||
$exportsToProcess = $mimReferenceValues | Convert-MimSvcReferenceToMimObject -SkipDependsOnForSchema:$SkipDependsOnForSchema | Sort-Object -Property ObjectID -Unique
|
||||
foreach($exportToProcess in $exportsToProcess)
|
||||
{
|
||||
if ($exportToProcess.ObjectID -notin $global:processedObjectIDs)
|
||||
{
|
||||
#Write-Host " DependsOn [$($exportToProcess.ObjectType)] $($exportToProcess.ObjectID)"
|
||||
Convert-MimSvcObjectToDscScript -MimObject $exportToProcess | Write-Output
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
function Convert-MimSvcReferenceToDscLookupString
|
||||
{
|
||||
param
|
||||
(
|
||||
<#
|
||||
A String the MIM ObjectID(s) to convert
|
||||
This is typically a single ID such as 'urn:uuid:1ef3d501-3c7b-42ad-8407-2c51cbb7a09b'
|
||||
or a more complex string containing multiple IDs, such as a XOML or Filter
|
||||
#>
|
||||
[parameter(Mandatory=$true, ValueFromPipeline = $true)]
|
||||
$ReferenceString
|
||||
)
|
||||
process
|
||||
{
|
||||
###
|
||||
### Value will either be a GUID or a STRING containing multiple GUIDS
|
||||
###
|
||||
if ($ReferenceString -match "^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}")
|
||||
{
|
||||
###
|
||||
### Get the MIM object
|
||||
###
|
||||
$mimObject = Get-Resource -ID $ReferenceString -AttributesToGet ObjectType, Name, TimeZoneId, AccountName, DisplayName
|
||||
|
||||
###
|
||||
### Return if the referenced object is not found
|
||||
###
|
||||
if (-not $mimObject)
|
||||
{
|
||||
Write-Warning "Could not find MIM object for this ObjectID: $ReferenceString"
|
||||
return
|
||||
}
|
||||
|
||||
###
|
||||
### Get the attribute that is unique for this object type
|
||||
###
|
||||
if ($mimObject.ObjectType -in 'ObjectTypeDescription','AttributeTypeDescription')
|
||||
{
|
||||
Write-Output "'$($mimObject.Name -replace "'", "''" -replace "’", "''" -replace "’", "''")'"
|
||||
}
|
||||
elseif($mimObject.ObjectType -eq 'TimeZoneConfiguration')
|
||||
{
|
||||
Write-Output "'$($mimObject.TimeZoneId -replace "'", "''" -replace "’", "''" -replace "’", "''")'"
|
||||
}
|
||||
elseif($mimObject.ObjectType -eq 'Person')
|
||||
{
|
||||
Write-Output "'$($mimObject.AccountName -replace "'", "''" -replace "’", "''" -replace "’", "''")'"
|
||||
}
|
||||
else
|
||||
{
|
||||
Write-Output "'$($mimObject.DisplayName -replace "'", "''" -replace "’", "''" -replace "’", "''")'"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$regex = [regex]"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
|
||||
if ($regex.IsMatch($ReferenceString))
|
||||
{
|
||||
foreach($regexMatch in $regex.Matches($ReferenceString))
|
||||
{
|
||||
$mimObject = Get-Resource -ID $regexMatch.Value -AttributesToGet ObjectType, Name, TimeZoneId, AccountName, DisplayName
|
||||
if ($mimObject)
|
||||
{
|
||||
###
|
||||
### Get the attribute that is unique for this object type
|
||||
###
|
||||
### TODO - do we really need the string replaces here?
|
||||
if ($mimObject.ObjectType -in 'ObjectTypeDescription','AttributeTypeDescription')
|
||||
{
|
||||
$mimAttributeName = 'Name'
|
||||
$mimAttributeValue = $mimObject.Name
|
||||
}
|
||||
elseif($mimObject.ObjectType -eq 'Person')
|
||||
{
|
||||
$mimAttributeName = 'AccountName'
|
||||
$mimAttributeValue = $mimObject.AccountName
|
||||
}
|
||||
else
|
||||
{
|
||||
$mimAttributeName = 'DisplayName'
|
||||
$mimAttributeValue = $mimObject.DisplayName
|
||||
}
|
||||
$jsonString = '{{ObjectType:"{0}",AttributeName:"{1}",AttributeValue:"{2}"}}' -F $mimObject.ObjectType, $mimAttributeName, $mimAttributeValue
|
||||
$ReferenceString = $ReferenceString -replace $regexMatch.Value, $jsonString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Only output if this string was created
|
||||
if ($ReferenceString)
|
||||
{
|
||||
$ReferenceString = $ReferenceString -replace "'","''" -replace "’","''" -replace "´","''"
|
||||
Write-Output "'$ReferenceString'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
function Convert-MimSvcReferenceToMimObject
|
||||
{
|
||||
param
|
||||
(
|
||||
<#
|
||||
A String the MIM ObjectID(s) to convert
|
||||
This is typically a single ID such as 'urn:uuid:1ef3d501-3c7b-42ad-8407-2c51cbb7a09b'
|
||||
or a more complex string containing multiple IDs, such as a XOML or Filter
|
||||
#>
|
||||
[parameter(Mandatory=$true, ValueFromPipeline = $true)]
|
||||
$ReferenceString,
|
||||
[Switch]$SkipDependsOnForSchema
|
||||
)
|
||||
process
|
||||
{
|
||||
###
|
||||
### Value will either be a GUID or a STRING containing multiple GUIDS
|
||||
###
|
||||
if ($ReferenceString -match "^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}")
|
||||
{
|
||||
###
|
||||
### Get the MIM object
|
||||
###
|
||||
if ($global:mimConfigHashTable)
|
||||
{
|
||||
$mimObject = $global:fimConfigHashTable[$ReferenceString]
|
||||
}
|
||||
else
|
||||
{
|
||||
$mimObjectType = Get-Resource -ID ($ReferenceString -replace 'urn:uuid:') -AttributesToGet ObjectType | Select -ExpandProperty ObjectType
|
||||
|
||||
$attributesToGet = Get-MimSvcSchemaCache -ObjectType $mimObjectType | Select -Expand Name | Where {$_ -notin @('ComputedMember','ExplicitMember','DetectedRulesList','ExpectedRulesList','MVObjectID','ExpirationTime')} | Where {$_ -notlike 'syncconfig-*'}
|
||||
|
||||
$mimObject = Get-Resource -ID ($ReferenceString -replace 'urn:uuid:') -AttributesToGet $attributesToGet
|
||||
}
|
||||
|
||||
###
|
||||
### Return if the referenced object is not found
|
||||
###
|
||||
if (-not $mimObject)
|
||||
{
|
||||
Write-Warning "Could not find MIM object for this ObjectID: $ReferenceString"
|
||||
return
|
||||
}
|
||||
|
||||
###
|
||||
### Skip if Person or Group object type to avoid (StrongConnect : DependsOn link exceeded max depth limitation '1024')
|
||||
###
|
||||
if ($mimObject.ObjectType -in 'Person','Group','Computer','ma-data','ForestConfiguration')
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
###
|
||||
### Skip if Schema
|
||||
###
|
||||
if ($SkipDependsOnForSchema -and $mimObject.ObjectType -in 'ObjectTypeDescription','AttributeTypeDescription','BindingDescription')
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
$mimObject | Write-Output
|
||||
}
|
||||
else
|
||||
{
|
||||
$dependsOnStrings = @()
|
||||
$regex = [regex]"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
|
||||
foreach($regexMatch in $regex.Matches($ReferenceString))
|
||||
{
|
||||
if ($regexMatch.Value -eq [Guid]::Empty)
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
if ($global:mimConfigHashTable)
|
||||
{
|
||||
$refObject = $global:mimConfigHashTable["urn:uuid:$($regexMatch.Value)"]
|
||||
}
|
||||
else
|
||||
{
|
||||
$refObjectType = Get-Resource -ID $regexMatch.Value -AttributesToGet ObjectType | Select -ExpandProperty ObjectType
|
||||
|
||||
$attributesToGet = Get-MimSvcSchemaCache -ObjectType $refObjectType | Select -Expand Name | Where {$_ -notin @('ComputedMember','ExplicitMember','DetectedRulesList','ExpectedRulesList','MVObjectID','ExpirationTime')} | Where {$_ -notlike 'syncconfig-*'}
|
||||
|
||||
$refObject = Get-Resource -ID $regexMatch.Value -AttributesToGet $attributesToGet
|
||||
}
|
||||
|
||||
###
|
||||
### Skip this loop iteration if the referenced object is not found
|
||||
###
|
||||
if (-not $refObject)
|
||||
{
|
||||
Write-Warning "Could not find MIM object for this ObjectID: $($regexMatch.Value)"
|
||||
continue
|
||||
}
|
||||
|
||||
###
|
||||
### Skip if Person or Group object type to avoid (StrongConnect : DependsOn link exceeded max depth limitation '1024')
|
||||
###
|
||||
if ($refObject.ObjectType -in 'Person','Group','Computer')
|
||||
{
|
||||
continue
|
||||
}
|
||||
|
||||
###
|
||||
### Skip if Schema
|
||||
###
|
||||
if ($SkipDependsOnForSchema -and $refObject.ObjectType -in 'ObjectTypeDescription','AttributeTypeDescription','BindingDescription')
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
$refObject | Write-Output
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -66,6 +66,11 @@ ScriptsToProcess = @(
|
|||
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
|
||||
FunctionsToExport = @(
|
||||
'Convert-MimSvcExportToPSObject'
|
||||
'Convert-MimSvcObjectToDscDependsOnString'
|
||||
'Convert-MimSvcObjectToDscItemName'
|
||||
'Convert-MimSvcObjectToDscScript'
|
||||
'Convert-MimSvcReferenceToDscLookupString'
|
||||
'Convert-MimSvcReferenceToMimObject'
|
||||
'Convert-MimSyncConfigToDsc'
|
||||
'Convert-MimSyncJoinCriterionToCimInstance'
|
||||
'Convert-MimSyncMVObjectTypeToCimInstance'
|
||||
|
|
Загрузка…
Ссылка в новой задаче