adds functions for generating DSC configuration from MIM Service objects

This commit is contained in:
craig-martin 2024-05-14 00:10:44 +00:00
Родитель b56ef645f2
Коммит 779e72d878
6 изменённых файлов: 495 добавлений и 0 удалений

Просмотреть файл

@ -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'