Microsoft365DSC/ResourceGenerator/M365DSCResourceGenerator.psm1

4094 строки
159 KiB
PowerShell

function New-M365DSCResource
{
param (
# Name for the new Resource
[Parameter()]
[System.String]
$ResourceName,
# Name of the Workload the resource is for.
[Parameter(Mandatory = $true)]
[ValidateSet('ExchangeOnline', 'Intune', `
'SecurityComplianceCenter', 'PnP', 'PowerPlatforms', `
'MicrosoftTeams', 'MicrosoftGraph')]
[System.String]
$Workload,
# CmdLet Noun
[Parameter()]
[System.String]
$CmdLetNoun,
# CmdLet Verb
[Parameter()]
[System.String]
$CmdLetVerb = 'New',
# Path to the new Resource
[Parameter()]
[System.String]
$Path = 'c:\temp\newresource',
# Path to the new Resource
[Parameter()]
[System.String]
$UnitTestPath = 'c:\temp\newresource',
# Path to the new Resource
[Parameter()]
[System.String]
$ExampleFilePath = 'c:\temp\newresource',
[Parameter()]
[ValidateSet('v1.0', 'beta')]
[System.String]
$APIVersion = 'v1.0',
[Parameter()]
[System.String[]]
$ParametersToSkip = @(),
[Parameter()]
[System.String]
$AdditionalPropertiesType,
[Parameter()]
[System.String]
$DateFormat = "o",
# SettingTemplates for DeviceManagementConfigurationPolicy
[Parameter(ParameterSetName = 'SettingsCatalog')]
[System.Array]
$SettingsCatalogSettingTemplates,
[Parameter(ParameterSetName = 'SettingsCatalog')]
[switch]
$SkipPlatformsAndTechnologies,
# Use this switch with caution.
# Navigation Properties could cause the DRG to enter an infinite loop
# Navigation Properties are the properties refered as Relationships in the Graph REST API documentation.
# Only include if it contains a property which is NOT read-only.
[Parameter()]
[System.Boolean]
$IncludeNavigationProperties = $false,
[Parameter()]
[System.Management.Automation.PSCredential]
$Credential
)
$null = New-M365DSCResourceFolder -ResourceName $ResourceName -Path $Path
$schemaFilePath = New-M365DSCSchemaFile -ResourceName $ResourceName -Path $Path -Workload $Workload
$moduleFilePath = New-M365DSCModuleFile -ResourceName $ResourceName -Path $Path -Workload $Workload
$settingsFilePath = New-M365DSCSettingsFile -ResourceName $ResourceName -Path $Path
$readmeFilePath = New-M365DSCReadmeFile -ResourceName $ResourceName -Path $Path
$unitTestPath = New-M365DSCUnitTest -ResourceName $ResourceName -Path $UnitTestPath
$graphWorkloads = @('MicrosoftGraph','Intune')
if ($Workload -in $graphWorkloads)
{
Write-Verbose "Import Intune Settings Catalog Helper module"
Import-Module ..\Modules\Microsoft365DSC\Modules\M365DSCIntuneSettingsCatalogUtil.psm1 -Force
$Global:CIMInstancesAlreadyFound = @()
$GetcmdletName = "Get-$CmdLetNoun"
$commandDetails = Find-MgGraphCommand -Command $GetcmdletName -ApiVersion $APIVersion -ErrorAction SilentlyContinue
$cmdletFound = Get-Command $GetcmdletName -ErrorAction SilentlyContinue
if (-not $commandDetails)
{
$APIVersion = 'beta'
$commandDetails = Find-MgGraphCommand -Command $GetcmdletName -ApiVersion $ApiVersion -ErrorAction SilentlyContinue
if (-not $commandDetails)
{
throw "Cmdlet {$GetcmdletName} was not found"
}
}
$cmdletFound = Get-Command $GetcmdletName -ErrorAction SilentlyContinue
$GraphModule = $cmdletFound.ModuleName
Import-Module $GraphModule -ErrorAction Stop
$commandDetails = Find-MgGraphCommand -Command $GetcmdletName -ApiVersion $ApiVersion
$cmdletCommandDetails = Get-Command -Name "$($CmdLetVerb)-$($CmdLetNoun)" -Module $GraphModule
$defaultParameterSet = $cmdletCommandDetails.ParameterSets | Where-Object -FilterScript { $_.IsDefault -eq $true }
$defaultParameterSetProperties = $defaultParameterSet.Parameters
$outputTypes = $commandDetails | Select-Object OutputType | Get-Unique
if ($outputTypes.GetType().BaseType.Name -eq 'Array')
{
$outputTypeInformationChoices = @()
for ($i = 0; $i -lt $typeInformation.Count; $i++)
{
$outputTypeInformationChoices += [System.Management.Automation.Host.ChoiceDescription]("$($commandDetails[$i].Name)")
}
$outputTypeChoice = $host.UI.PromptForChoice('Output Type Selection', 'Please select an output type', $outputTypeInformationChoices, 0) + 1
$outputType = $outputTypes[$outputTypeChoice - 1].OutputType
}
else
{
$outputType = $outputTypes.OutputType
}
if ($outputType.EndsWith(1))
{
$outputType = $outputType -replace '.$'
}
$actualType = $outputType.Replace('IMicrosoftGraph', '')
$cmdletDefinition = Get-CmdletDefinition -Entity $actualType `
-APIVersion $ApiVersion
#Check if the actual type returns multiple type of policies
$policyTypes = ($cmdletDefinition.EntityType | Where-Object -FilterScript { $_.basetype -like "*$actualType" }).Name
if ($null -ne $policyTypes -and $policyTypes.GetType().Name -like '*[[\]]')
{
if ([String]::IsNullOrEmpty($AdditionalPropertiesType))
{
$policyTypeChoices = @()
for ($i = 0; $i -lt $policyTypes.Count; $i++)
{
$policyTypeChoices += [System.Management.Automation.Host.ChoiceDescription]("$($policyTypes[$i])")
}
$typeChoice = $host.UI.PromptForChoice('Additional Type Information', 'Please select an additional type', $policyTypeChoices, 0) + 1
$selectedODataType = $policyTypes[$typeChoice - 1]
}
else
{
$selectedODataType = $policyTypes | Where-Object -FilterScript { $_ -eq $AdditionalPropertiesType }
if ([String]::IsNullOrEmpty($selectedODataType))
{
$selectedODataType = $AdditionalPropertiesType
}
}
$isAdditionalProperty = $true
}
else
{
$selectedODataType = $actualType
$isAdditionalProperty = $false
}
$addIntuneAssignments = $false
$AssignmentsParam = ''
$AssignmentsGet = ''
$AssignmentsRemove = ''
$AssignmentsNew = ''
$AssignmentsUpdate = ''
$AssignmentsFunctions = ''
$AssignmentsCIM = ''
$AssignmentsProperty = ''
$AssignmentsConvertComplexToString = ''
$AssignmentsConvertComplexToVariable = ''
$global:ComplexList = @()
$cimClasses = Get-Microsoft365DSCModuleCimClass -ResourceName $ResourceName
$global:searchedEntity = $selectedODataType
$typeProperties = Get-TypeProperties `
-CmdletDefinition $cmdletDefinition `
-Entity $selectedODataType `
-IncludeNavigationProperties $IncludeNavigationProperties `
-CimClasses $cimClasses `
-Workload $Workload
$typeProperties = $typeProperties | Where-Object -FilterScript {
$_.Name -notin @('createdDateTime', 'isAssigned', 'lastModifiedDateTime', 'priorityMetaData', 'retryCount', 'settingCount', 'templateReference', 'creationSource')
}
$global:ComplexList = $null
$global:searchedEntity = $null
[Hashtable[]]$parameterInformation = Get-ParameterBlockInformation `
-Properties $typeProperties `
-DefaultParameterSetProperties $defaultParameterSetProperties
#retrieve assignment details
if ($Workload -in @('Intune', 'MicrosoftGraph'))
{
$repository = ($commandDetails | Where-Object -FilterScript {$_.variants -eq 'List'}).URI
$repository = $repository.Substring(1, ($repository.Length - 1))
$assignmentCmdlet = Get-Command -Name ($cmdletFound.Name + 'Assignment') -Module $GraphModule -ErrorAction SilentlyContinue
$assignmentCmdletNoun = $assignmentCmdlet.Noun
$assignmentKey = (($assignmentCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'List' }).Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name
if (-not [String]::IsNullOrWhiteSpace($repository) `
-and -not [String]::IsNullOrWhiteSpace($assignmentCmdletNoun) `
-and -not [String]::IsNullOrWhiteSpace($assignmentKey))
{
$addIntuneAssignments = $true
$ParametersToSkip += 'Assignments'
}
if ($SkipPlatformsAndTechnologies)
{
$ParametersToSkip += 'Platforms'
$ParametersToSkip += 'Technologies'
}
}
$parameterInformation = $parameterInformation | Where-Object -FilterScript {$_.Name -notin $ParametersToSkip}
$script:DiscoveredComplexTypes = @()
[Array]$CimInstances = $parameterInformation | Where-Object -FilterScript { $_.IsComplexType }
$script:DiscoveredComplexTypes = $null
$Global:AlreadyFoundInstances = @()
$CimInstancesSchemaContent = ''
if ($null -ne $CimInstances)
{
foreach ($CimInstance in $CimInstances)
{
$CimInstancesSchemaContent += Get-M365DSCDRGCimInstancesSchemaStringContent `
-CIMInstance $CimInstance `
-Workload $Workload
}
}
$Global:AlreadyFoundInstances = $null
$parameterString = Get-ParameterBlockStringForModule -ParameterBlockInformation $parameterInformation
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
if ($SettingsCatalogSettingTemplates.Count -eq 0)
{
throw "SettingsCatalogSettingTemplates is required for DeviceManagementConfigurationPolicy resources"
}
$templateSettings = @()
$deviceSettingsCatalogTemplates = $SettingsCatalogSettingTemplates | Where-Object -FilterScript { $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("device_") }
$deviceSettingDefinitions = $deviceSettingsCatalogTemplates.SettingDefinitions
$userSettingsCatalogTemplates = $SettingsCatalogSettingTemplates | Where-Object -FilterScript { $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("user_") }
$userSettingDefinitions = $userSettingsCatalogTemplates.SettingDefinitions
$defaultSettingsCatalogTemplates = $SettingsCatalogSettingTemplates | Where-Object -FilterScript {
-not $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("device_") -and
-not $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("user_")
}
$defaultSettingDefinitions = $defaultSettingsCatalogTemplates.SettingDefinitions
$containsDeviceAndUserSettings = $false
if ($deviceSettingDefinitions.Count -gt 0 -and $userSettingDefinitions.Count -gt 0)
{
$containsDeviceAndUserSettings = $true
}
$deviceTemplateSettings = @()
foreach ($deviceSettingTemplate in $deviceSettingsCatalogTemplates)
{
$deviceTemplateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate `
-FromRoot `
-SettingTemplate $deviceSettingTemplate `
-AllSettingDefinitions $deviceSettingDefinitions
}
$userTemplateSettings = @()
foreach ($userSettingTemplate in $userSettingsCatalogTemplates)
{
$userTemplateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate `
-FromRoot `
-SettingTemplate $userSettingTemplate `
-AllSettingDefinitions $userSettingDefinitions
}
$defaultTemplateSettings = @()
foreach ($defaultSettingTemplate in $defaultSettingsCatalogTemplates)
{
$defaultTemplateSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate `
-FromRoot `
-SettingTemplate $defaultSettingTemplate `
-AllSettingDefinitions $defaultSettingDefinitions
}
$deviceDefinitionSettings = @()
foreach ($deviceTemplateSetting in $deviceTemplateSettings)
{
foreach ($deviceChildSetting in $deviceTemplateSetting.ChildSettings)
{
$deviceChildSetting.DisplayName += " - Depends on $($deviceTemplateSetting.Name)"
}
$deviceDefinitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting `
-TemplateSetting $deviceTemplateSetting
}
$userDefinitionSettings = @()
foreach ($userTemplateSetting in $userTemplateSettings)
{
foreach ($userChildSetting in $userTemplateSetting.ChildSettings)
{
$userChildSetting.DisplayName += " - Depends on $($userTemplateSetting.Name)"
}
$userDefinitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting `
-TemplateSetting $userTemplateSetting
}
$defaultDefinitionSettings = @()
foreach ($defaultTemplateSetting in $defaultTemplateSettings)
{
foreach ($defaultChildSetting in $defaultTemplateSetting.ChildSettings)
{
$defaultChildSetting.DisplayName += " - Depends on $($defaultTemplateSetting.Name)"
}
$defaultDefinitionSettings += New-ParameterDefinitionFromSettingsCatalogTemplateSetting `
-TemplateSetting $defaultTemplateSetting
}
Write-Verbose -Message "* Check the description for the parameters. CIM types might include a 'Depends on' information, although it is not required."
if ($containsDeviceAndUserSettings)
{
$definitionSettings = @{
PowerShell = @(
@"
[Parameter()]
[Microsoft.Management.Infrastructure.CimInstance]
`$DeviceSettings
"@,
@"
[Parameter()]
[Microsoft.Management.Infrastructure.CimInstance]
`$UserSettings
"@
)
MOFInstance = @(
@"
[ClassVersion("1.0.0.0")]
class MSFT_MicrosoftGraphIntuneSettingsCatalogDeviceSettings_$($ResourceName)
{
$($deviceDefinitionSettings.MOF -join "`r`n")
};
"@,
@"
[ClassVersion("1.0.0.0")]
class MSFT_MicrosoftGraphIntuneSettingsCatalogUserSettings_$($ResourceName)
{
$($userDefinitionSettings.MOF -join "`r`n")
};
"@
)
}
$definitionSettings.MOFInstance = ($deviceDefinitionSettings.MOFInstance -join "`r`n") + "`r`n" + ($definitionSettings.MOFInstance -join "`r`n")
$definitionSettings.MOFInstance = ($userDefinitionSettings.MOFInstance -join "`r`n") + "`r`n" + ($definitionSettings.MOFInstance -join "`r`n")
$definitionSettings.MOFInstance = ($defaultDefinitionSettings.MOFInstance -join "`r`n") + "`r`n" + ($definitionSettings.MOFInstance -join "`r`n")
}
else
{
$definitionSettings = $deviceDefinitionSettings + $userDefinitionSettings + $defaultDefinitionSettings
}
$parameterString += $definitionSettings.PowerShell -join ",`r`n`r`n"
$parameterString += ",`r`n`r`n"
$complexParameters = @($definitionSettings.PowerShell | Where-Object -FilterScript { $_ -like "*CimInstance*" })
foreach ($parameter in $complexParameters)
{
$parameter -match '\$.*$'
$parameterName = $Matches[0].Replace('$', '')
$parameterType = 'IntuneSettingsCatalog' + $parameterName + $(if ($parameterName -in @('DeviceSettings', 'UserSettings')) { "_$ResourceName" })
$cimInstance = $definitionSettings.MOFInstance | Where-Object -FilterScript { $_ -like "*$parameterType`n*" -or $_ -like "*$parameterType`r`n*" }
$rowFilter = '\[.*;'
$cimRows = [regex]::Matches($cimInstance, $rowFilter) | Foreach-Object {
$_.Value
}
$cimPropertyNamequery = '[a-zA-Z0-9_]+[\[\]]*;'
$cimProperties = @()
foreach ($row in $cimRows)
{
$cimProperties += [regex]::Matches($row, $cimPropertyNamequery) | Foreach-Object {
$props = @{
Name = $_.Value.Replace('[', '').Replace(']', '').Replace(';', '')
IsArray = $_.Value.Contains('[]')
IsComplexType = $row.Contains('EmbeddedInstance')
}
if ($props.IsComplexType)
{
Write-Warning -Message "Attention: No automatic complex type conversion is available for the property $($props.Name) in $parameterName. Please implement the conversion manually."
$props.Type = $row.Split(' ')[2].Replace('EmbeddedInstance("', '').Replace('")]', '')
}
$props
}
}
$parameterInformation += @{
Name = $parameterName
IsComplexType = $true
IsMandatory = $false
IsArray = $parameter -match '\[.*\[\]\]'
Type = $parameterType
Properties = $cimProperties
}
Write-Warning -Message "* Do not forget to replace the value `$getValue.$parameterName with `$policySettings.$parameterName in Get-TargetResource, remove it using `$policySettings.Remove('$parameterName')` and update the description in the MOF template. "
Write-Warning -Message "* Make sure to remove the duplicate entry of '$parameterName' in the MOF template."
Write-Warning -Message "* Check all CimInstanceNames in the `$complexTypeMapping in Export-TargetResource because they are not generated correctly."
}
Write-Warning -Message "* Update all occurences of 'Name' from parameters to 'DisplayName', since security and settings catalog policies use 'Name' internally, but the DSC resource uses 'DisplayName' for clarity."
Write-Warning -Message "* Replace the technology, platform and template reference placeholders with the actual values."
}
$hashtableResults = New-M365HashTableMapping -Properties $parameterInformation `
-DefaultParameterSetProperties $defaultParameterSetProperties `
-GraphNoun $CmdLetNoun `
-Workload $Workload `
-DateFormat $DateFormat
$hashTableMapping = $hashtableResults.StringContent
#region UnitTests
$fakeValues = Get-M365DSCFakeValues `
-ParametersInformation $parameterInformation `
-IntroduceDrift $false `
-Workload $Workload `
-AdditionalPropertiesType $selectedODataType `
-DateFormat $DateFormat
$targetResourceFakeValues = Get-M365DSCFakeValues `
-ParametersInformation $parameterInformation `
-IntroduceDrift $false `
-Workload $Workload `
-IsGetTargetResource $true `
-DateFormat $DateFormat
$fakeValuesString = Get-M365DSCHashAsString -Values $fakeValues
$targetResourceFakeValuesString = Get-M365DSCHashAsString -Values $targetResourceFakeValues -Space ' '
$assignmentMock = ''
if ($addIntuneAssignments)
{
$assignmentMock = "`r`n`r`n Mock -CommandName Get-$assignmentCmdletNoun -MockWith {`r`n"
$assignmentMock += " }`r`n"
}
Write-TokenReplacement -Token '<AssignmentMock>' -Value $assignmentMock -FilePath $unitTestPath
Write-TokenReplacement -Token '<FakeValues>' -Value $fakeValuesString -FilePath $unitTestPath
Write-TokenReplacement -Token '<TargetResourceFakeValues>' -Value $targetResourceFakeValuesString -FilePath $unitTestPath
$fakeValues2 = $fakeValues
$fakeValuesString2 = Get-M365DSCHashAsString -Values $fakeValues2 -isCmdletCall $true
Write-TokenReplacement -Token '<FakeValues2>' -Value $fakeValuesString2 -FilePath $unitTestPath
$fakeDriftValues = Get-M365DSCFakeValues -ParametersInformation $parameterInformation `
-IntroduceDrift $true `
-isCmdletCall $true `
-AdditionalPropertiesType $AdditionalPropertiesType `
-Workload $Workload `
-DateFormat $DateFormat
$fakeDriftValuesString = Get-M365DSCHashAsString -Values $fakeDriftValues -isCmdletCall $true
Write-TokenReplacement -Token '<DriftValues>' -Value $fakeDriftValuesString -FilePath $unitTestPath
Write-TokenReplacement -Token '<ResourceName>' -Value $ResourceName -FilePath $unitTestPath
Write-TokenReplacement -Token '<GetCmdletName>' -Value $GetcmdletName -FilePath $unitTestPath
$updateVerb = 'Update'
$updateCmdlet = Find-MgGraphCommand -Command "$updateVerb-$CmdLetNoun" -ApiVersion $ApiVersion -ErrorAction SilentlyContinue
if ($null -eq $updateCmdlet)
{
$updateVerb = 'Set'
}
Write-TokenReplacement -Token '<SetCmdletName>' -value "$updateVerb-$($CmdLetNoun)" -FilePath $unitTestPath
Write-TokenReplacement -Token '<RemoveCmdletName>' -value "Remove-$($CmdLetNoun)" -FilePath $unitTestPath
Write-TokenReplacement -Token '<NewCmdletName>' -value "New-$($CmdLetNoun)" -FilePath $unitTestPath
Update-Microsoft365StubFile -CmdletNoun $CmdLetNoun
if ($addIntuneAssignments)
{
Update-Microsoft365StubFile -CmdletNoun $assignmentCmdletNoun
}
#endregion
#region Module
$platforms = @{
'Windows10' = 'for Windows10'
'Windows11' = 'for Windows11'
'Android' = 'for Android'
'Mac O S' = 'for macOS'
'I O S' = 'for iOS'
'A A D' = 'Azure AD'
'Linux' = 'for Linux'
}
$resourceDescription = ($ResourceName -split '_')[0] -creplace '(?<=\w)([A-Z])', ' $1'
foreach ($platform in $platforms.keys)
{
if ($resourceDescription -like "*$platform*")
{
$resourceDescription = $resourceDescription.Replace($platform, $platforms.$platform)
}
$resourceDescription = $resourceDescription.Replace('Azure A D','Azure AD')
}
$getCmdlet = Get-Command -Name "Get-$($CmdLetNoun)" -Module $GraphModule
$getDefaultParameterSet = $getCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Get' }
$getKeyIdentifier = ($getDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name
if ([String]::IsNullOrEmpty($getKeyIdentifier))
{
$getDefaultParameterSet = $getCmdlet.ParameterSets | Where-Object -FilterScript { $_.IsDefault }
$getKeyIdentifier = ($getDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name
}
$primaryKey = ''
$alternativeKey = ''
if ($typeProperties.Name -contains 'id')
{
$primaryKey = 'Id'
$alternativeKey = 'DisplayName'
if ($typeProperties.Name -contains 'name')
{
$alternativeKey = 'Name'
}
}
if ($null -ne $getKeyIdentifier)
{
$getParameterString = [System.Text.StringBuilder]::New()
foreach ($key in $getKeyIdentifier)
{
if ($getKeyIdentifier.Count -gt 1)
{
$getParameterString.Append("```r`n") | Out-Null
$getParameterString.Append(" ") | Out-Null
}
$keyValue = $key
if ($key -eq "$($actualtype)Id")
{
$keyValue = $primaryKey
}
$getParameterString.Append("-$key `$$keyValue ") | Out-Null
}
[String]$getKeyIdentifier = $getParameterString.ToString()
}
$getDefaultParameterSet = $getCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'List' }
$getListIdentifier = $getDefaultParameterSet.Parameters.Name
$getAlternativeFilterString = [System.Text.StringBuilder]::New()
if ($getListIdentifier -contains 'Filter')
{
$getAlternativeFilterString.AppendLine(" -Filter `"$alternativeKey eq '`$$alternativeKey'`" ``") | Out-Null
$getAlternativeFilterString.AppendLine(" -ErrorAction SilentlyContinue | Where-Object ``") | Out-Null
$getAlternativeFilterString.AppendLine(" -FilterScript {") | Out-Null
$getAlternativeFilterString.AppendLine(" `$_.AdditionalProperties.'@odata.type' -eq `"`#microsoft.graph.$SelectedODataType`"") | Out-Null
$getAlternativeFilterString.Append(" }") | Out-Null
}
else
{
$getAlternativeFilterString.AppendLine(" -ErrorAction SilentlyContinue | Where-Object ``") | Out-Null
$getAlternativeFilterString.AppendLine(" -FilterScript {") | Out-Null
$getAlternativeFilterString.AppendLine(" `$_.$alternativeKey -eq `"`$(`$$alternativeKey)`" ``") | Out-Null
$getAlternativeFilterString.AppendLine(" -and `$_.AdditionalProperties.'@odata.type' -eq `"`#microsoft.graph.$SelectedODataType`"") | Out-Null
$getAlternativeFilterString.Append(" }") | Out-Null
}
Write-TokenReplacement -Token '<AlternativeFilter>' -Value $getAlternativeFilterString.ToString() -FilePath $moduleFilePath
Write-TokenReplacement -Token '<ParameterBlock>' -Value $parameterString -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#Workload#>' -Value $Workload -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#APIVersion#>' -Value $ApiVersion -FilePath $moduleFilePath
Write-TokenReplacement -Token '<PrimaryKey>' -Value $primaryKey -FilePath $moduleFilePath
Write-TokenReplacement -Token '<getKeyIdentifier>' -Value $getKeyIdentifier -FilePath $moduleFilePath
Write-TokenReplacement -Token '<GetCmdLetName>' -Value "Get-$($CmdLetNoun)" -FilePath $moduleFilePath
$settingsCatalogGetSettings = ""
$settingsCatalogAddSettings = ""
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
$settingsCatalogGetSettings = @"
`r`n # Retrieve policy specific settings
[array]`$settings = Get-$($CmdLetNoun)Setting ``
-DeviceManagementConfigurationPolicyId `$Id ``
-ExpandProperty 'settingDefinitions' ``
-All ``
-ErrorAction Stop
`$policySettings = @{}
`$policySettings = Export-IntuneSettingCatalogPolicySettings -Settings `$settings -ReturnHashtable `$policySettings$(if ($containsDeviceAndUserSettings) { ' -ContainsDeviceAndUserSettings' })`r`n
"@
$settingsCatalogAddSettings = " `$results += `$policySettings`r`n`r`n"
}
Write-TokenReplacement -Token '<SettingsCatalogGetSettings>' -Value $settingsCatalogGetSettings -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#SettingsCatalogAddSettings#>' -Value $settingsCatalogAddSettings -FilePath $moduleFilePath
$complexTypeConstructor = ""
if (-not [String]::IsNullOrEmpty($hashtableResults.ComplexTypeConstructor))
{
$complexTypeConstructor = $hashtableResults.ComplexTypeConstructor
$complexTypeConstructor = "`r`n #region resource generator code`r`n" + $complexTypeConstructor
$complexTypeConstructor = $complexTypeConstructor.Substring(0, $complexTypeConstructor.Length -2)
$complexTypeConstructor = $complexTypeConstructor + " #endregion`r`n"
}
Write-TokenReplacement -Token '<ComplexTypeConstructor>' -Value $complexTypeConstructor -FilePath $moduleFilePath
$enumTypeConstructor = ""
if (-not [String]::IsNullOrEmpty($hashtableResults.EnumTypeConstructor))
{
$enumTypeConstructor = $hashtableResults.EnumTypeConstructor
$enumTypeConstructor = "`r`n #region resource generator code`r`n" + $enumTypeConstructor
$enumTypeConstructor = $enumTypeConstructor.Substring(0, $enumTypeConstructor.Length -2)
$enumTypeConstructor = $enumTypeConstructor + " #endregion`r`n"
}
Write-TokenReplacement -Token '<EnumTypeConstructor>' -Value $enumTypeConstructor -FilePath $moduleFilePath
$dateTypeConstructor = ""
if (-not [String]::IsNullOrEmpty($hashtableResults.DateTypeConstructor))
{
$dateTypeConstructor = $hashtableResults.DateTypeConstructor
$dateTypeConstructor = "`r`n #region resource generator code`r`n" + $dateTypeConstructor
$dateTypeConstructor = $dateTypeConstructor.Substring(0, $dateTypeConstructor.Length -2)
$dateTypeConstructor = $dateTypeConstructor + " #endregion`r`n"
}
Write-TokenReplacement -Token '<DateTypeConstructor>' -Value $dateTypeConstructor -FilePath $moduleFilePath
$timeTypeConstructor = ""
if (-not [String]::IsNullOrEmpty($hashtableResults.TimeTypeConstructor))
{
$timeTypeConstructor = $hashtableResults.TimeTypeConstructor
$timeTypeConstructor = "`r`n #region resource generator code`r`n" + $timeTypeConstructor
$timeTypeConstructor = $timeTypeConstructor.Substring(0, $timeTypeConstructor.Length -2)
$timeTypeConstructor = $timeTypeConstructor + " #endregion`r`n"
}
Write-TokenReplacement -Token '<TimeTypeConstructor>' -Value $timeTypeConstructor -FilePath $moduleFilePath
$newCmdlet = Get-Command -Name "New-$($CmdLetNoun)"
$newDefaultParameterSet = $newCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Create' }
[Array]$newKeyIdentifier = ($newDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name
$defaultCreateParameters = @"
`$createParameters = ([Hashtable]`$BoundParameters).Clone()
`$createParameters = Rename-M365DSCCimInstanceParameter -Properties `$createParameters
`$createParameters.Remove('Id') | Out-Null
`$keys = (([Hashtable]`$createParameters).Clone()).Keys
foreach (`$key in `$keys)
{
if (`$null -ne `$createParameters.`$key -and `$createParameters.`$key.GetType().Name -like '*CimInstance*')
{
`$createParameters.`$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject `$createParameters.`$key
}
}
"@
$defaultUpdateParameters = @"
`$updateParameters = ([Hashtable]`$BoundParameters).Clone()
`$updateParameters = Rename-M365DSCCimInstanceParameter -Properties `$updateParameters
`$updateParameters.Remove('Id') | Out-Null
`$keys = (([Hashtable]`$updateParameters).Clone()).Keys
foreach (`$key in `$keys)
{
if (`$null -ne `$pdateParameters.`$key -and `$updateParameters.`$key.GetType().Name -like '*CimInstance*')
{
`$updateParameters.`$key = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject `$updateParameters.$key
}
}
"@
if ($null -ne $newKeyIdentifier)
{
$newParameterString = [System.Text.StringBuilder]::New()
foreach ($key in $newKeyIdentifier)
{
if ($newKeyIdentifier.Count -gt 1)
{
$newParameterString.Append(" ```r`n") | Out-Null
$newParameterString.Append(" ") | Out-Null
}
$keyValue = $key
if ($key -eq 'BodyParameter')
{
$keyValue = 'createParameters'
}
$newParameterString.Append("-$key `$$keyValue") | Out-Null
}
[String]$newKeyIdentifier = $newParameterString.ToString()
}
$odataType = $null
if ($true)#$isAdditionalProperty)
{
$odataType = " `$createParameters.Add(`"@odata.type`", `"#microsoft.graph.$SelectedODataType`")`r`n"
}
$settingsCatalogProperties = ""
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
$odataType = ""
$settingsCatalogProperties = @"
`$templateReferenceId = '<TemplateReferenceId>'
`$platforms = '<Platforms>'
`$technologies = '<Technologies>'`r`n
"@
$defaultCreateParameters = @"
`$settings = Get-IntuneSettingCatalogPolicySetting ``
-DSCParams ([System.Collections.Hashtable]`$BoundParameters) ``
-TemplateId `$templateReferenceId$(if ($containsDeviceAndUserSettings) { " ```r`n -ContainsDeviceAndUserSettings" })
`$createParameters = @{
Name = `$DisplayName
Description = `$Description
TemplateReference = @{ templateId = `$templateReferenceId }
Platforms = `$platforms
Technologies = `$technologies
Settings = `$settings
}`r`n
"@
}
Write-TokenReplacement -Token '<#SettingsCatalogProperties#>' -Value $settingsCatalogProperties -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#DefaultCreateParameters#>' -Value $defaultCreateParameters -FilePath $moduleFilePath
Write-TokenReplacement -Token '<NewDataType>' -Value "$odataType" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#NewKeyIdentifier#>' -Value $newKeyIdentifier -FilePath $moduleFilePath
Write-TokenReplacement -Token '<NewCmdLetName>' -Value "New-$($CmdLetNoun)" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<SetCmdLetName>' -Value "Set-$($CmdLetNoun)" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<RemoveCmdLetName>' -Value "Remove-$($CmdLetNoun)" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<ResourceDescription>' -Value $resourceDescription -FilePath $moduleFilePath
Write-TokenReplacement -Token '<FilterKey>' -Value $alternativeKey -FilePath $moduleFilePath
$exportGetCommand = [System.Text.StringBuilder]::New()
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
$exportGetCommand.AppendLine(" `$policyTemplateID = `"<TemplateId>`"") | Out-Null
}
$exportGetCommand.AppendLine(" [array]`$getValue = Get-$CmdLetNoun ``") | Out-Null
if ($getDefaultParameterSet.Parameters.Name -contains "Filter")
{
$exportGetCommand.AppendLine(" -Filter `$Filter ``") | Out-Null
}
if ($getDefaultParameterSet.Parameters.Name -contains "All")
{
$exportGetCommand.AppendLine(" -All ``") | Out-Null
}
if ($isAdditionalProperty -and $CmdletNoun -notlike "*DeviceManagementConfigurationPolicy")
{
$exportGetCommand.AppendLine(" -ErrorAction Stop | Where-Object ``") | Out-Null
$exportGetCommand.AppendLine(" -FilterScript {") | Out-Null
$exportGetCommand.AppendLine(" `$_.AdditionalProperties.'@odata.type' -eq '#microsoft.graph.$($selectedODataType)'") | Out-Null
$exportGetCommand.AppendLine(" }") | Out-Null
}
elseif ($CmdletNoun -like "*DeviceManagementConfigurationPolicy")
{
$exportGetCommand.AppendLine(" -ErrorAction Stop | Where-Object ``") | Out-Null
$exportGetCommand.AppendLine(" -FilterScript {") | Out-Null
$exportGetCommand.AppendLine(" `$_.TemplateReference.TemplateId -eq `$policyTemplateID") | Out-Null
$exportGetCommand.AppendLine(" }") | Out-Null
}
else
{
$exportGetCommand.AppendLine(" -ErrorAction Stop") | Out-Null
}
$trailingCharRemoval = ""
if ($cimInstances.Count -gt 0)
{
$trailingCharRemoval = @'
'@
}
$requiredKey = ''
if (-not [String]::IsNullOrEmpty($alternativeKey))
{
$requiredKey = "`r`n DisplayName = `$config.DisplayName"
}
Write-TokenReplacement -Token '<exportGetCommand>' -Value $exportGetCommand.ToString() -FilePath $moduleFilePath
Write-TokenReplacement -Token '<RequiredKey>' -Value $requiredKey -FilePath $moduleFilePath
Write-TokenReplacement -Token '<HashTableMapping>' -Value $hashTableMapping -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#ComplexTypeContent#>' -Value $hashtableResults.ComplexTypeContent -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#ConvertComplexToString#>' -Value $hashtableResults.ConvertToString -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#ConvertComplexToVariable#>' -Value $hashtableResults.ConvertToVariable -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#TrailingCharRemoval#>' -Value $trailingCharRemoval -FilePath $moduleFilePath
$updateVerb = 'Update'
$updateCmdlet = Find-MgGraphCommand -Command "$updateVerb-$CmdLetNoun" -ApiVersion $ApiVersion -ErrorAction SilentlyContinue
if ($null -eq $updateCmdlet)
{
$updateVerb = 'Set'
}
$updateCmdlet = Get-Command -Name "$updateVerb-$CmdLetNoun"
$updateDefaultParameterSet = $updateCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq "$updateVerb" }
[Array]$updateKeyIdentifier = ($updateDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name
if ($null -ne $updateKeyIdentifier)
{
$updateParameterString = [System.Text.StringBuilder]::New()
foreach ($key in $updateKeyIdentifier)
{
if ($updateKeyIdentifier.Count -gt 1)
{
$updateParameterString.Append(" ```r`n") | Out-Null
$updateParameterString.Append(" ") | Out-Null
}
$keyValue = $key
if ($key -eq 'BodyParameter')
{
$keyValue = 'UpdateParameters'
}
if ($key -eq "$($actualtype)Id")
{
$keyValue = 'currentInstance.' + $primaryKey
}
$updateParameterString.Append("-$key `$$keyValue") | Out-Null
}
[String]$updateKeyIdentifier = $updateParameterString.ToString()
}
$odataType = $null
if ($true)#$isAdditionalProperty)
{
$odataType = " `$UpdateParameters.Add(`"@odata.type`", `"#microsoft.graph.$SelectedODataType`")`r`n"
}
$updateCmdletName = " $updateVerb-$CmdLetNoun"
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
$odataType = ""
$updateKeyIdentifier = ""
$updateCmdletName = ""
$defaultUpdateParameters = @"
`$settings = Get-IntuneSettingCatalogPolicySetting ``
-DSCParams ([System.Collections.Hashtable]`$BoundParameters) ``
-TemplateId `$templateReferenceId$(if ($containsDeviceAndUserSettings) { " ```r`n -ContainsDeviceAndUserSettings" })
Update-IntuneDeviceConfigurationPolicy ``
-DeviceConfigurationPolicyId `$currentInstance.Id ``
-Name `$DisplayName ``
-Description `$Description ``
-TemplateReferenceId `$templateReferenceId ``
-Platforms `$platforms ``
-Technologies `$technologies ``
-Settings `$settings`r`n
"@
}
Write-TokenReplacement -Token '<#DefaultUpdateParameters#>' -Value $defaultUpdateParameters -FilePath $moduleFilePath
Write-TokenReplacement -Token '<UpdateDataType>' -Value "$odataType" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<UpdateCmdLetName>' -Value $updateCmdletName -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#UpdateKeyIdentifier#>' -Value $updateKeyIdentifier -FilePath $moduleFilePath
$removeCmdlet = Get-Command -Name "Remove-$($CmdLetNoun)"
$removeDefaultParameterSet = $removeCmdlet.ParameterSets | Where-Object -FilterScript { $_.Name -eq 'Delete' }
[Array]$removeKeyIdentifier = ($removeDefaultParameterSet.Parameters | Where-Object -FilterScript { $_.IsMandatory }).Name
if ($null -ne $removeKeyIdentifier)
{
$removeParameterString = [System.Text.StringBuilder]::New()
foreach ($key in $removeKeyIdentifier)
{
if ($removeKeyIdentifier.Count -gt 1)
{
$removeParameterString.Append(" ```r`n") | Out-Null
$removeParameterString.Append(" ") | Out-Null
}
$keyValue = $key
if ($removeKeyIdentifier.Count -eq 1)
{
$keyValue = 'currentInstance.' + $primaryKey
}
$removeParameterString.Append("-$key `$$keyValue") | Out-Null
}
[String]$removeKeyIdentifier = $removeParameterString.ToString()
}
Write-TokenReplacement -Token '<#removeKeyIdentifier#>' -Value $removeKeyIdentifier -FilePath $moduleFilePath
#Intune Assignments
if ($addIntuneAssignments -and -not [String]::IsNullOrEmpty($repository))
{
$AssignmentsParam += " [Parameter()]`r`n"
$AssignmentsParam += " [Microsoft.Management.Infrastructure.CimInstance[]]`r`n"
$AssignmentsParam += " `$Assignments,`r`n"
$AssignmentsGet += " `$assignmentsValues = Get-$($assignmentCmdLetNoun) -$($assignmentKey) `$$primaryKey`r`n"
$AssignmentsGet += " `$assignmentResult = @()`r`n"
$AssignmentsGet += " if (`$assignmentsValues.Count -gt 0)`r`n"
$AssignmentsGet += " {`r`n"
$AssignmentsGet += " `$assignmentResult += ConvertFrom-IntunePolicyAssignment -Assignments `$assignmentsValues -IncludeDeviceFilter `$true`r`n"
$AssignmentsGet += " }`r`n"
$AssignmentsGet += " `$results.Add('Assignments', `$assignmentResult)`r`n"
$AssignmentsRemove += " `$BoundParameters.Remove(`"Assignments`") | Out-Null`r`n"
$AssignmentsNew += ""
$AssignmentsNew += "`r`n"
$AssignmentsNew += " if (`$policy.Id)`r`n"
$AssignmentsNew += " {`r`n"
$AssignmentsNew += " `$assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:`$true -Assignments `$Assignments`r`n"
$AssignmentsNew += " Update-DeviceConfigurationPolicyAssignment ```r`n"
$AssignmentsNew += " -DeviceConfigurationPolicyId `$policy.Id ```r`n"
$AssignmentsNew += " -Targets `$assignmentsHash ```r`n"
$AssignmentsNew += " -Repository '$repository'`r`n"
$AssignmentsNew += " }`r`n"
$AssignmentsUpdate += " `$assignmentsHash = ConvertTo-IntunePolicyAssignment -IncludeDeviceFilter:`$true -Assignments `$Assignments`r`n"
$AssignmentsUpdate += " Update-DeviceConfigurationPolicyAssignment ```r`n"
$AssignmentsUpdate += " -DeviceConfigurationPolicyId `$currentInstance.Id ```r`n"
$AssignmentsUpdate += " -Targets `$assignmentsHash ```r`n"
$AssignmentsUpdate += " -Repository '$repository'"
$AssignmentsCIM = @'
[ClassVersion("1.0.0.0")]
class MSFT_DeviceManagementConfigurationPolicyAssignments
{
[Write, Description("The type of the target assignment."), ValueMap{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}, Values{"#microsoft.graph.groupAssignmentTarget","#microsoft.graph.allLicensedUsersAssignmentTarget","#microsoft.graph.allDevicesAssignmentTarget","#microsoft.graph.exclusionGroupAssignmentTarget","#microsoft.graph.configurationManagerCollectionAssignmentTarget"}] String dataType;
[Write, Description("The type of filter of the target assignment i.e. Exclude or Include. Possible values are:none, include, exclude."), ValueMap{"none","include","exclude"}, Values{"none","include","exclude"}] String deviceAndAppManagementAssignmentFilterType;
[Write, Description("The Id of the filter for the target assignment.")] String deviceAndAppManagementAssignmentFilterId;
[Write, Description("The group Id that is the target of the assignment.")] String groupId;
[Write, Description("The group Display Name that is the target of the assignment.")] String groupDisplayName;
[Write, Description("The collection Id that is the target of the assignment.(ConfigMgr)")] String collectionId;
};
'@
$AssignmentsProperty = "`r`n [Write, Description(`"Represents the assignment to the Intune policy.`"), EmbeddedInstance(`"MSFT_DeviceManagementConfigurationPolicyAssignments`")] String Assignments[];`r`n"
$AssignmentsConvertComplexToString = @"
`r`n if (`$Results.Assignments)
{
`$complexTypeStringResult = Get-M365DSCDRGComplexTypeToString -ComplexObject `$Results.Assignments -CIMInstanceName DeviceManagementConfigurationPolicyAssignments
if (`$complexTypeStringResult)
{
`$Results.Assignments = `$complexTypeStringResult
}
else
{
`$Results.Remove('Assignments') | Out-Null
}
}`r`n
"@
$AssignmentsConvertComplexToVariable = @"
`r`n if (`$Results.Assignments)
{
`$currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock `$currentDSCBlock -ParameterName "Assignments" -IsCIMArray:`$true
}`r`n
"@
}
Write-TokenReplacement -Token '<AssignmentsParam>' -Value $AssignmentsParam -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsGet#>' -Value $AssignmentsGet -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsRemove#>' -Value $AssignmentsRemove -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsNew#>' -Value $AssignmentsNew -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsUpdate#>' -Value $AssignmentsUpdate -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsFunctions#>' -Value $AssignmentsFunctions -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsConvertComplexToString#>' -Value $AssignmentsConvertComplexToString -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#AssignmentsConvertComplexToVariable#>' -Value $AssignmentsConvertComplexToVariable -FilePath $moduleFilePath
$defaultTestValuesToCheck = " `$ValuesToCheck = ([Hashtable]`$PSBoundParameters).clone()"
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
$defaultTestValuesToCheck = @"
[Hashtable]`$ValuesToCheck = @{}
`$MyInvocation.MyCommand.Parameters.GetEnumerator() | ForEach-Object {
if (`$_.Key -notlike '*Variable' -or `$_.Key -notin @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction'))
{
if (`$null -ne `$CurrentValues[`$_.Key] -or `$null -ne `$PSBoundParameters[`$_.Key])
{
`$ValuesToCheck.Add(`$_.Key, `$null)
if (-not `$PSBoundParameters.ContainsKey(`$_.Key))
{
`$PSBoundParameters.Add(`$_.Key, `$null)
}
}
}
}
"@
Write-TokenReplacement -Token 'Target Values: $(Convert-M365DscHashtableToString -Hashtable $ValuesToCheck)' `
-Value 'Target Values: $(Convert-M365DscHashtableToString -Hashtable $PSBoundParameters)' `
-FilePath $moduleFilePath
}
Write-TokenReplacement -Token '<#DefaultTestValuesToCheck#>' -Value $defaultTestValuesToCheck -FilePath $moduleFilePath
# Remove comments
Write-TokenReplacement -Token '<#ResourceGenerator' -Value '' -FilePath $moduleFilePath
Write-TokenReplacement -Token 'ResourceGenerator#>' -Value '' -FilePath $moduleFilePath
#endregion
#region Schema
$schemaFilePath = New-M365DSCSchemaFile -ResourceName $ResourceName -Path $Path
$schemaProperties = New-M365SchemaPropertySet -Properties $parameterInformation `
-Workload $Workload
if ($CmdLetNoun -like "*DeviceManagementConfigurationPolicy")
{
$CimInstancesSchemaContent += "`r`n" + ($definitionsettings.MOFInstance -join "`r`n`r`n")
$schemaProperties += $definitionSettings.MOF -join "`r`n"
}
Write-TokenReplacement -Token '<AssignmentsCIM>' -Value $AssignmentsCIM -FilePath $schemaFilePath
Write-TokenReplacement -Token '<AssignmentsProperty>' -Value $AssignmentsProperty -FilePath $schemaFilePath
Write-TokenReplacement -Token '<CIMInstances>' -Value $CimInstancesSchemaContent -FilePath $schemaFilePath
Write-TokenReplacement -Token '<FriendlyName>' -Value $ResourceName -FilePath $schemaFilePath
Write-TokenReplacement -Token '<ResourceName>' -Value $ResourceName -FilePath $schemaFilePath
Write-TokenReplacement -Token '<Properties>' -Value $schemaProperties -FilePath $schemaFilePath
#endregion
#region Settings
$resourcePermissions = (Get-M365DSCResourcePermission `
-Workload $Workload `
-CmdLetNoun $CmdLetNoun `
-ApiVersion $ApiVersion `
-UpdateVerb $updateVerb).permissions
if ($ResourceName -like "Intune*")
{
$resourcePermissions.graph.application.read += @{ name = 'Group.Read.All' }
$resourcePermissions.graph.application.update += @{ name = 'Group.Read.All' }
$resourcePermissions.graph.delegated.read += @{ name = 'Group.Read.All' }
$resourcePermissions.graph.delegated.update += @{ name = 'Group.Read.All' }
}
$resourcePermissions = $resourcePermissions | ConvertTo-Json -Depth 20
$resourcePermissions = ' ' + $resourcePermissions
Write-TokenReplacement -Token '<ResourceFriendlyName>' -Value $ResourceName -FilePath $settingsFilePath
Write-TokenReplacement -Token '<ResourceDescription>' -Value $resourceDescription -FilePath $settingsFilePath
Write-TokenReplacement -Token '<ResourcePermissions>' -Value $ResourcePermissions -FilePath $settingsFilePath
#endregion
#region ReadMe
Write-TokenReplacement -Token '<ResourceFriendlyName>' -Value $ResourceName -FilePath $readmeFilePath
Write-TokenReplacement -Token '<ResourceDescription>' -Value $resourceDescription -FilePath $readmeFilePath
#endregion
#region Examples
if ($null -ne $Credential)
{
Import-Module Microsoft365DSC -Force
New-M365DSCExampleFile -ResourceName $ResourceName `
-Path $ExampleFilePath `
-Credential $Credential
}
#endregion
}
else
{
$ParametersToFilterOut = @('Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction', 'ErrorVariable', 'WarningVariable', 'InformationVariable', 'OutVariable', 'OutBuffer', 'PipelineVariable', 'WhatIf', 'Confirm', 'ProgressAction')
$cmdlet = Get-Command ($cmdletVerb + "-" + $cmdletNoun)
$defaultParameterSetProperties = $cmdlet.ParameterSets | Where-Object -FilterScript {$_.IsDefault}
if ($null -eq $defaultParameterSetProperties)
{
# No default parameter set, if there is only a single parameter set then use that
if ($cmdlet.ParameterSets.Count -eq 1)
{
$defaultParameterSetProperties = $cmdlet.ParameterSets[0]
}
else
{
throw "CmdLet '$($cmdletVerb + "-" + $cmdletNoun)' does not have a default parameter set"
}
}
$properties = $defaultParameterSetProperties.Parameters | Where-Object -FilterScript {-not $ParametersToFilterOut.Contains($_.Name) -and -not $_.Name.StartsWith('MsftInternal')}
#region Get longest parametername
$longestParameterName = ("CertificateThumbprint").Length
foreach ($property in $properties)
{
if ($property.Name.Length -gt $longestParameterName)
{
$longestParameterName = $property.Name.Length
}
}
#endregion
#region Get ParameterBlock
$primaryKey = ''
$paramContent = [System.Text.StringBuilder]::New()
$returnContent = [System.Text.StringBuilder]::New()
$exportAuthContent = [System.Text.StringBuilder]::New()
$mofSchemaContent = [System.Text.StringBuilder]::New()
$fakeValues = @{}
foreach ($property in $properties)
{
$propertyTypeMOF = $property.ParameterType.Name
switch($property.ParameterType.Name)
{
"Int64"
{
$propertyTypeMOF = 'UInt64'
}
"Int32"
{
$propertyTypeMOF = 'UInt32'
}
}
if ($property.IsMandatory)
{
if ([System.String]::IsNullOrEmpty($primaryKey) -or $property.Name -eq 'Identity')
{
$primaryKey = $property.Name
}
$paramContent.AppendLine(" [Parameter(Mandatory = `$true)]") | Out-Null
$mofSchemaContent.AppendLine(" [Key, Description(`"$($property.Description)`")] $propertyTypeMOF $($property.Name);") | Out-Null
}
else
{
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"$($property.Description)`")] $propertyTypeMOF $($property.Name);") | Out-Null
}
$fakeValues.Add($property.Name, (Get-M365DSCDRGFakeValueForParameter -ParameterType $property.ParameterType.Name))
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - $property.Name.Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" $($property.Name)$spacingRequired= `$instance.$($property.Name)") | Out-Null
$paramContent.AppendLine(" [$($property.ParameterType.FullName)]") | Out-Null
$paramContent.AppendLine(" `$$($property.Name),`r`n") | Out-Null
}
# Ensure
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - ("Ensure").Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" Ensure$spacingRequired= 'Present'") | Out-Null
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$paramContent.AppendLine(" [ValidateSet('Present', 'Absent')]") | Out-Null
$paramContent.AppendLine(" [System.String]") | Out-Null
$paramContent.AppendLine(" `$Ensure,`r`n") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"Present ensures the instance exists, absent ensures it is removed.`"), ValueMap{`"Present`",`"Absent`"}, Values{`"Present`",`"Absent`"}] string Ensure;") | Out-Null
# Credential
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - ("Credential").Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" Credential$spacingRequired= `$Credential") | Out-Null
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$paramContent.AppendLine(" [System.Management.Automation.PSCredential]") | Out-Null
$paramContent.AppendLine(" `$Credential,`r`n") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"Credentials of the workload's Admin`"), EmbeddedInstance(`"MSFT_Credential`")] string Credential;") | Out-Null
if ($Workload -ne 'SecurityAndCompliance')
{
# Application Id
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - ("ApplicationId").Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" ApplicationId$spacingRequired= `$ApplicationId") | Out-Null
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$paramContent.AppendLine(" [System.String]") | Out-Null
$paramContent.AppendLine(" `$ApplicationId,`r`n") | Out-Null
$exportAuthContent.AppendLine(" ApplicationId = `$ApplicationId") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"Id of the Azure Active Directory application to authenticate with.`")] String ApplicationId;") | Out-Null
# Tenant Id
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - ("TenantId").Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" TenantId$spacingRequired= `$TenantId") | Out-Null
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$paramContent.AppendLine(" [System.String]") | Out-Null
$paramContent.AppendLine(" `$TenantId,`r`n") | Out-Null
$exportAuthContent.AppendLine(" TenantId = `$TenantId") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"Id of the Azure Active Directory tenant used for authentication.`")] String TenantId;") | Out-Null
# CertificateThumbprint
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - ("CertificateThumbprint").Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" CertificateThumbprint$spacingRequired= `$CertificateThumbprint") | Out-Null
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$paramContent.AppendLine(" [System.String]") | Out-Null
$paramContent.AppendLine(" `$CertificateThumbprint,`r`n") | Out-Null
$exportAuthContent.AppendLine(" CertificateThumbprint = `$CertificateThumbprint") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"Thumbprint of the Azure Active Directory application's authentication certificate to use for authentication.`")] String CertificateThumbprint;") | Out-Null
if ($workload -ne 'MicrosoftTeams')
{
# ApplicationSecret
$spacingRequired = " "
for ($i = 0; $i -lt ($longestParameterName - ("ApplicationSecret").Length); $i++)
{
$spacingRequired += " "
}
$returnContent.AppendLine(" ApplicationSecret$spacingRequired= `$ApplicationSecret") | Out-Null
$paramContent.AppendLine(" [Parameter()]") | Out-Null
$paramContent.AppendLine(" [System.Management.Automation.PSCredential]") | Out-Null
$paramContent.AppendLine(" `$ApplicationSecret,`r`n") | Out-Null
$exportAuthContent.AppendLine(" ApplicationSecret = `$ApplicationSecret") | Out-Null
$mofSchemaContent.AppendLine(" [Write, Description(`"Secret of the Azure Active Directory tenant used for authentication.`"), EmbeddedInstance(`"MSFT_Credential`")] String ApplicationSecret;") | Out-Null
}
}
$parameterBlock = $paramContent.ToString()
$parameterBlock = $parameterBlock.Remove($parameterBlock.Length -5, 5) # remove trailing comma
Write-TokenReplacement -Token '<ParameterBlock>' -Value $parameterBlock -FilePath $moduleFilePath
Write-TokenReplacement -Token '<ExportAuth>' -Value $exportAuthContent.ToString() -FilePath $moduleFilePath
Write-TokenReplacement -Token '<HashTableMapping>' -Value $returnContent.ToString() -FilePath $moduleFilePath
Write-TokenReplacement -Token '<PrimaryKey>' -Value $primaryKey -FilePath $moduleFilePath
Write-TokenReplacement -Token '<NewCmdLetName>' -Value "New-$cmdletNoun" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<UpdateCmdLetName>' -Value "Set-$cmdletNoun" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<RemoveCmdLetName>' -Value "Remove-$cmdletNoun" -FilePath $moduleFilePath
#endregion
#region GetKeyIdentifier
$cmdlet = Get-Command $('Get-' + $cmdletNoun)
$defaultParameterSetProperties = $cmdlet.ParameterSets | Where-Object -FilterScript {$_.IsDefault}
Write-TokenReplacement -Token '<getKeyIdentifier>' -Value $defaultParameterSetProperties[0].Name -FilePath $moduleFilePath
#endregion
Write-TokenReplacement -Token '<GetCmdLetName>' -Value "Get-$cmdletNoun" -FilePath $moduleFilePath
Write-TokenReplacement -Token '<#Workload#>' -Value $Workload -FilePath $moduleFilePath
Write-TokenReplacement -Token '<AssignmentsParam>' -Value '' -FilePath $moduleFilePath
Write-TokenReplacement -Token '<Properties>' -Value $mofSchemaContent -FilePath $schemaFilePath
Write-TokenReplacement -Token '<ResourceName>' -Value $ResourceName -FilePath $schemaFilePath
Write-TokenReplacement -Token '<CIMInstances>' -Value '' -FilePath $schemaFilePath
#region Readme & Settings
$cmdName = "New-$cmdletNoun"
$cmdletInfo = & $cmdName -?
$synopsis = $cmdletInfo.Synopsis.Replace('cmdlet', 'resource')
Write-TokenReplacement -Token '<ResourceFriendlyName>' -Value $ResourceName -FilePath $readmeFilePath
Write-TokenReplacement -Token '<ResourceDescription>' -Value $synopsis -FilePath $readmeFilePath
Write-TokenReplacement -Token '<ResourceFriendlyName>' -Value $ResourceName -FilePath $settingsFilePath
Write-TokenReplacement -Token '<ResourceDescription>' -Value $synopsis -FilePath $settingsFilePath
Write-TokenReplacement -Token '<ResourcePermissions>' -Value '[]' -FilePath $settingsFilePath
#endregion
#region UnitTests
$fakeValuesString = [System.Text.StringBuilder]::New()
$fakeValuesDriftString = [System.Text.StringBuilder]::New()
$numberOfProperties = $fakeValues.Keys.Count
$currentKeyIndex = 1
foreach ($key in $fakeValues.Keys)
{
$spacingRequired = ' '
for ($i = 0; $i -lt ($longestParameterName - $key.Length); $i++)
{
$spacingRequired += " "
}
$propertyValue = $null
$propertyDriftValue = $null
if ($null -eq $fakeValues.$key)
{
continue
}
switch ($fakeValues.$key.GetType().Name)
{
"String"
{
$propertyValue = "`"$($fakeValues.$key)`""
if ($key -ne $primaryKey)
{
$propertyDriftValue = "`"" + (Get-M365DSCDRGFakeValueForParameter -ParameterType 'String' `
-Drift:$true) + "`""
}
else
{
$propertyDriftValue = $propertyValue
}
}
"Boolean"
{
$propertyValue = "`$$($fakeValues.$key)"
if ($key -ne $primaryKey)
{
$propertyDriftValue = "`$" + (Get-M365DSCDRGFakeValueForParameter -ParameterType 'Boolean' `
-Drift:$true)
}
else
{
$propertyDriftValue = $propertyValue
}
}
"Int32"
{
$propertyValue = $fakeValues.$key.ToString()
if ($key -ne $primaryKey)
{
$propertyDriftValue = (Get-M365DSCDRGFakeValueForParameter -ParameterType 'Int32' `
-Drift:$true)
}
else
{
$propertyDriftValue = $propertyValue
}
}
"Int64"
{
$propertyValue = $fakeValues.$key.ToString()
if ($key -ne $primaryKey)
{
$propertyDriftValue = (Get-M365DSCDRGFakeValueForParameter -ParameterType 'Int64' `
-Drift:$true)
}
else
{
$propertyDriftValue = $propertyValue
}
}
}
$fakeValuesString.AppendLine("#$#$key$spacingRequired= $propertyValue") | Out-Null
$fakeValuesDriftString.AppendLine("#$#$key$spacingRequired= $propertyDriftValue") | Out-Null
$currentKeyIndex++
}
Write-TokenReplacement -Token '<ResourceName>' -Value $ResourceName -FilePath $unitTestPath
Write-TokenReplacement -Token '<GetCmdletName>' -Value "Get-$cmdletNoun" -FilePath $unitTestPath
Write-TokenReplacement -Token '<SetCmdletName>' -Value "Set-$cmdletNoun" -FilePath $unitTestPath
Write-TokenReplacement -Token '<NewCmdletName>' -Value "New-$cmdletNoun" -FilePath $unitTestPath
Write-TokenReplacement -Token '<RemoveCmdletName>' -Value "Remove-$cmdletNoun" -FilePath $unitTestPath
Write-TokenReplacement -Token '<FakeValues>' -Value $fakeValuesString.ToString().Replace('#$#', ' ') -FilePath $unitTestPath
Write-TokenReplacement -Token '<DriftValues>' -Value $fakeValuesDriftString.ToString().Replace('#$#', ' ') -FilePath $unitTestPath
#endregion
#region Generate Examples
$exportPath = Join-Path -Path $env:temp -ChildPath $ResourceName
Export-M365DSCConfiguration -Credential $Credential `
-Components $ResourceName -Path $exportPath `
-FileName "$ResourceName.ps1" `
-ConfigurationName 'Example' | Out-Null
$exportedFilePath = Join-Path -Path $exportPath -ChildPath "$ResourceName.ps1"
$exportContent = Get-Content $exportedFilePath -Raw
$start = $exportContent.IndexOf("`r`n $ResourceName ")
$end = $exportContent.IndexOf("`r`n }", $start)
$start = $exportContent.IndexOf("{", $start) + 1
$exampleContent = $exportContent.Substring($start, $end-$start)
$exampleFileFullPath = "$ExampleFilePath\$ResourceName\1-$ResourceName-Example.psm1"
$folderPath = "$ExampleFilePath\$ResourceName"
New-Item $folderPath -ItemType Directory -Force | Out-Null
$templatePath = '.\Example.Template.ps1'
Copy-Item -Path $templatePath -Destination $exampleFileFullPath -Force
Write-TokenReplacement -Token '<FakeValues>' -Value $exampleContent -FilePath $exampleFileFullPath
Write-TokenReplacement -Token '<ResourceName>' -Value $ResourceName -FilePath $exampleFileFullPath
#endregion
}
}
function Get-MgGraphModuleCmdLetDifference
{
$modules = Get-Module -Name Microsoft.Graph.* -ListAvailable | Sort-Object -Property Name, Version | Out-GridView -PassThru
if ($modules.Count -eq 0)
{
throw 'No module selected!'
}
if (($modules.Name | Sort-Object | Select-Object -Unique).Count -ne 1 -or $modules.Count -ne 2)
{
throw 'Please select two versions of the same module'
}
[array]$exportedKeysModule1 = $modules[0].ExportedCommands.Keys
[array]$exportedKeysModule2 = $modules[1].ExportedCommands.Keys
$diffs = Compare-Object -ReferenceObject $exportedKeysModule1 -DifferenceObject $exportedKeysModule2
foreach ($diff in $diffs)
{
switch ($diff.SideIndicator)
{
'=>'
{
Write-Host "Cmdlet '$($diff.InputObject)' is new in $($modules[1].Name) v$($modules[1].Version)" -ForegroundColor Green
}
'<='
{
Write-Host "Cmdlet '$($diff.InputObject)' has been removed from $($modules[1].Name) v$($modules[1].Version)" -ForegroundColor Yellow
}
}
}
}
function New-M365DSCResourceForGraphCmdLet
{
param (
# Name of one graph module, e.g. "Microsoft.Graph.Intune"
[Parameter()]
[System.String]
$MgGraphModule,
# Generate resources for all cmdLets within Microsoft.Graph.* modules
[Parameter()]
[Switch]
$All = $false
)
if ($null -ne $MgGraphModuleName)
{
$modules = Get-InstalledModule -Name $MgGraphModule
}
if ($All)
{
$modules = Get-InstalledModule -Name Microsoft.Graph.*
}
foreach ($module in $modules)
{
Write-Verbose -Message "$($module.Name)"
$commands = (Get-Command -Module $module.Name -Verb Get | Where-Object -FilterScript { $_.CommandType -eq 'Function' }).Noun
$commands = Get-Command -Module $module.Name
$nouns = $commands.Noun | Sort-Object | Select-Object -Unique
foreach ($noun in $nouns)
{
Write-Verbose -Message "- $($noun)"
$nounCommands = $commands | Where-Object -FilterScript { $_.Noun -eq $noun }
if ($nounCommands.Verb -notcontains 'Get' -or `
$nounCommands.Verb -notcontains 'Update' -or `
$nounCommands.Verb -notcontains 'New')
{
Write-Verbose ' [SKIPPING] Noun does not have Get, New and/or Update method' -ForegroundColor Magenta
continue
}
$shortNoun = $noun.Substring(2, $noun.Length - 2)
New-M365DSCResource -ResourceName $shortNoun -GraphModule $module.Name -GraphModuleVersion $module.Version -CmdLetNoun $noun
}
}
}
function Get-CmdletDefinition
{
param (
[Parameter(Mandatory = $true)]
[string]
$Entity,
[Parameter()]
[ValidateSet('v1.0', 'beta')]
[string]
$APIVersion
)
if ($ApiVersion -eq 'v1.0')
{
$Uri = 'https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/clean_v10_metadata/cleanMetadataWithDescriptionsAndAnnotationsv1.0.xml'
}
else
{
$Uri = 'https://raw.githubusercontent.com/microsoftgraph/msgraph-metadata/master/clean_beta_metadata/cleanMetadataWithDescriptionsAndAnnotationsbeta.xml'
}
$metadata = ([XML](Invoke-RestMethod -Uri $Uri)).Edmx.DataServices.schema
return $metadata
}
# Retrieve all properties from metadata schema
function Get-TypeProperties
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
$CmdletDefinition,
[Parameter(Mandatory = $true)]
[System.String]
$Entity,
[Parameter()]
[System.Boolean]
$IncludeNavigationProperties = $false,
[Parameter()]
[System.String[]]
$CimClasses,
[Parameter()]
[System.String]
$Workload,
[Parameter()]
[System.String]
$ParentPropertyName = ""
)
$namespace = $CmdletDefinition | Where-Object -FilterScript { $_.EntityType.Name -contains $Entity }
if ($null -eq $namespace)
{
$namespace = $CmdletDefinition | Where-Object -FilterScript { $_.ComplexType.Name -contains $Entity }
}
$properties = @()
$baseType = $Entity
#Get all properties for the entity or complex
do
{
$isComplex = $false
$entityType = $namespace.EntityType | Where-Object -FilterScript { $_.Name -eq $baseType }
$isAbstract = $false
if ($entityType.Abstract -eq 'True')
{
$isAbstract = $true
}
if ($null -eq $entityType)
{
$isComplex = $true
$entityType = $namespace.ComplexType | Where-Object -FilterScript { $_.Name -eq $baseType }
#if ($entityType.Abstract -eq 'true')
if ($null -eq $entityType.BaseType)
{
$isAbstract = $true
}
}
if ($null -ne $entityType.Property)
{
$rawProperties = $entityType.Property
foreach ($property in $rawProperties)
{
$IsRootProperty = $false
if (($entityType.BaseType -eq "graph.Entity") -or ($entityType.Name -eq "entity") -or ($isAbstract -and $entityType.Name -eq $global:searchedEntity))
{
$IsRootProperty = $true
}
$myProperty = @{}
$myProperty.Add('Name',$property.Name)
$myProperty.Add('Type',$property.Type)
$myProperty.Add('IsRootProperty',$IsRootProperty)
$myProperty.Add('ParentType',$entityType.Name)
$description = ''
if (-not [String]::IsNullOrWhiteSpace($property.Annotation.String))
{
$description = $property.Annotation.String.Replace('"',"'")
$description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', ''
}
else
{
$annotation = $CmdletDefinition.Annotations | Where-Object -FilterScript {$_.Target -like "microsoft.graph.$($property.ParentNode.Name)/$($property.Name)" }
if (-not [String]::IsNullOrWhiteSpace($annotation.Annotation.String))
{
$description = $annotation.Annotation.String.Replace('"',"'")
$description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', ''
}
}
$myProperty.Add('Description', $description)
$properties += $myProperty
}
}
if ($isComplex)
{
$abstractType = $namespace.ComplexType | Where-Object -FilterScript {$_.BaseType -eq "graph.$baseType"}
foreach ($subType in $abstractType)
{
$rawProperties = $subType.Property
foreach ($property in $rawProperties)
{
$IsRootProperty = $false
if ($entityType.BaseType -eq "graph.Entity" -or $entityType.Name -eq "entity" )
{
$IsRootProperty = $true
}
if ($property.Name -notin ($properties.Name))
{
$myProperty = @{}
$myProperty.Add('Name',$property.Name)
$myProperty.Add('Type',$property.Type)
$myProperty.Add('IsRootProperty',$false)
$myProperty.Add('ParentType',$entityType.Name)
$description = ''
if (-not [String]::IsNullOrWhiteSpace($property.Annotation.String))
{
$description = $property.Annotation.String.Replace('"',"'")
$description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', ''
}
else
{
$annotation = $CmdletDefinition.Annotations | Where-Object -FilterScript { $_.Target -like "microsoft.graph.$($property.ParentNode.Name)/$($property.Name)" }
if (-not [String]::IsNullOrWhiteSpace($annotation.Annotation.String))
{
$description = $annotation.Annotation.String.Replace('"',"'")
$description = $description -replace '[^\p{L}\p{Nd}/(/}/_ -.,=:)'']', ''
}
}
$myProperty.Add('Description', $description)
$properties += $myProperty
}
}
}
if (([Array]$abstractType.Name).Count -gt 0)
{
$myProperty = @{}
$myProperty.Add('Name','@odata.type')
$myProperty.Add('Type','Custom.Enum')
$myProperty.Add('Members',$abstractType.Name)
$myProperty.Add('IsRootProperty',$false)
$myProperty.Add('Description','The type of the entity.')
$myProperty.Add('ParentType',$entityType.Name)
$properties += $myProperty
}
}
if ($IncludeNavigationProperties -and $null -ne $entityType.NavigationProperty)
{
$rawProperties = $entityType.NavigationProperty
foreach ($property in $rawProperties)
{
$IsRootProperty = $false
if ($entityType.BaseType -eq "graph.Entity" -or $entityType.Name -eq "entity" )
{
$IsRootProperty = $true
}
$myProperty = @{}
$myProperty.Add('Name',$property.Name)
$myProperty.Add('Type',$property.Type)
$myProperty.Add('IsNavigationProperty', $true)
$myProperty.Add('IsRootProperty',$IsRootProperty)
$myProperty.Add('ParentType',$entityType.Name)
$myProperty.Add('Description', $property.Annotation.String.Replace('"',"'"))
$properties += $myProperty
}
}
$baseType = $null
if (-not [String]::IsNullOrEmpty($entityType.BaseType))
{
$baseType = $entityType.BaseType.Replace('graph.','')
}
} while ($null -ne $baseType)
# Enrich properties
$result = @()
foreach ($property in $properties)
{
$derivedType = $property.Type
#Array
$isArray = $false
$isEnum = $false
if ($derivedType -eq 'Custom.Enum')
{
$isEnum = $true
}
$isComplex = $false
if ($derivedType -like "Collection(*)")
{
$isArray = $true
$derivedType = $derivedType.Replace('Collection(','').Replace(')','')
}
$property.Add('IsArray',$isArray)
#}
#DerivedType
if ($derivedType -like ('graph.*'))
{
$derivedType = $derivedType.Replace('graph.','')
#Enum
if ($derivedType -in $namespace.EnumType.Name)
{
$isEnum = $true
$enumType = $namespace.EnumType | where-Object -FilterScript {$_.Name -eq $derivedType}
$property.Add('Members',$enumType.Member.Name)
}
#Complex
if (($derivedType -in $namespace.ComplexType.Name) -or ($property.IsNavigationProperty))
{
$complexName = $ParentPropertyName + "-" + $property.Name + "-" + $property.Type
$isComplex = $true
if ($complexName -notin $global:ComplexList)
{
if ($ParentPropertyName -ne "")
{
$global:ComplexList += $complexName
}
$nestedProperties = Get-TypeProperties `
-CmdletDefinition $CmdletDefinition `
-Entity $derivedType `
-CimClasses $CimClasses `
-Workload $Workload `
-ParentPropertyName $property.Name
$property.Add('Properties', $nestedProperties)
}
}
}
if ($derivedType -like ('Edm.*'))
{
$derivedType = $derivedType.Replace('Edm','System')
if ($derivedType -like ('*.TimeOfDay'))
{
$derivedType = 'System.TimeSpan'
}
if ($derivedType -like ('*.Date'))
{
$derivedType = 'System.DateTime'
}
}
if ($cimClasses -contains "MSFT_$Workload$derivedType")
{
$cimCounter = ([Array]($CimClasses | Where-Object -FilterScript { $_ -like "MSFT_$Workload$derivedType*" })).Count
$derivedType += $cimCounter.ToString()
}
if ($isEnum)
{
$derivedType = 'System.String'
}
$property.Add('DerivedType', $derivedType)
$property.Add('IsComplexType', $isComplex)
$property.Add('IsEnumType', $isEnum)
$result += $property
}
return $result
}
function Get-Microsoft365DSCModuleCimClass
{
[CmdletBinding()]
[OutputType([System.String])]
param (
[Parameter()]
[System.String]
$ResourceName
)
Import-Module -Name Microsoft365DSC -Force
$modulePath = Split-Path -Path (Get-Module -Name Microsoft365DSC).Path
$resourcesPath = "$modulePath\DSCResources\*\*.mof"
$resources = (Get-ChildItem $resourcesPath).FullName
$resources = $resources | Where-Object -FilterScript {$_ -notlike "*MSFT_$ResourceName.schema.mof"}
$cimClasses = @()
foreach ($resource in $resources)
{
$text = Get-Content $resource
foreach ($line in $text)
{
if ($line -like "class MSFT_*")
{
$class = $line.Replace("class ","").Replace("Class ","")
if ($line -like "*:*")
{
$class = $class.Split(":")[0].trim()
}
if ($class -notin $cimClasses)
{
$cimClasses += $class
}
}
}
}
return $cimClasses
}
function Get-StringFirstCharacterToUpper
{
[CmdletBinding()]
[OutputType([System.String])]
param (
[Parameter(Mandatory = $true)]
[System.String]
$Value
)
return $Value.Substring(0, 1).ToUpper() + $Value.Substring(1, $Value.Length - 1)
}
function Get-StringFirstCharacterToLower
{
[CmdletBinding()]
[OutputType([System.String])]
param (
[Parameter(Mandatory = $true)]
[System.String]
$Value
)
return $Value.Substring(0, 1).ToLower() + $Value.Substring(1, $Value.Length - 1)
}
function Get-ComplexTypeConstructorToString
{
[CmdletBinding()]
[OutputType([System.String])]
param (
[Parameter(Mandatory = $true)]
[ValidateScript({ $_.IsComplexType })]
$Property,
[Parameter()]
[System.String]
$ParentPropertyName,
[Parameter()]
[System.String]
$ParentPropertyValuePath,
[Parameter()]
[System.String]
$IsParentFromAdditionalProperties = $False,
[Parameter()]
[System.Int32]
$IndentCount = 0,
[Parameter()]
[System.String]
$DateFormat,
[Parameter()]
[System.Boolean]
$IsNested = $false
)
$complexString = [System.Text.StringBuilder]::New()
$indent = " "
$spacing = $indent * $IndentCount
$propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name
$returnPropertyName = "complex" + $propertyName
$tempPropertyName = $returnPropertyName
$valuePrefix = "getValue."
$referencePrefix = "getValue."
if ($isNested)
{
#$valuePrefix = "`$current$propertyName."
$valuePrefix = "$ParentPropertyValuePath"
$referencePrefix = "$ParentPropertyValuePath"
}
$loopPropertyName = $Property.Name
if ($isParentfromAdditionalProperties)
{
$loopPropertyName = Get-StringFirstCharacterToLower -Value $loopPropertyName
}
if ($Property.IsRootProperty -eq $false -and -not $IsNested)
{
$loopPropertyName = Get-StringFirstCharacterToLower -Value $Property.Name
$propertyName = Get-StringFirstCharacterToLower -Value $Property.Name
$valuePrefix += "AdditionalProperties."
$referencePrefix += "AdditionalProperties."
}
$referencePrefix += "$propertyName."
if ($property.IsArray)
{
$tempPropertyName = "my$propertyName"
if ($isNested)
{
$valuePrefix = $ParentPropertyValuePath
if ($null -eq $valuePrefix)
{
$propRoot = $ParentPropertyName.Replace("my","")
$valuePrefix = "current$propRoot."
#if ($property.IsRootProperty -eq $false -and -not $IsNested)
#{
# $valuePrefix += "AdditionalProperties."
#}
}
}
$iterationPropertyName = "current$propertyName"
$complexString.AppendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null
$complexString.AppendLine($spacing + "foreach (`$$iterationPropertyName in `$$valuePrefix" + $loopPropertyName + ")" ) | Out-Null
$complexString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount ++
$spacing = $indent * $IndentCount
}
$complexString.AppendLine($spacing + "`$$tempPropertyName" + " = @{}") | Out-Null
foreach ($nestedProperty in $property.Properties)
{
$nestedPropertyName = Get-StringFirstCharacterToUpper -Value $nestedProperty.Name
if ($nestedPropertyName -eq '@odata.type')
{
$nestedPropertyName = 'odataType'
}
$valuePrefix = "getValue."
if ($Property.IsArray)
{
$valuePrefix = "$iterationPropertyName."
$referencePrefix = "$iterationPropertyName."
}
if ($isNested -and -not $Property.IsArray)
{
$propRoot = $ParentPropertyName.Replace("my","")
#$valuePrefix = "current$propRoot."
$valuePrefix = "$referencePrefix"
#$recallProperty=''
if ($isParentfromAdditionalProperties)
{
#$recallProperty=Get-StringFirstCharacterToLower -Value $propertyName
$referencePrefixElements = @()
foreach ($elt in ($referencePrefix.Split('.') | Where-Object -FilterScript { -not [String]::IsNullOrWhiteSpace($_) }))
{
$referencePrefixElements += Get-StringFirstCharacterToLower -Value $elt
#$referencePrefix = "$valuePrefix$recallProperty."
}
$referencePrefix = ($referencePrefixElements -join '.') + '.'
$valuePrefix = $referencePrefix
}
#$valuePrefix += "."
}
$AssignedPropertyName = $nestedProperty.Name
if ($nestedProperty.IsRootProperty -eq $false -and -not $IsNested)
{
$valuePrefix += "AdditionalProperties."
}
if ($nestedProperty.IsRootProperty -eq $false -or $IsParentFromAdditionalProperties)
{
$AssignedPropertyName = Get-StringFirstCharacterToLower -Value $nestedProperty.Name
}
if ($AssignedPropertyName.contains("@"))
{
$AssignedPropertyName = "'$AssignedPropertyName'"
}
if ((-not $isNested) -and (-not $Property.IsArray) -and ([String]::IsNullOrWhiteSpace($ParentPropertyValuePath)))
{
$valuePrefix += "$propertyName."
}
if ($nestedProperty.IsComplexType)
{
$complexName = $Property.Name + "-" + $nestedProperty.Type
#if ($complexName -notin $global:ComplexList)
#{
$global:ComplexList += $complexName
$nestedString = ''
$nestedString = Get-ComplexTypeConstructorToString `
-Property $nestedProperty `
-IndentCount $IndentCount `
-IsNested $true `
-ParentPropertyName $tempPropertyName `
-ParentPropertyValuePath $referencePrefix `
-IsParentFromAdditionalProperties $(if ($isNested) {$isParentfromAdditionalProperties} else {-not $Property.IsRootProperty})
#-IsParentFromAdditionalProperties (-not $Property.IsRootProperty)
$complexString.Append($nestedString) | Out-Null
#}
}
else
{
if ($nestedProperty.Type -like "*.Date*")
{
$nestedPropertyType = $nestedProperty.Type.Split(".") | Select-Object -Last 1
if ($isNested)
{
$complexString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null
}
else
{
$complexString.AppendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null
}
$complexString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$AssignedPropertyName += ").ToString('$DateFormat')"
if ($isNested)
{
$complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$valuePrefix$AssignedPropertyName)" ) | Out-Null
}
else
{
$complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$referencePrefix$AssignedPropertyName)" ) | Out-Null
}
$IndentCount--
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "}" ) | Out-Null
}
elseif ($nestedProperty.Type -like "*.Time*")
{
$nestedPropertyType = $nestedProperty.Type.Split(".") | Select-Object -Last 1
if ($isNested)
{
$complexString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null
}
else
{
$complexString.AppendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null
}
$complexString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$AssignedPropertyName += ").ToString()"
if ($isNested)
{
$complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$valuePrefix$AssignedPropertyName)" ) | Out-Null
}
else
{
$complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', ([$nestedPropertyType]`$$referencePrefix$AssignedPropertyName)" ) | Out-Null
}
$IndentCount--
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "}" ) | Out-Null
}
else
{
if ($nestedProperty.IsEnumType)
{
if ($isNested)
{
$complexString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$AssignedPropertyName)" ) | Out-Null
}
else
{
$complexString.AppendLine($spacing + "if (`$null -ne `$$referencePrefix$AssignedPropertyName)" ) | Out-Null
}
$complexString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
if ($isNested)
{
$complexString.Append($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$valuePrefix$AssignedPropertyName.ToString()" ) | Out-Null
}
else
{
$complexString.Append($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$referencePrefix$AssignedPropertyName.ToString()" ) | Out-Null
}
$complexString.Append(")`r`n" ) | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "}" ) | Out-Null
}
else
{
if ($isNested)
{
$complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$valuePrefix$AssignedPropertyName)" ) | Out-Null
}
else
{
$complexString.AppendLine($spacing + "`$$tempPropertyName.Add('" + $nestedPropertyName + "', `$$referencePrefix$AssignedPropertyName)" ) | Out-Null
}
}
}
}
}
if ($property.IsArray)
{
$complexString.AppendLine($spacing + "if (`$$tempPropertyName.values.Where({`$null -ne `$_}).Count -gt 0)" ) | Out-Null
$complexString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "`$$returnPropertyName += `$$tempPropertyName" ) | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "}" ) | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "}" ) | Out-Null
if ($IsNested)
{
$complexString.AppendLine($spacing + "`$$ParentPropertyName" +".Add('$propertyName',`$$returnPropertyName" +")" ) | Out-Null
}
}
else
{
$complexString.AppendLine($spacing + "if (`$$tempPropertyName.values.Where({`$null -ne `$_}).Count -eq 0)" ) | Out-Null
$complexString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "`$$returnPropertyName = `$null" ) | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$complexString.AppendLine($spacing + "}" ) | Out-Null
if ($IsNested)
{
$complexString.AppendLine($spacing + "`$$ParentPropertyName" +".Add('$propertyName',`$$returnPropertyName" +")" ) | Out-Null
}
}
return [String]($complexString.ToString())
}
function Get-DateTypeConstructorToString
{
[CmdletBinding()]
[OutputType([System.String[]])]
param (
[Parameter(Mandatory = $true)]
[ValidateScript({$_.Type -like "System.Date*"})]
$Property,
[Parameter()]
[System.String]
$ParentPropertyName,
[Parameter()]
[System.Int32]
$IndentCount = 0,
[Parameter()]
[System.String]
$DateFormat,
[Parameter()]
[System.Boolean]
$IsNested = $false
)
$dateString = [System.Text.StringBuilder]::New()
$indent = " "
$spacing = $indent * $IndentCount
$valuePrefix = "getValue."
$propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name
$returnPropertyName = "date"+ $propertyName
$propertyType = $Property.Type.Split(".") | Select-Object -Last 1
if ($Property.IsRootProperty -eq $false)
{
$propertyName = Get-StringFirstCharacterToLower -Value $Property.Name
$valuePrefix += "AdditionalProperties."
}
if ($property.IsArray)
{
$dateString.AppendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null
$dateString.AppendLine($spacing + "foreach (`$current$propertyName in `$$valuePrefix$PropertyName)" ) | Out-Null
$dateString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$dateString.AppendLine($spacing + "`$$returnPropertyName += ([$propertyType]`$current$propertyName).ToString('$DateFormat')") | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$dateString.AppendLine($spacing + "}" ) | Out-Null
}
else
{
$dateString.AppendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null
$dateString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null
$dateString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$dateString.AppendLine($spacing + "`$$returnPropertyName = ([$propertyType]`$$valuePrefix$PropertyName).ToString('$DateFormat')") | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$dateString.AppendLine($spacing + "}" ) | Out-Null
}
return $dateString.ToString()
}
function Get-TimeTypeConstructorToString
{
[CmdletBinding()]
[OutputType([System.String[]])]
param (
[Parameter(Mandatory = $true)]
[ValidateScript({ $_.Type -like "System.Time*" })]
$Property,
[Parameter()]
[System.String]
$ParentPropertyName,
[Parameter()]
[System.Int32]
$IndentCount = 0,
[Parameter()]
[System.String]
$DateFormat,
[Parameter()]
[System.Boolean]
$IsNested = $false
)
$timeString = [System.Text.StringBuilder]::New()
$indent = " "
$spacing = $indent * $IndentCount
$valuePrefix = "getValue."
$propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name
$returnPropertyName = "time"+ $propertyName
$propertyType = $Property.Type.Split(".") | Select-Object -Last 1
if ($Property.IsRootProperty -eq $false)
{
$propertyName = Get-StringFirstCharacterToLower -Value $Property.Name
$valuePrefix += "AdditionalProperties."
}
if ($property.IsArray)
{
$timeString.AppendLine($spacing + "`$$returnPropertyName" + " = @()") | Out-Null
$timeString.AppendLine($spacing + "foreach (`$current$propertyName in `$$valuePrefix$PropertyName)" ) | Out-Null
$timeString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$timeString.AppendLine($spacing + "`$$returnPropertyName += ([$propertyType]`$current$propertyName).ToString()") | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$timeString.AppendLine($spacing + "}" ) | Out-Null
}
else
{
$timeString.AppendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null
$timeString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null
$timeString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$timeString.AppendLine($spacing + "`$$returnPropertyName = ([$propertyType]`$$valuePrefix$PropertyName).ToString()") | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$timeString.AppendLine($spacing + "}" ) | Out-Null
}
return $timeString.ToString()
}
function Get-EnumTypeConstructorToString
{
[CmdletBinding()]
[OutputType([System.String[]])]
param (
[Parameter(Mandatory = $true)]
[ValidateScript({$_.IsEnumType})]
$Property,
[Parameter()]
[System.String]
$ParentPropertyName,
[Parameter()]
[System.Int32]
$IndentCount = 0,
[Parameter()]
[System.String]
$DateFormat
)
$enumString = [System.Text.StringBuilder]::New()
$indent = " "
$spacing = $indent * $IndentCount
$valuePrefix = "getValue."
$propertyName = Get-StringFirstCharacterToUpper -Value $Property.Name
$returnPropertyName= "enum"+ $propertyName
if ($Property.IsRootProperty -eq $false)
{
$propertyName = Get-StringFirstCharacterToLower -Value $Property.Name
$valuePrefix += "AdditionalProperties."
}
$enumString.AppendLine($spacing + "`$$returnPropertyName" + " = `$null") | Out-Null
$enumString.AppendLine($spacing + "if (`$null -ne `$$valuePrefix$PropertyName)" ) | Out-Null
$enumString.AppendLine($spacing + "{" ) | Out-Null
$IndentCount++
$spacing = $indent * $IndentCount
$enumString.AppendLine($spacing + "`$$returnPropertyName = `$$valuePrefix$PropertyName.ToString()") | Out-Null
$IndentCount--
$spacing = $indent * $IndentCount
$enumString.AppendLine($spacing + "}" ) | Out-Null
return $enumString.ToString()
}
function Get-ParameterBlockInformation
{
[OutputType([Hashtable[]])]
[CmdletBinding()]
param (
[Parameter()]
[Object[]]
$Properties,
[Parameter()]
[System.Object]
$DefaultParameterSetProperties
)
$parameterBlock = @()
foreach ($property in $Properties)
{
$isMandatory = $false
# Replace this one with the proper mandatory key value
$cmdletParameter = $DefaultParameterSetProperties | Where-Object -FilterScript { $_.Name -eq $property.Name }
if (($null -ne $cmdletParameter `
-and $cmdletParameter.IsMandatory -eq $true) `
-or $property.Name -eq 'Id' -or $property.Name -eq 'DisplayName')
{
$isMandatory = $true
$parameterAttribute = "[Parameter(Mandatory = `$true)]"
}
else
{
$parameterAttribute = '[Parameter()]'
}
$parameterName = $property.Name
$parameterNameFirstLetter = $parameterName.Substring(0, 1)
$parameterNameFirstLetter = $parameterNameFirstLetter.ToUpper()
$parameterNameCamelCaseString = $parameterName.Substring(1)
$parameterName = "$($parameterNameFirstLetter)$($parameterNameCamelCaseString)"
$myParam = @{
IsMandatory = $isMandatory
Attribute = $parameterAttribute
Type = $property.DerivedType
Name = $parameterName
Description = $property.Description
IsArray = $property.IsArray
IsComplexType = $property.IsComplexType
IsEnumType = $property.IsEnumType
IsRootProperty = $property.IsRootProperty
ParentType = $property.ParentType
}
if ($property.IsEnumType)
{
$myParam.Add('Members', $property.Members)
}
if ($property.IsComplexType)
{
$myParam.Add('Properties', (Get-ParameterBlockInformation `
-Properties $property.Properties `
-DefaultParameterSetProperties $DefaultParameterSetProperties))
}
$parameterBlock += $myParam
}
return $parameterBlock
}
function Get-M365DSCDRGParameterType
{
param(
[parameter(Mandatory = $true)]
[System.String]
$Type
)
$parameterType = ''
switch -Wildcard ($Type.ToLower())
{
'system.string'
{
$parameterType = 'System.String'
break;
}
'system.datetime'
{
$parameterType = 'System.String'
break;
}
'system.boolean'
{
$parameterType = 'System.Boolean'
break;
}
'system.management.automation.switchparameter'
{
$parameterType = 'System.Boolean'
break;
}
'system.int32'
{
$parameterType = 'System.Int32'
break;
}
'system.int64'
{
$parameterType = 'System.Int64'
break;
}
'system.string[[\]]'
{
$parameterType = 'System.String[]'
break;
}
'system.*'
{
$parameterType = $_
break;
}
'edm.*'
{
$parameterType = $Type.Replace('Edm', 'System')
break;
}
'C(*)'
{
$typeName = $Type.Replace('C(', '').Replace(')', '')
$parameterType = (Get-M365DSCDRGParameterType -Type $typeName) + '[]'
break;
}
'Microsoft.Graph.PowerShell.*'
{
$parameterType = $_
break;
}
Default
{
$parameterType = $_
}
}
return $parameterType
}
function Get-M365DSCDRGParameterTypeForSchema
{
param(
[parameter(Mandatory = $true)]
[System.String]
$Type
)
$parameterType = ''
switch -Wildcard ($Type.ToLower())
{
'*.string'
{
$parameterType = 'String'
}
'*.datetime'
{
$parameterType = 'String'
}
'*.boolean'
{
$parameterType = 'Boolean'
}
'*.int32'
{
$parameterType = 'UInt32'
}
'*.int64'
{
$parameterType = 'UInt64'
}
Default
{
$parameterType = 'String'
}
}
return $parameterType
}
function New-M365CmdLetHelper
{
param(
[Parameter()]
[System.String]
$CmdLetVerb,
[Parameter()]
[System.String]
$CmdLetNoun,
[Parameter()]
[System.String]
$Properties
)
$returnValue = "$($CmdLetVerb)-$($CmdLetNoun) "
foreach ($property in $Properties)
{
if ($property.IsMandatory -eq $true)
{
$returnValue += "-$($property.Name) `$$($property.Name)0"
}
}
}
function Get-M365DSCDRGFakeValueForParameter
{
[CmdletBinding()]
[OutputType([System.Object])]
param(
[Parameter(Mandatory = $true)]
[System.String]
$ParameterType,
[Parameter()]
[System.String[]]
$ValidateSetValues,
[Parameter()]
[System.Boolean]
$Drift = $false
)
switch ($ParameterType)
{
"String"
{
if ($null -eq $ValidateSetValues -or $ValidateSetValues.Length -eq 0)
{
if ($Drift)
{
return "FakeStringValueDrift #Drift"
}
return "FakeStringValue"
}
}
"Boolean"
{
if ($Drift)
{
return $false
}
return $true
}
"Int32"
{
if ($Drift)
{
return 2
}
return 3
}
"Int64"
{
if ($Drift)
{
return 2
}
return 3
}
}
}
function Get-M365DSCFakeValues
{
[OutputType([System.Collections.Hashtable])]
param(
[Parameter(Mandatory = $true)]
[System.Object[]]
$ParametersInformation,
[Parameter()]
[System.Boolean]
$IntroduceDrift = $false,
[Parameter()]
[System.Boolean]
$IsGetTargetResource = $false,
[Parameter()]
[System.Boolean]
$IsParentFromAdditionalProperties = $false,
[Parameter()]
[System.Boolean]
$isCmdletCall = $false,
[Parameter()]
[System.Boolean]
$isRecursive = $false,
[Parameter()]
[System.String]
$AdditionalPropertiesType = '',
[Parameter()]
[System.String]
$Workload,
[Parameter()]
[System.String]
$DateFormat = "o"
)
$result = @{}
$parameters = $parametersInformation
$additionalProperties = @{}
foreach ($parameter in $parameters)
{
if ($null -ne (Get-Variable hashValue -ErrorAction SilentlyContinue))
{
try
{
clear-variable hashValue -force
}
catch {}
}
$parameterName = $parameter.Name
if ($parameter.Name -eq "@odata.type" -and $IsGetTargetResource)
{
$parameterName = 'odataType'
}
if ($parameter.IsComplexType)
{
[hashtable]$hashValue = @{}
$propertyType = $workload + $parameter.Type
if ($IsGetTargetResource)
{
$propertyType = "MSFT_$propertyType"
$hashValue.Add('CIMType', $propertyType)
}
if (-not $isRecursive)
{
$IsParentFromAdditionalProperties = $false
if (-not $parameter.IsRootProperty)
{
$IsParentFromAdditionalProperties = $true
}
}
$hashValue.Add('isArray', $parameter.IsArray)
$nestedProperties = @()
if ($null -ne $parameter.Properties)
{
$nestedProperties = Get-M365DSCFakeValues -ParametersInformation $parameter.Properties `
-Workload $Workload `
-isCmdletCall $isCmdletCall `
-isRecursive $true `
-IntroduceDrift $IntroduceDrift `
-IsGetTargetResource $IsGetTargetResource `
-IsParentFromAdditionalProperties $IsParentFromAdditionalProperties
}
$hashValue.Add('Properties', $nestedProperties)
$hashValue.Add('Name', $parameterName)
}
else
{
switch -Wildcard ($parameter.Type)
{
'*.String'
{
[String]$hashValue = ''
$fakeValue = 'FakeStringValue'
if ($parameter.Members)
{
$fakeValue = $parameter.Members[0]
if ($parameter.Name -eq "@odata.type")
{
$fakeValue = "#microsoft.graph." + $parameter.Members[0]
}
}
$hashValue = $fakeValue
if ($parameter.IsArray)
{
[string[]]$hashValue = @($fakeValue)
}
break
}
'*.String[[\]]'
{
$fakeValue1 = 'FakeStringArrayValue1'
$fakeValue2 = 'FakeStringArrayValue2'
if ($parameter.Members)
{
$fakeValue1 = $parameter.Members[0]
$fakeValue2 = $parameter.Members[1]
}
[Array]$hashValue = @($fakeValue1, $fakeValue2)
if ($IntroduceDrift)
{
$hashValue = @($fakeValue1)
}
break
}
'*.Int32'
{
[Int32]$hashValue = 25
if ($IntroduceDrift)
{
$hashValue = 7
}
break
}
'*.Boolean'
{
[Boolean]$hashValue = $true
if ($IntroduceDrift)
{
$hashValue = $false
}
break
}
'*.DateTime'
{
[String]$hashValue = ''
$fakeValue = ([DateTime]"2023-01-01T00:00:00").ToString("$DateFormat")
$hashValue = $fakeValue
break
}
'*.DateTimeOffset'
{
[String]$hashValue = ''
$fakeValue = ([DateTimeOffset]"2023-01-01T00:00:00").ToString("$DateFormat")
$hashValue = $fakeValue
break
}
'*.Time*'
{
[String]$hashValue = ''
$fakeValue = [Datetime]::Parse("00:00:00").TimeOfDay.ToString()
$hashValue = $fakeValue
break
}
}
}
if ($hashValue)
{
if ((-not $parameter.IsRootProperty) -and -not $IsGetTargetResource -and -not $isRecursive)
{
$parameterName = Get-StringFirstCharacterToLower -Value $parameterName
$additionalProperties.Add($parameterName, $hashValue)
}
else
{
if ($IsParentFromAdditionalProperties)
{
$parameterName = Get-StringFirstCharacterToLower -Value $parameterName
}
$result.Add($parameterName, $hashValue)
}
}
}
if (-not [String]::IsNullOrEmpty($AdditionalPropertiesType))
{
$additionalProperties.Add('@odata.type', '#microsoft.graph.' + $AdditionalPropertiesType)
}
if ($additionalProperties.Count -gt 0)
{
$result.Add('AdditionalProperties', $additionalProperties)
}
return $result
}
function Get-M365DSCHashAsString
{
[CmdletBinding()]
[OutputType([System.String])]
param(
[Parameter(Mandatory = $true)]
[System.Collections.Hashtable]
$Values,
[Parameter()]
[System.String]
$Space = ' ',
[Parameter()]
[System.Boolean]
$isCmdletCall = $false
)
$sb = [System.Text.StringBuilder]::New()
$keys = $Values.Keys | Sort-Object -Property $_
foreach ($key in $keys)
{
switch ($Values.$key.GetType().Name)
{
'String'
{
$value = $Values.$key
if ($key -eq '@odata.type')
{
$key = "'$key'"
}
$sb.AppendLine("$Space$key = `"$value`"") | Out-Null
}
'Int32'
{
$sb.AppendLine("$Space$key = $($Values.$key)") | Out-Null
}
'Boolean'
{
$sb.AppendLine("$Space$key = `$$($Values.$key)") | Out-Null
}
'String[]'
{
$stringValue = ''
foreach ($item in $Values.$key)
{
$stringValue += "`"$item`","
}
$stringValue = $stringValue.Substring(0, $stringValue.Length - 1)
$sb.AppendLine("$Space$key = `@($stringValue)") | Out-Null
}
'Hashtable'
{
#read-host -Prompt ($Values.$Key|fl *|out-string)
$extraSpace = ''
$line = "$Space$extraSpace$key = "
if ($Values.$Key.isArray)
{
if ($Values.$Key.CIMType)
{
$line += "[CimInstance[]]"
}
$line += "@(`r$space "
$extraSpace = ' '
}
if ($Values.$Key.CIMType)
{
$line += "(New-CimInstance -ClassName $($Values.$Key.CIMType) -Property "
}
$sb.AppendLine("$line@{") | Out-Null
if ($Values.$Key.Properties)
{
$propLine = ''
foreach ($prop in $Values.$Key.Properties)
{
if ($isCmdletCall -and $prop.contains('odataType'))
{
$prop.Add('@odata.type', $prop.odataType)
$prop.Remove('odataType')
}
$l = (Get-M365DSCHashAsString -Values $prop -Space "$Space$extraSpace " -isCmdletCall $isCmdletCall)
$propLine += $l
}
$sb.Append($propLine) | Out-Null
}
else
{
$sb.Append((Get-M365DSCHashAsString -Values $Values.$key -Space "$Space " -isCmdletCall $isCmdletCall)) | Out-Null
}
$endLine = "$Space$extraSpace}"
if ($Values.$Key.CIMType)
{
$endLine += ' -ClientOnly)'
}
$sb.AppendLine($endLine) | Out-Null
if ($Values.$Key.isArray)
{
$sb.AppendLine("$space)") | Out-Null
}
}
}
}
return $sb.ToString()
}
function Get-M365DSCResourcePermission
{
param (
# Name of the Workload the resource is for.
[Parameter(Mandatory = $true)]
[ValidateSet('ExchangeOnline', 'Intune', `
'SecurityComplianceCenter', 'PnP', 'PowerPlatforms', `
'MicrosoftTeams', 'MicrosoftGraph')]
[System.String]
$Workload,
# CmdLet Noun
[Parameter()]
[System.String]
$CmdLetNoun,
[Parameter()]
[System.String]
$UpdateVerb = 'Update',
[Parameter()]
[ValidateSet('v1.0','beta')]
[System.String]
$APIVersion = 'v1.0'
)
$readPermissionsNames = (Find-MgGraphCommand -Command "Get-$CmdLetNoun" -ApiVersion $ApiVersion| Select-Object -First 1 -ExpandProperty Permissions).Name
$leastReadPermissions = @()
foreach ($permission in $readPermissionsNames)
{
$splitPermission = $permission.Split('.')
if ($splitPermission[1] -eq 'ReadWrite')
{
if ($readPermissionsNames -notcontains "$($splitPermission[0]).Read.$($splitPermission[2])")
{
$leastReadPermissions += $permission
}
}
else
{
$leastReadPermissions += $permission
}
}
$updatePermissionsNames = (Find-MgGraphCommand -Command "$UpdateVerb-$CmdLetNoun" -ApiVersion $ApiVersion | Select-Object -First 1 -ExpandProperty Permissions).Name
switch ($Workload)
{
'Intune'
{
$nodeWorkloadName = 'graph'
}
'MicrosoftGraph'
{
$nodeWorkloadName = 'graph'
}
}
$readPermissions = @()
foreach ($permission in $leastReadPermissions)
{
$readPermissions += @{'name' = $permission }
}
$updatePermissions = @()
foreach ($permission in $updatePermissionsNames)
{
$updatePermissions += @{'name' = $permission }
}
$delegatedPermissions = @{}
$delegatedPermissions.Add('read', $readPermissions)
$delegatedPermissions.Add('update', $updatePermissions)
$applicationPermissions = @{}
$applicationPermissions.Add('read', $readPermissions)
$applicationPermissions.Add('update', $updatePermissions)
$workloadPermissions = @{}
$workloadPermissions.Add('delegated', $delegatedPermissions)
$workloadPermissions.Add('application', $applicationPermissions)
$permissions = @{}
$permissions.Add($nodeWorkloadName, $workloadPermissions)
$return = @{'permissions' = $permissions }
return $return
}
function Get-M365DSCDRGCimInstancesSchemaStringContent
{
param (
[Parameter(Mandatory = $true)]
#[System.Object[]]
[Hashtable]
$CIMInstance,
[Parameter(Mandatory = $true)]
[System.String]
$Workload
)
$stringResult = ''
$cimInstanceType = Get-StringFirstCharacterToUpper -Value $cimInstance.Type
if ($cimInstanceType -notin $Global:AlreadyFoundInstances)
{
$stringResult += "[ClassVersion(`"1.0.0`")]`r`n"
$stringResult += 'class MSFT_' + $Workload + $cimInstanceType + "`r`n"
$stringResult += "{`r`n"
$nestedResults = ''
foreach ($property in $cimInstance.Properties)
{
$newNestedCimToBeAdded = $false
$propertyType = Get-StringFirstCharacterToUpper -Value $property.Type
if ($property.IsComplexType)
{
if ($propertyType -notin $Global:AlreadyFoundInstances)
{
$Global:AlreadyFoundInstances += $cimInstanceType
$newNestedCimToBeAdded = $true
#$Global:AlreadyFoundInstances += $propertyType
$nestedResult = Get-M365DSCDRGCimInstancesSchemaStringContent `
-CIMInstance $property `
-Workload $Workload
}
$stringResult += " [Write, Description(`"$($property.Description)`"), EmbeddedInstance(`"MSFT_$Workload$($propertyType)`")] String $($property.Name)"
if ($property.IsArray)
{
$stringResult += '[]'
}
$stringResult += ";`r`n"
}
else
{
$propertyType = Get-M365DSCDRGParameterTypeForSchema -Type $property.Type
$propertySet = ''
if ($property.IsEnumType)
{
$mySet = ''
foreach ($member in $property.Members)
{
if ($property.Name -eq "@odata.type")
{
$member = "#microsoft.graph." + $member
}
$mySet += "`"" + $member + "`","
}
$mySet = $mySet.Substring(0, $mySet.Length - 1)
$propertySet = ", ValueMap{$mySet}, Values{$mySet}"
}
$propertyName = $property.Name
if ($property.Name -eq "@odata.type")
{
$propertyName = "odataType"
}
$stringResult += " [Write, Description(`"$($property.Description)`")$propertySet] $($propertyType) $($propertyName)"
if ($property.IsArray)
{
$stringResult += '[]'
}
$stringResult += ";`r`n"
}
if ($newNestedCimToBeAdded)
{
$nestedResults += $nestedResult
}
}
$stringResult += "};`r`n"
$stringResult += $nestedResults
if ($cimInstanceType -notin $Global:AlreadyFoundInstances)
{
$Global:AlreadyFoundInstances += $cimInstanceType
}
}
return $stringResult
}
function New-M365SchemaPropertySet
{
param (
[Parameter()]
[Object[]]
$Properties,
[Parameter()]
[System.String]
$Workload
)
$schemaProperties = ''
$Properties | ForEach-Object -Process {
if ($_.Name -ne 'LastModifiedDateTime' -and $_.Name -ne 'CreatedDateTime')
{
if ($_.IsComplexType)
{
$propertyType = $_.Type -replace 'microsoft.graph.powershell.models.', ''
$propertyType = $propertyType -replace 'imicrosoftgraph', ''
$propertyType = $Workload + $propertyType
$propertyType = $propertyType -replace '[[\]]', ''
$schemaProperties += " [Write, Description(`"$($_.Description)`"), EmbeddedInstance(`"MSFT_$propertyType`")] String $($_.Name)"
if ($_.IsArray)
{
$schemaProperties += '[]'
}
$schemaProperties += ";`r`n"
}
else
{
$propertyType = Get-M365DSCDRGParameterTypeForSchema -Type $_.Type
$propertySet = ''
if ($null -ne $_.Members)
{
$mySet = ''
foreach ($member in $_.Members)
{
$mySet += "`"" + $member + "`","
}
$mySet = $mySet.Substring(0, $mySet.Length - 1)
$propertySet = ", ValueMap{$mySet}, Values{$mySet}"
}
$permission = "Write"
if ($_.Name -eq "Id")
{
$permission = "Key"
}
if ($_.Name -eq "DisplayName")
{
$permission = "Required"
}
$schemaProperties += " [$permission, Description(`"$($_.Description)`")$propertySet] $($propertyType) $($_.Name)"
if ($_.IsArray)
{
$schemaProperties += '[]'
}
$schemaProperties += ";`r`n"
}
}
}
return $schemaProperties
}
function Write-TokenReplacement
{
param (
[Parameter()]
[System.String]
$Token,
# Parameter help description
[Parameter()]
[System.String]
$Value,
# Parameter help description
[Parameter()]
[System.String]
$FilePath
)
$content = Get-Content -Path $FilePath
$content = $content.Replace($Token, $Value)
Set-Content -Path $FilePath -Value $content
}
function New-M365DSCResourceFolder
{
param (
[Parameter()]
[System.String]
$ResourceName,
# Parameter help description
[Parameter()]
[System.String]
$Path,
# Parameter help description
[Parameter()]
[Object[]]
$Properties
)
$directoryPath = "$Path\MSFT_$ResourceName"
if (-not(Test-Path $directoryPath))
{
New-Item -Path $directoryPath -ItemType Directory
}
}
function New-M365DSCModuleFile
{
param (
[Parameter()]
[System.String]
$ResourceName,
[Parameter()]
[System.String]
$Path,
[Parameter()]
[System.String]
$Workload = "MicrosoftGraph"
)
$filePath = "$Path\MSFT_$ResourceName\MSFT_$($ResourceName).psm1"
if ($workload -in @('MicrosoftGraph','Intune'))
{
Copy-Item -Path .\Module.Template.psm1 -Destination $filePath -Force
}
else
{
Copy-Item -Path .\Module.Workloads.Template.psm1 -Destination $filePath -Force
}
return $filePath
}
function New-M365DSCExampleFile
{
param(
[Parameter()]
[System.String]
$ResourceName,
[Parameter()]
[System.Management.Automation.PSCredential]
$Credential,
[Parameter()]
[System.String]
$Path
)
$exportPath = Join-Path -Path $env:temp -ChildPath $ResourceName
Export-M365DSCConfiguration `
-Credential $Credential `
-Components $ResourceName `
-Path $exportPath `
-FileName "$ResourceName.ps1" `
-ConfigurationName 'Example' | Out-Null
$exportedFilePath = Join-Path -Path $exportPath -ChildPath "$ResourceName.ps1"
$exportContent = Get-Content $exportedFilePath -Raw
$start = $exportContent.IndexOf("`r`n $ResourceName ")
$end = $exportContent.IndexOf("`r`n }", $start)
$start = $exportContent.IndexOf("{", $start) + 1
$exampleContent = $exportContent.Substring($start, $end - $start)
$exampleFileFullPath = "$Path\$ResourceName\1-$ResourceName-Example.ps1"
$folderPath = "$Path\$ResourceName"
New-Item $folderPath -ItemType Directory -Force | Out-Null
$templatePath = '.\Example.Template.ps1'
Copy-Item -Path $templatePath -Destination $exampleFileFullPath -Force
Write-TokenReplacement -Token '<FakeValues>' -Value $exampleContent -FilePath $exampleFileFullPath
Write-TokenReplacement -Token '<ResourceName>' -Value $ResourceName -FilePath $exampleFileFullPath
}
function New-M365DSCUnitTest
{
param (
[Parameter()]
[System.String]
$ResourceName,
[Parameter()]
[System.String]
$Path
)
$filePath = "$Path\Microsoft365DSC.$($ResourceName).Tests.ps1"
Copy-Item -Path .\UnitTest.Template.ps1 -Destination $filePath
return $filePath
}
function New-M365DSCSchemaFile
{
param (
[Parameter()]
[System.String]
$ResourceName,
[Parameter()]
[System.String]
$Path,
[Parameter()]
[System.String]
$Workload = 'MicrosoftGraph'
)
$filePath = "$Path\MSFT_$ResourceName\MSFT_$($ResourceName).schema.mof"
if ($Workload -in @('MicrosoftGraph','Intune'))
{
Copy-Item -Path .\Schema.Template.mof -Destination $filePath
}
else
{
Copy-Item -Path .\Schema.Workloads.Template.mof -Destination $filePath
}
return $filePath
}
function New-M365DSCSettingsFile
{
param (
[Parameter()]
[System.String]
$ResourceName,
[Parameter()]
[System.String]
$Path
)
$filePath = "$Path\MSFT_$ResourceName\settings.json"
Copy-Item -Path .\settings.template.json -Destination $filePath
return $filePath
}
function New-M365DSCReadmeFile
{
param (
[Parameter()]
[System.String]
$ResourceName,
[Parameter()]
[System.String]
$Path
)
$filePath = "$Path\MSFT_$ResourceName\readme.md"
Copy-Item -Path .\readme.template.md -Destination $filePath
return $filePath
}
function Get-ComplexTypeMapping
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param (
[Parameter()]
$Property,
[Parameter()]
[System.String]
$Workload
)
$complexMapping = @()
$propertyType = Get-StringFirstCharacterToUpper -Value $Property.Type
$isRequired = $false
if ($property.Description -like "* Required.*")
{
$isRequired = $true
}
$map = @{
Name = $Property.Name
CimInstanceName = $Workload+ $PropertyType
IsRequired = $isRequired
}
$complexMapping += $map
foreach ($nestedProperty in $property.Properties)
{
if ($nestedProperty.IsComplexType)
{
$complexMapping += Get-ComplexTypeMapping -Property $nestedProperty -Workload $Workload
}
}
return $complexMapping
}
function New-M365HashTableMapping
{
[CmdletBinding()]
[OutputType([System.Collections.Hashtable])]
param (
[Parameter()]
[Object[]]
$Properties,
[Parameter()]
[System.String]
$GraphNoun,
[Parameter()]
[System.String]
$Workload,
[Parameter()]
[System.String]
$DateFormat,
# Parameter help description
[Parameter()]
[System.Object]
$DefaultParameterSetProperties
)
$newCmdlet = Get-Command "New-$GraphNoun"
$results = @{}
$hashtable = ''
$complexTypeContent = ''
$convertToString = ''
$convertToVariable = ''
$additionalProperties = ''
$complexTypeConstructor = [System.Text.StringBuilder]::New()
$enumTypeConstructor = [System.Text.StringBuilder]::New()
$dateTypeConstructor = [System.Text.StringBuilder]::New()
$timeTypeConstructor = [System.Text.StringBuilder]::New()
$biggestParameterLength = 'CertificateThumbprint'.Length
foreach ($property in $properties.Name)
{
If ($property.Length -gt $biggestParameterLength)
{
$biggestParameterLength = $property.Length
}
}
foreach ($property in $properties)
{
$cmdletParameter = $DefaultParameterSetProperties | Where-Object -FilterScript { $_.Name -eq $property.Name }
if ($null -eq $cmdletParameter)
{
$UseAdditionalProperties = $true
}
if ($property.Name -ne 'CreatedDateTime' -and $property.Name -ne 'LastModifiedDateTime')
{
$paramType = $property.Type
$parameterName = $property.Name
if ($property.IsComplexType)
{
$CimInstanceName = $paramType -replace 'Microsoft.Graph.PowerShell.Models.IMicrosoftGraph', ''
$CimInstanceName = $CimInstanceName -replace '[[\]]', ''
$CimInstanceName = $Workload + $CimInstanceName
$global:ComplexList = @()
$complexTypeConstructor.AppendLine((Get-ComplexTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat))
$global:ComplexList = $null
[Array]$complexMapping = Get-ComplexTypeMapping -Property $property -Workload $Workload
$complexMappingString = [System.Text.StringBuilder]::New()
if ($complexMapping.Count -gt 1)
{
$complexMappingString.AppendLine(" `$complexMapping = @(") | Out-Null
foreach ($map in $complexMapping)
{
$complexMappingString.AppendLine(" @{") | Out-Null
$complexMappingString.AppendLine(" Name = '" + $map.Name + "'") | Out-Null
$complexMappingString.AppendLine(" CimInstanceName = '" + $map.CimInstanceName + "'") | Out-Null
$complexMappingString.AppendLine(" IsRequired = `$" + $map.IsRequired.ToString()) | Out-Null
$complexMappingString.AppendLine(" }") | Out-Null
}
$complexMappingString.AppendLine(" )") | Out-Null
}
$convertToString += " if (`$null -ne `$Results.$parameterName)`r`n"
$convertToString += " {`r`n"
if (-not ([String]::IsNullOrEmpty($complexMappingString.ToString())))
{
$convertToString += $complexMappingString.ToString()
}
$convertToString += " `$complexTypeStringResult = Get-M365DSCDRGComplexTypeToString ```r`n"
$convertToString += " -ComplexObject `$Results.$parameterName ```r`n"
$convertToString += " -CIMInstanceName '$CimInstanceName'"
if (-not ([String]::IsNullOrEmpty($complexMappingString.ToString())))
{
$convertToString += " ```r`n"
$convertToString += " -ComplexTypeMapping `$complexMapping`r`n"
}
$convertToString += "`r`n"
$convertToString += " if (-not [String]::IsNullOrWhiteSpace(`$complexTypeStringResult))`r`n"
$convertToString += " {`r`n"
$convertToString += " `$Results.$parameterName = `$complexTypeStringResult`r`n"
$convertToString += " }`r`n"
$convertToString += " else`r`n"
$convertToString += " {`r`n"
$convertToString += " `$Results.Remove('$parameterName') | Out-Null`r`n"
$convertToString += " }`r`n"
$convertToString += " }`r`n"
$convertToVariable += " if (`$Results.$parameterName)`r`n"
$convertToVariable += " {`r`n"
$convertToVariable += " `$currentDSCBlock = Convert-DSCStringParamToVariable -DSCBlock `$currentDSCBlock -ParameterName `"$parameterName`" -IsCIMArray:`$$($property.IsArray)`r`n"
$convertToVariable += " }`r`n"
}
if ($property.IsEnumType)
{
$enumTypeConstructor.AppendLine((Get-EnumTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat))
}
if ($property.Type -like "System.Date*")
{
$dateTypeConstructor.AppendLine((Get-DateTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat))
}
if ($property.Type -like "System.Time*")
{
$timeTypeConstructor.AppendLine((Get-TimeTypeConstructorToString -Property $property -IndentCount 2 -DateFormat $DateFormat))
}
$spacing = $biggestParameterLength - $property.Name.Length
$propertyName = Get-StringFirstCharacterToUpper -Value $property.Name
$hashtable += " $($parameterName + (' ' * $spacing) ) = "
if ($property.IsComplexType)
{
$hashtable += "`$complex$propertyName`r`n"
}
elseif ($property.Type -like "System.Date*")
{
$hashtable += "`$date$propertyName`r`n"
}
elseif ($property.Type -like "System.Time*")
{
$hashtable += "`$time$propertyName`r`n"
}
elseif ($property.IsEnumType)
{
$hashtable += "`$enum$propertyName`r`n"
}
else
{
$propertyPrefix = "`$getValue."
if ($property.IsRootProperty -eq $false)
{
$propertyName = Get-StringFirstCharacterToLower -Value $property.Name
$propertyPrefix += "AdditionalProperties."
}
$hashtable += "$propertyPrefix$propertyName"
$hashtable += "`r`n"
}
}
}
$defaultKeys = @(
'Ensure'
'Credential'
'ApplicationId'
'TenantId'
'ApplicationSecret'
'CertificateThumbprint'
'ManagedIdentity'
)
foreach ($key in $defaultKeys)
{
$keyValue = "`$$key"
if ($key -eq 'Ensure')
{
$keyValue = "'Present'"
}
if ($key -eq 'ManagedIdentity')
{
$keyValue = '$ManagedIdentity.IsPresent'
}
$spacing = $biggestParameterLength - $key.Length
$hashtable += " $($key + ' ' * $spacing) = $keyValue`r`n"
}
$results.Add('ConvertToVariable', $convertToVariable)
$results.Add('ComplexTypeConstructor', $complexTypeConstructor.ToString())
$results.Add('EnumTypeConstructor', $enumTypeConstructor.ToString())
$results.Add('DateTypeConstructor', $dateTypeConstructor.ToString())
$results.Add('TimeTypeConstructor', $timeTypeConstructor.ToString())
$results.Add('additionalProperties', $additionalProperties)
$results.Add('ConvertToString', $convertToString)
$results.Add('StringContent', $hashtable)
$results.Add('ComplexTypeContent', $complexTypeContent)
return $results
}
function Get-ParameterBlockStringForModule
{
param (
[Parameter()]
[Object[]]
$ParameterBlockInformation
)
$parameterBlockOutput = ''
$ParameterBlockInformation | ForEach-Object -Process {
if ($_.Name -ne 'LastModifiedDateTime' -and $_.Name -ne 'CreatedDateTime')
{
$parameterBlockOutput += " $($_.Attribute)`r`n"
if ($null -ne $_.Members)
{
$validateSet = '[ValidateSet('
foreach ($member in $_.Members)
{
$validateSet += "'" + $member + "',"
}
$validateSet = $validateSet.Substring(0, $validateSet.Length - 1)
$validateSet += ')]'
$parameterBlockOutput += " $($ValidateSet)`r`n"
}
$propertyType = $_.Type
if ($_.IsComplexType)
{
$parameterBlockOutput += ' [Microsoft.Management.Infrastructure.CimInstance'
}
elseif ($propertyType.ToLower() -eq 'system.management.automation.switchparameter')
{
$parameterBlockOutput += ' [System.Boolean'
}
elseif ($propertyType.ToLower() -like 'system.date*')
{
$parameterBlockOutput += ' [System.String'
}
elseif ($propertyType.ToLower() -like 'system.binary*')
{
$parameterBlockOutput += ' [System.String'
}
else
{
$parameterBlockOutput += " [$($_.Type.Replace('[]',''))"
}
if ($_.IsArray)
{
$parameterBlockOutput += '[]'
}
$parameterBlockOutput += "]`r`n"
$parameterBlockOutput += " `$$($_.Name),`r`n"
$parameterBlockOutput += "`r`n"
}
}
return $parameterBlockOutput
}
function Get-ResourceStub
{
param (
[Parameter()]
[System.String]
$CmdletNoun
)
$parametersToSkip = @(
'InformationVariable'
'WhatIf'
'WarningVariable'
'OutVariable'
'ErrorVariable'
'WarningAction'
'ErrorAction'
'Debug'
'Verbose'
'IfMatch'
'OutBuffer'
'InformationAction'
'PipelineVariable'
)
$stub = [System.Text.StringBuilder]::New()
$version = (Get-Command -Noun $cmdletNoun | Select-Object -Unique Version | Sort-Object -Descending | Select-Object -First 1).Version.ToString()
$commands = Get-Command -Noun $cmdletNoun | Where-Object -FilterScript { $_.Version -eq $version }
foreach ($command in $commands)
{
$command= get-Command -Name $command.Name | Where-Object -FilterScript { $_.Version -eq $version }
$stub.AppendLine("function $($command.Name)") | Out-Null
$stub.AppendLine("{") | Out-Null
$stub.AppendLine(" [CmdletBinding()]") | Out-Null
$stub.AppendLine(" param") | Out-Null
$stub.AppendLine(" (") | Out-Null
$parameters = $command.Parameters
$i = 0
$keys= ($parameters.Keys) | Where-Object -FilterScript { $_ -notin $parametersToSkip }
$keyCount = $keys.Count
foreach ($key in $keys)
{
$stub.AppendLine(" [Parameter()]") | Out-Null
$name = ($parameters.$key).Name
$type = ($parameters.$key).ParameterType.ToString()
$isArray = $false
if ($type -like "*[[\]]")
{
$isArray = $true
}
if ($type -notlike "System.*")
{
$type = "PSObject"
if ($isArray)
{
$type += "[]"
}
}
$stub.AppendLine(" [$type]") | Out-Null
$stub.Append(" `$$name") | Out-Null
if ($i -lt $keyCount -1)
{
$stub.Append(",`r`n") | Out-Null
}
$stub.Append("`r`n") | Out-Null
$i++
}
$stub.AppendLine(" )") | Out-Null
$stub.AppendLine("}`r`n") | Out-Null
}
$stub.ToString()
}
function Update-Microsoft365StubFile
{
param (
[Parameter()]
[System.String]
$CmdletNoun
)
try
{
$M365DSCTestFolder = Join-Path -Path $PSScriptRoot `
-ChildPath "..\Tests\Unit" `
-Resolve
$filePath = (Join-Path -Path $M365DSCTestFolder `
-ChildPath "\Stubs\Microsoft365.psm1" `
-Resolve)
$content = Get-Content -Path $FilePath
if (($content | Select-String -Pattern "function Get-$CmdletNoun$").Count -eq 0)
{
$content += "#region $CmdletNoun`r`n" + (Get-ResourceStub -CmdletNoun $CmdletNoun) + "#endregion`r`n"
Set-Content -Path $FilePath -Value $content
}
}
catch
{
New-M365DSCLogEntry -Message 'Error Updating Stub File:' `
-Exception $_ `
-Source $($MyInvocation.MyCommand.Source)
Write-Error $_
}
}
function Get-SettingsCatalogSettingDefinitionValueDefinition {
param(
[Parameter(Mandatory = $true)]
$SettingDefinition,
[Parameter(Mandatory = $true)]
[System.String]
$SettingDefinitionOdataTypeBase
)
if (-not $SettingDefinition.AdditionalProperties.valueDefinition) {
return $null
}
$description = ""
$type = $SettingDefinition.AdditionalProperties.valueDefinition.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValueDefinition", "")
switch ($type) {
"String" {
$max = $SettingDefinition.AdditionalProperties.valueDefinition.maximumLength
$min = $SettingDefinition.AdditionalProperties.valueDefinition.minimumLength
$description = "Length must be between $min and $max characters."
} "Integer" {
$max = $SettingDefinition.AdditionalProperties.valueDefinition.maximumValue
$min = $SettingDefinition.AdditionalProperties.valueDefinition.minimumValue
$description = "Value must be between $min and $max."
}
}
return @{
Max = $max
Min = $min
Description = $description
Type = $type
}
}
function Get-SettingsCatalogSettingDefinitionValueOption {
param(
[Parameter(Mandatory = $true)]
$SettingDefinition,
[Parameter(Mandatory = $true)]
[System.String]
$SettingDefinitionOdataTypeBase
)
$options = @()
foreach ($option in $SettingDefinition.AdditionalProperties.options) {
$options += @{
Name = $option.name
Id = $option.itemId.Split("_")[-1]
Type = $option.optionValue.'@odata.type'.Replace($SettingDefinitionOdataTypeBase, "").Replace("SettingValue", "")
DisplayName = $option.displayName
}
}
$options
}
function Get-SettingsCatalogSettingDefinitionDefaultValue {
param(
[Parameter(Mandatory = $true)]
$SettingDefinition,
[Parameter(Mandatory = $true)]
[System.String]
$SettingDefinitionOdataTypeBase
)
$type = Get-SettingsCatalogSettingDefinitionValueType -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $SettingDefinitionOdataTypeBase
# Either they are a "simple" setting or a "choice" setting
# If they are a simple setting, they have a default value
if ($type -like "Simple*") {
# There might be a default value specified in the setting definition
$value = $SettingDefinition.AdditionalProperties.defaultValue.value
$nullOrEmpty = [String]::IsNullOrEmpty($value)
# If the value is not null or empty, return the value, otherwise return the default value for the type
switch ($type) {
"String" { if (-not $nullOrEmpty) { $value } else { "" } }
"Integer" { if (-not $nullOrEmpty) { [System.Int32]::Parse($value) } else { 0 } }
# The secret value will require an update at a later date. Currently no use case found for this.
"Secret" { if (-not $nullOrEmpty) { $value } else { "" } }
default { $value }
}
} else {
# If the setting is a choice setting, the default value is the default option id
if (-not [String]::IsNullOrEmpty($SettingDefinition.AdditionalProperties.defaultOptionId)) {
$SettingDefinition.AdditionalProperties.defaultOptionId.Split("_")[-1]
} else {
$null
}
}
}
function Get-SettingsCatalogSettingDefinitionValueType {
param(
[Parameter(Mandatory = $true)]
$SettingDefinition,
[Parameter(Mandatory = $true)]
[System.String]
$SettingDefinitionOdataTypeBase
)
# Type can be Choice, Simple or *Collection
$type = $SettingDefinition.AdditionalProperties.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("Setting", "").Replace("Definition", "")
if ($type -eq 'Simple') {
$type += $SettingDefinition.AdditionalProperties.valueDefinition.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValueDefinition", "")
} elseif ($type -eq 'SimpleCollection') {
if ($null -ne $SettingDefinition.AdditionalProperties.defaultValue) {
$type = $type.Replace("Collection", $SettingDefinition.AdditionalProperties.defaultValue.'@odata.type'.Replace($settingDefinitionOdataTypeBase, "").Replace("SettingValue", "") + "Collection")
} else {
$type = $type.Replace("Collection", "StringCollection")
}
} elseif ($type -eq 'ChoiceCollection') {
$valueType = $SettingDefinition.AdditionalProperties.options[0].optionValue.'@odata.type'.Replace("#microsoft.graph.deviceManagementConfiguration", "").Replace("SettingValue", "")
$type = $type.Replace("Collection", $valueType + "Collection")
} else {
# Type is GroupCollection and does not have a default value to narrow down the type
# but we can check the maximum count to determine if it is a collection or not
if ($SettingDefinition.AdditionalProperties.maximumCount -gt 1) {
$type += 'Collection'
}
}
return $type
}
function New-SettingsCatalogSettingDefinitionSettingsFromTemplate {
param(
[Parameter(Mandatory = $true)]
$SettingTemplate,
[Parameter(ParameterSetName = "ParseRoot")]
[Parameter(ParameterSetName = "ParseChild")]
[System.String]
$SettingDefinitionIdPrefix,
[Parameter(ParameterSetName = "ParseChild")]
$SettingDefinition,
[Parameter(ParameterSetName = "ParseRoot")]
[System.Array]
$RootSettingDefinitions,
[Parameter(ParameterSetName = "Start")]
[switch] $FromRoot,
[Parameter(Mandatory = $true)]
[System.Array]
$AllSettingDefinitions,
[Parameter(ParameterSetName = "ParseChild")]
[System.String]$ParentInstanceName,
[Parameter(ParameterSetName = "ParseChild")]
[System.Int32]$Level = 0
)
$settingDefinitionOdataTypeBase = "#microsoft.graph.deviceManagementConfiguration"
if ($FromRoot) {
$RootSettingDefinitions = $SettingTemplate.SettingDefinitions | Where-Object -FilterScript {
$_.Id -eq $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId -and `
($_.AdditionalProperties.dependentOn.Count -eq 0 -and $_.AdditionalProperties.options.dependentOn.Count -eq 0)
}
$settingDefinitionIdPrefix = $SettingTemplate.SettingInstanceTemplate.SettingDefinitionId
return New-SettingsCatalogSettingDefinitionSettingsFromTemplate `
-SettingTemplate $SettingTemplate `
-RootSettingDefinitions $RootSettingDefinitions `
-SettingDefinitionIdPrefix $settingDefinitionIdPrefix `
-AllSettingDefinitions $AllSettingDefinitions
}
if ($PSCmdlet.ParameterSetName -eq "ParseRoot") {
$settings = @()
foreach ($RootSettingDefinition in $RootSettingDefinitions) {
$settings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate `
-SettingTemplate $SettingTemplate `
-SettingDefinition $RootSettingDefinition `
-SettingDefinitionIdPrefix $settingDefinitionIdPrefix `
-Level 1 `
-ParentInstanceName "MSFT_MicrosoftGraphIntuneSettingsCatalog" `
-AllSettingDefinitions $AllSettingDefinitions
}
return $settings
}
$type = Get-SettingsCatalogSettingDefinitionValueType -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase
$defaultValue = Get-SettingsCatalogSettingDefinitionDefaultValue -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase
$options = Get-SettingsCatalogSettingDefinitionValueOption -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase
$valueRestriction = Get-SettingsCatalogSettingDefinitionValueDefinition -SettingDefinition $SettingDefinition -SettingDefinitionOdataTypeBase $settingDefinitionOdataTypeBase
$settingName = Get-SettingsCatalogSettingName -SettingDefinition $SettingDefinition -AllSettingDefinitions $AllSettingDefinitions
$childSettings = @()
$childSettings += $SettingTemplate.SettingDefinitions | Where-Object -FilterScript {
$_.visibility -notlike "*none*" -and
(($_.AdditionalProperties.dependentOn.Count -gt 0 -and $_.AdditionalProperties.dependentOn.parentSettingId -contains $SettingDefinition.Id) -or
($_.AdditionalProperties.options.dependentOn.Count -gt 0 -and $_.AdditionalProperties.options.dependentOn.parentSettingId -contains $SettingDefinition.Id))
}
$instanceName = "MSFT_MicrosoftGraphIntuneSettingsCatalog"
if (($Level -gt 1 -and $type -like "GroupCollection*" -and $childSettings.Count -gt 1) -or
($Level -eq 1 -and $type -like "GroupCollection*" -and $childSettings.Count -ge 1 -and $childSettings.AdditionalProperties.'@odata.type' -notcontains "#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition"))
{
$instanceName = $ParentInstanceName + $settingName
}
$innerChildSettings = @()
foreach ($childSetting in $childSettings) {
$innerChildSettings += New-SettingsCatalogSettingDefinitionSettingsFromTemplate `
-SettingTemplate $SettingTemplate `
-SettingDefinition $childSetting `
-SettingDefinitionIdPrefix $SettingDefinitionIdPrefix `
-Level $($Level + 1) `
-ParentInstanceName $instanceName `
-AllSettingDefinitions $AllSettingDefinitions
}
$setting = [ordered]@{
Name = $settingName
DisplayName = $SettingDefinition.DisplayName
Type = $type
DefaultValue = $defaultValue
Options = $options
ValueRestriction = $valueRestriction
InstanceName = $instanceName
ChildSettings = $innerChildSettings
}
if ($type -eq "GroupCollectionCollection" -and $childSettings.Count -eq 1 -and $SettingDefinition.AdditionalProperties.maximumCount -eq 1)
{
# Reset type and make child setting a collection
$setting.Type = "GroupCollection"
$setting.ChildSettings[0].Type += "Collection"
}
$setting
}
function New-ParameterDefinitionFromSettingsCatalogTemplateSetting {
param(
[Parameter(Mandatory = $true)]
$TemplateSetting
)
$mofTypeMapping = @{
"Choice" = "String"
"ChoiceIntegerCollection" = "SInt32"
"ChoiceStringCollection" = "String"
"SimpleString" = "String"
"String" = "String"
"SimpleInteger" = "SInt32"
"Integer" = "SInt32"
"Boolean" = "Boolean"
"SimpleStringCollection" = "String"
"SimpleIntegerCollection" = "SInt32"
}
$powerShellTypeMapping = @{
"Choice" = "System.String"
"ChoiceIntegerCollection" = "System.Int32[]"
"ChoiceStringCollection" = "System.String[]"
"SimpleString" = "System.String"
"String" = "System.String"
"SimpleInteger" = "System.Int32"
"Integer" = "System.Int32"
"Boolean" = "System.Boolean"
"DateTime" = "System.DateTime"
"GroupCollection" = "Microsoft.Management.Infrastructure.CimInstance"
"GroupCollectionCollection" = "Microsoft.Management.Infrastructure.CimInstance[]"
"SimpleStringCollection" = "System.String[]"
"SimpleIntegerCollection" = "System.Int32[]"
}
$mofInstanceTemplate = @"
[ClassVersion("1.0.0.0")]
class <ClassName>
{
<MofParameterTemplate>};
"@
$mofParameterTemplate = " [Write, Description(""<DisplayName><Options><EmbeddedInstance>"")<ValueMap>] <Type> <Name><Collection>;"
$powerShellParameterTemplate = @"
[Parameter()]<Restriction>
[<Type>]
$<Name>
"@
$mofDefinition = $mofParameterTemplate.Replace("<DisplayName>", $TemplateSetting.DisplayName.Replace("`r`n", ""))
$optionsString = ""
$valueMapString = ""
if ($TemplateSetting.Options) {
$options = @()
$values = @()
$TemplateSetting.Options | ForEach-Object {
$options += "$($_.Id)" + ": " + $_.Name.Replace("""", "'")
$values += """$($_.Id)"""
}
$optionsString = " (" + ($options -join ", ") + ")"
$valueMapString = ", ValueMap{$($values -join ", ")}, Values{$($values -join ", ")}"
}
$mofDefinition = $mofDefinition.Replace("<Options>", $optionsString)
$mofDefinition = $mofDefinition.Replace("<ValueMap>", $valueMapString)
if ($TemplateSetting.InstanceName -ne "MSFT_MicrosoftGraphIntuneSettingsCatalog") {
$mofDefinition = $mofDefinition.Replace("<EmbeddedInstance>", """), EmbeddedInstance(""$($TemplateSetting.InstanceName)")
$mofDefinition = $mofDefinition.Replace("<Type>", "String")
} else {
$mofDefinition = $mofDefinition.Replace("<Type>", $mofTypeMapping[$TemplateSetting.Type])
$mofDefinition = $mofDefinition.Replace("<EmbeddedInstance>", "")
}
$mofDefinition = $mofDefinition.Replace("<Name>", $TemplateSetting.Name)
$isCollection = ($TemplateSetting.Type -like "*Collection" -and $TemplateSetting.Type -ne "GroupCollection") -or $TemplateSetting.Type -eq "GroupCollectionCollection"
$mofDefinition = $mofDefinition.Replace("<Collection>", $( if ($isCollection) { "[]" } else { "" } ))
$powerShellDefinition = $powerShellParameterTemplate.Replace("<Name>", $TemplateSetting.Name)
$powerShellDefinition = $powerShellDefinition.Replace("<Type>", $powerShellTypeMapping[$TemplateSetting.Type])
$restriction = ''
if ($null -ne $TemplateSetting.ValueRestriction) {
if ($TemplateSetting.ValueRestriction.Type -like "*String") {
$restriction = " [ValidateLength($($TemplateSetting.ValueRestriction.Min), $($TemplateSetting.ValueRestriction.Max))]"
} elseif ($TemplateSetting.ValueRestriction.Type -like "*Integer") {
$restriction = " [ValidateRange($($TemplateSetting.ValueRestriction.Min), $($TemplateSetting.ValueRestriction.Max))]"
}
}
if ($null -ne $TemplateSetting.Options) {
$restriction = " [ValidateSet('$($TemplateSetting.Options.Id -join "', '")')]"
}
$powerShellDefinition = $powerShellDefinition.Replace("<Restriction>", $( if ($restriction) { "`n $restriction" } else { "" }))
$definition = @{}
if ($TemplateSetting.Type -notlike "GroupCollection*" -or $TemplateSetting.InstanceName -ne "MSFT_MicrosoftGraphIntuneSettingsCatalog") {
$definition.Add("MOF", @($mofDefinition))
$definition.Add("PowerShell", @($powerShellDefinition))
}
$childDefinitions = @()
foreach ($childSetting in $TemplateSetting.ChildSettings) {
$childDefinitions += New-ParameterDefinitionFromSettingsCatalogTemplateSetting -TemplateSetting $childSetting
}
if ($TemplateSetting.Type -like "GroupCollection*" -and $TemplateSetting.InstanceName -ne "MSFT_MicrosoftGraphIntuneSettingsCatalog") {
$mofInstanceDefinition = $mofInstanceTemplate.Replace("<ClassName>", $TemplateSetting.InstanceName)
$mofInstanceDefinition = $mofInstanceDefinition.Replace("<MofParameterTemplate>", $($childDefinitions.MOF | Out-String))
$definition.Add("MOFInstance", @($mofInstanceDefinition))
$definition.MOFInstance += $childDefinitions.MOFInstance
} else {
if ($null -ne $childDefinitions.MOFInstance) {
$definition.MOFInstance += $childDefinitions.MOFInstance
}
if ($null -ne $childDefinitions.MOF) {
$definition.MOF += $childDefinitions.MOF
}
if ($null -ne $childDefinitions.PowerShell) {
$definition.PowerShell += $childDefinitions.PowerShell
}
}
$definition
}