From 3e20acf5215af4243f970c513044360957bd0d2d Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Thu, 5 Dec 2024 18:06:19 +0100 Subject: [PATCH] Restrict nested object creation and generation --- CHANGELOG.md | 5 + .../Modules/M365DSCDRGUtil.psm1 | 34 +++++- .../M365DSCResourceGenerator.psm1 | 112 ++++++++++++------ 3 files changed, 107 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c605e0b348..f8c56ca5b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ # UNRELEASED +* M365DSCDRGUtil + * Improve settings catalog handling for nested objects. +* M365DSCResourceGenerator + * Fixes an issue with nested object creation. + # 1.24.1204.1 * All resources diff --git a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 index d7b2a9be5a..2858541d08 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCDRGUtil.psm1 @@ -831,7 +831,11 @@ function Convert-M365DSCDRGComplexTypeToHashtable [Parameter()] [switch] - $SingleLevel + $SingleLevel, + + [Parameter()] + [switch] + $ExcludeUnchangedProperties ) if ($null -eq $ComplexObject) @@ -854,6 +858,24 @@ function Convert-M365DSCDRGComplexTypeToHashtable #However, an array can be preserved on return by prepending it with the array construction operator (,) return , [hashtable[]]$results } + + if ($SingleLevel) + { + $returnObject = @{} + $keys = $ComplexObject.CimInstanceProperties | Where-Object -FilterScript { $_.Name -ne 'PSComputerName' } + foreach ($key in $keys) + { + if ($ExcludeUnchangedProperties -and -not $key.IsValueModified) + { + continue + } + $propertyName = $key.Name[0].ToString().ToLower() + $key.Name.Substring(1, $key.Name.Length - 1) + $propertyValue = $ComplexObject.$($key.Name) + $returnObject.Add($propertyName, $propertyValue) + } + return [hashtable]$returnObject + } + $hashComplexObject = Get-M365DSCDRGComplexTypeToHashtable -ComplexObject $ComplexObject if ($null -ne $hashComplexObject) @@ -1656,8 +1678,8 @@ function Get-IntuneSettingCatalogPolicySetting $userSettingTemplates = $SettingTemplates | Where-object -FilterScript { $_.SettingInstanceTemplate.SettingDefinitionId.StartsWith("user_") } - $deviceDscParams = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.DeviceSettings -SingleLevel - $userDscParams = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.UserSettings -SingleLevel + $deviceDscParams = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.DeviceSettings -SingleLevel -ExcludeUnchangedProperties + $userDscParams = Convert-M365DSCDRGComplexTypeToHashtable -ComplexObject $DSCParams.UserSettings -SingleLevel -ExcludeUnchangedProperties $combinedSettingInstances = @() $combinedSettingInstances += Get-IntuneSettingCatalogPolicySetting -DSCParams $deviceDscParams -SettingTemplates $deviceSettingTemplates $combinedSettingInstances += Get-IntuneSettingCatalogPolicySetting -DSCParams $userDscParams -SettingTemplates $userSettingTemplates @@ -1692,8 +1714,8 @@ function Get-IntuneSettingCatalogPolicySetting } $settingValueName = $settingType.Replace('#microsoft.graph.deviceManagementConfiguration', '').Replace('Instance', 'Value') $settingValueName = $settingValueName.Substring(0, 1).ToLower() + $settingValueName.Substring(1, $settingValueName.length - 1 ) - $settingValueType = $settingInstanceTemplate.AdditionalProperties."$($settingValueName)Template".'@odata.type' - if ($null -ne $settingValueType) + [string]$settingValueType = $settingInstanceTemplate.AdditionalProperties."$($settingValueName)Template".'@odata.type' + if (-not [System.String]::IsNullOrEmpty($settingValueType)) { $settingValueType = $settingValueType.Replace('ValueTemplate', 'Value') } @@ -1838,7 +1860,7 @@ function Get-IntuneSettingCatalogPolicySettingInstanceValue $DSCParams = @{ $cimDSCParamsName = if ($instanceCount -eq 1) { $newDSCParams.$cimDSCParamsName[0] } else { $newDSCParams.$cimDSCParamsName } } - $AllSettingDefinitions = $groupSettingCollectionDefinitionChildren + $AllSettingDefinitions = $groupSettingCollectionDefinitionChildren + $SettingDefinition } for ($i = 0; $i -lt $instanceCount; $i++) diff --git a/ResourceGenerator/M365DSCResourceGenerator.psm1 b/ResourceGenerator/M365DSCResourceGenerator.psm1 index c23fd156db..f89162869b 100644 --- a/ResourceGenerator/M365DSCResourceGenerator.psm1 +++ b/ResourceGenerator/M365DSCResourceGenerator.psm1 @@ -388,42 +388,7 @@ $($userDefinitionSettings.MOF -join "`r`n") { $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." + $parameterInformation += Get-ComplexParameter -Parameter $parameterName -CimInstance $definitionSettings.MOFInstance -ResourceName $ResourceName } 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." @@ -1375,6 +1340,77 @@ class MSFT_DeviceManagementConfigurationPolicyAssignments } } +function Get-ComplexParameter { + param ( + [Parameter(Mandatory = $true)] + [System.String] + $Parameter, + + [Parameter(Mandatory = $true)] + [System.String] + $CimInstance, + + [Parameter(Mandatory = $true)] + [System.String] + $ResourceName + ) + + $parameterType = 'IntuneSettingsCatalog' + $Parameter + $(if ($Parameter -in @('DeviceSettings', 'UserSettings')) { "_$ResourceName" }) + $filteredCimInstance = $CimInstance | Where-Object -FilterScript { $_ -like "*$parameterType`n*" -or $_ -like "*$parameterType`r`n*" } + $splittedCimInstance = $filteredCimInstance.Split("`n") + $rowFilter = '\[.*;' + $startRow = for ($i = 0; $i -lt $splittedCimInstance.Count; $i++) { + if ($splittedCimInstance[$i] -like "*$parameterType*") + { + $i + break + } + } + $endRow = for ($i = $startRow; $i -lt $splittedCimInstance.Count; $i++) { + if ($splittedCimInstance[$i] -like "*};*") + { + $i + break + } + } + + $cimInstanceOfInterest = $splittedCimInstance[$startRow..$endRow] + $cimRows = [regex]::Matches($cimInstanceOfInterest -join "`n", $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("', '').Split(' ')[0].Replace('")]', '') + $props.Properties = (Get-ComplexParameter -Parameter $props.Name -CimInstance $CimInstance -ResourceName $ResourceName).Properties + } + $props + } + } + @{ + 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." +} + function Get-MgGraphModuleCmdLetDifference { $modules = Get-Module -Name Microsoft.Graph.* -ListAvailable | Sort-Object -Property Name, Version | Out-GridView -PassThru @@ -3933,8 +3969,8 @@ function New-SettingsCatalogSettingDefinitionSettingsFromTemplate { } $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")) + if (($Level -gt 1 -and $type -like "GroupCollection*" -and $childSettings.Count -gt 1) -or + ($Level -eq 1 -and $type -eq "GroupCollectionCollection" -and $childSettings.Count -ge 1 -and $childSettings.AdditionalProperties.'@odata.type' -notcontains "#microsoft.graph.deviceManagementConfigurationSettingGroupCollectionDefinition")) { $instanceName = $ParentInstanceName + $settingName }