From d8e620ab8df155e606817aea48624fa5d2f4a9ef Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 5 Jan 2024 16:46:59 +0100 Subject: [PATCH 1/3] Fix nested change detection in CIMInstance --- .../Modules/M365DSCReport.psm1 | 260 +++++++++--------- 1 file changed, 132 insertions(+), 128 deletions(-) diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 index 7330466d83..97a8412f20 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 @@ -722,83 +722,85 @@ function Compare-M365DSCConfigurations { [string]$key = Get-M365DSCCimInstanceKey -CIMInstance $instance - if ($null -ne $key) - { - $destinationResourceInstances = $destinationResource.$destinationPropertyName | Where-Object -FilterScript {$_."$key" -eq $instance."$key"} + $destinationResourceInstances = $destinationResource.$destinationPropertyName | Where-Object -FilterScript {$_."$key" -eq $instance."$key"} - if ($null -ne $destinationResourceInstances) + if ($null -ne $destinationResourceInstances) + { + # There is a chance we found 2 instances of a CIMInstance based on its key property. + # If that's the case, loop through each instance found and if at least one of them is + # a perfect match, then don't consider this a drift. + $foundOneMatch = $false + $drift = $null + foreach ($destinationResourceInstance in $destinationResourceInstances) { - # There is a chance we found 2 instances of a CIMInstance based on its key property. - # If that's the case, loop through each instance found and if at least of of them is - # a perfect match, then don't consider this a drift. - $foundOneMatch = $false - $drift = $null - foreach ($destinationResourceInstance in $destinationResourceInstances) + $foundResourceMatch = $true + [array]$driftProperties = @() + foreach ($property in $instance.Keys) { - $foundResourceMatch = $true - foreach ($property in $instance.Keys) + if ($null -eq $destinationResourceInstance."$property" -or $null -ne (Compare-Object -ReferenceObject ($instance."$property")` + -DifferenceObject ($destinationResourceInstance."$property"))) { - if ($null -eq $destinationResourceInstance."$property" -or $null -ne (Compare-Object -ReferenceObject ($instance."$property")` - -DifferenceObject ($destinationResourceInstance."$property"))) - { - $drift = @{ - ResourceName = $sourceResource.ResourceName - ResourceInstanceName = $destinationResource.ResourceInstanceName - Key = $propertyName - KeyValue = $instance."$key" - Properties = @(@{ - ParameterName = $property - CIMInstanceKey = $key - CIMInstanceValue = $instance."$Key" - ValueInSource = $instance."$property" - ValueInDestination = $destinationResourceInstance."$property" - }) - } - $foundResourceMatch = $false + $driftProperties += @{ + ParameterName = $property + CIMInstanceKey = $key + CIMInstanceValue = $instance."$Key" + ValueInSource = $instance."$property" + ValueInDestination = $destinationResourceInstance."$property" } - } - if ($foundResourceMatch) - { - $foundOneMatch = $true + $foundResourceMatch = $false } } - if ($foundOneMatch) + if ($foundResourceMatch) { - # If a match was found, clear the drift. - $drift = $null + $foundOneMatch = $true } else { - $Delta += , $drift - $drift = $null + $drift = @{ + ResourceName = $sourceResource.ResourceName + ResourceInstanceName = $destinationResource.ResourceInstanceName + Key = $propertyName + KeyValue = $instance."$key" + Properties = $driftProperties + } } } + if ($foundOneMatch) + { + # If a match was found, clear the drift. + $drift = $null + } else { - # We have detected a drift where the CIM Instance exists in the Source but NOT in the Destination - $drift = @{ - ResourceName = $sourceResource.ResourceName - ResourceInstanceName = $destinationResource.ResourceInstanceName - Key = $propertyName - KeyValue = $instance."$key" - Properties = @(@{ - ParameterName = $propertyName - CIMInstanceKey = $key - CIMInstanceValue = $instance."$Key" - ValueInSource = $instance - ValueInDestination = $null - }) - } - if ($null -ne $drift) - { - $Delta += , $drift - $drift = $null - } + $Delta += , $drift + $drift = $null + } + } + else + { + # We have detected a drift where the CIM Instance exists in the Source but NOT in the Destination + $drift = @{ + ResourceName = $sourceResource.ResourceName + ResourceInstanceName = $destinationResource.ResourceInstanceName + Key = $propertyName + KeyValue = $instance."$key" + Properties = @(@{ + ParameterName = $propertyName + CIMInstanceKey = $key + CIMInstanceValue = $instance."$Key" + ValueInSource = $instance + ValueInDestination = $null + }) + } + if ($null -ne $drift) + { + $Delta += , $drift + $drift = $null } } } } - # Needs to be a separate nested if statement otherwise the ReferenceObject an be null and it will error out; + # Needs to be a separate nested if statement otherwise the ReferenceObject can be null and it will error out; elseif ($destinationResource.ContainsKey($destinationPropertyName) -eq $false -or (-not [System.String]::IsNullOrEmpty($propertyName) -and $null -ne (Compare-Object -ReferenceObject ($sourceResource.$propertyName)` -DifferenceObject ($destinationResource.$destinationPropertyName))) -and @@ -853,8 +855,8 @@ function Compare-M365DSCConfigurations } } - # Do the scan the other way around because there's a chance that the property, if null, wasn't part of the source - # object. By scanning against the destination we will catch properties that are not null on the source but not null in destination; + # Do the scan the other way around because there's a chance that the property, if null, wasn't part of the source object. + # By scanning against the destination we will catch properties that are not null on the source but not null in destination; foreach ($propertyName in $destinationResource.Keys) { if ($propertyName -notin $filteredProperties) @@ -871,89 +873,91 @@ function Compare-M365DSCConfigurations { [string]$key = Get-M365DSCCimInstanceKey -CIMInstance $instance - if ($null -ne $key) - { - $sourceResourceInstances = $sourceResource.$sourcePropertyName | Where-Object -FilterScript {$_."$key" -eq $instance."$key"} + $sourceResourceInstances = $sourceResource.$sourcePropertyName | Where-Object -FilterScript {$_."$key" -eq $instance."$key"} - if ($null -ne $sourceResourceInstances) + if ($null -ne $sourceResourceInstances) + { + # There is a chance we found 2 instances of a CIMInstance based on its key property. + # If that's the case, loop through each instance found and if at least one of them is + # a perfect match, then don't consider this a drift. + $foundOneMatch = $false + $drift = $null + foreach ($sourceResourceInstance in $sourceResourceInstances) { - # There is a chance we found 2 instances of a CIMInstance based on its key property. - # If that's the case, loop through each instance found and if at least of of them is - # a perfect match, then don't consider this a drift. - $foundOneMatch = $false - $drift = $null - foreach ($sourceResourceInstance in $sourceResourceInstances) + $innerDrift = $null + foreach ($property in $instance.Keys) { - foreach ($property in $instance.Keys) + if ($null -eq $sourceResourceInstance."$property" -or $null -ne (Compare-Object -ReferenceObject ($instance."$property")` + -DifferenceObject ($sourceResourceInstance."$property"))) { - if ($null -eq $sourceResourceInstance."$property" -or $null -ne (Compare-Object -ReferenceObject ($instance."$property")` - -DifferenceObject ($sourceResourceInstance."$property"))) + # Make sure we haven't already added this drift in the delta return object to prevent duplicates. + $existing = $delta | Where-Object -FilterScript {$_.ResourceName -eq $destinationResource.ResourceName -and ` + $_.ResourceInstanceName -eq $destinationResource.ResourceInstanceName} + + $sameEntry = $null + if ($null -ne $existing) { - # Make sure we haven't already added this drift in the delta return object to prevent duplicates. - $existing = $delta | Where-Object -FilterScript {$_.ResourceName -eq $destinationResource.ResourceName -and ` - $_.ResourceInstanceName -eq $destinationResource.ResourceInstanceName} - - $sameEntry = $null - if ($null -ne $existing) - { - $sameEntry = $existing.Properties | Where-Object -FilterScript {$_.ParameterName -eq $property -and ` - $_.CIMInstanceKey -eq $key -and ` - $_.CIMInstanceValue -eq ($instance."$key") -and ` - $_.ValueInSource -eq $sourceResourceInstance."$property" -and ` - $_.ValueInDestination -eq $instance."$property"} - } + $sameEntry = $existing.Properties | Where-Object -FilterScript {$_.ParameterName -eq $property -and ` + $_.CIMInstanceKey -eq $key -and ` + $_.CIMInstanceValue -eq ($instance."$key") -and ` + $_.ValueInSource -eq $sourceResourceInstance."$property" -and ` + $_.ValueInDestination -eq $instance."$property"} + } - if ($null -eq $sameEntry) - { - $drift = @{ - ResourceName = $destinationResource.ResourceName - ResourceInstanceName = $destinationResource.ResourceInstanceName - Key = $propertyName - KeyValue = $instance."$key" - Properties = @(@{ - ParameterName = $property - CIMInstanceKey = $key - CIMInstanceValue = $instance."$Key" - ValueInSource = $sourceResourceInstance."$property" - ValueInDestination = $instance."$property" - }) - } + if ($null -eq $sameEntry) + { + $innerDrift = @{ + ResourceName = $destinationResource.ResourceName + ResourceInstanceName = $destinationResource.ResourceInstanceName + Key = $propertyName + KeyValue = $instance."$key" + Properties = @(@{ + ParameterName = $property + CIMInstanceKey = $key + CIMInstanceValue = $instance."$Key" + ValueInSource = $sourceResourceInstance."$property" + ValueInDestination = $instance."$property" + }) } } } - if ($null -eq $drift) - { - $foundOneMatch = $true - } } - if ($foundOneMatch) + if ($null -eq $innerDrift) { - # If a match was found, clear the drift. - $drift = $null + $foundOneMatch = $true } - } - else - { - # We have detected a drift where the CIM Instance exists in the Destination but NOT in the Source - $drift = @{ - ResourceName = $destinationResource.ResourceName - ResourceInstanceName = $destinationResource.ResourceInstanceName - Key = $propertyName - KeyValue = $instance."$key" - Properties = @(@{ - ParameterName = $propertyName - CIMInstanceKey = $key - CIMInstanceValue = $instance."$Key" - ValueInSource = $null - ValueInDestination = $instance - }) - } - if ($null -ne $drift) + else { - $Delta += , $drift - $drift = $null + $drift = $innerDrift } } + if ($foundOneMatch) + { + # If a match was found, clear the drift. + $drift = $null + } + } + else + { + # We have detected a drift where the CIM Instance exists in the Destination but NOT in the Source + $drift = @{ + ResourceName = $destinationResource.ResourceName + ResourceInstanceName = $destinationResource.ResourceInstanceName + Key = $propertyName + KeyValue = $instance."$key" + Properties = @(@{ + ParameterName = $propertyName + CIMInstanceKey = $key + CIMInstanceValue = $instance."$Key" + ValueInSource = $null + ValueInDestination = $instance + }) + } + if ($null -ne $drift) + { + $Delta += , $drift + $drift = $null + } } } } From 71295a4c6993e21d060d2ab105920fc77b73a816 Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Fri, 5 Jan 2024 16:47:54 +0100 Subject: [PATCH 2/3] Fix enrollment platform restriction comparison during report creation --- CHANGELOG.md | 6 ++++++ Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80c14b376f..e461866fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Change log for Microsoft365DSC +# UNRELEASED + +* M365DSCReport + * Fix nested change detection for CIMInstances + * Fix IntuneDeviceEnrolllmentPlatformRestriction comparison in report + # 1.24.110.1 * AADAdministrativeUnit diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 index 97a8412f20..3fabb2eff1 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 @@ -1155,6 +1155,10 @@ function Get-M365DSCResourceKey { return @('Id') } + if ($Resource.ResourceName -eq 'IntuneDeviceEnrollmentPlatformRestriction' -and $Resource.Keys.Where({ $_ -like "*Restriction"})) + { + return @('ResourceInstanceName') + } if ($Resource.ResourceName -eq 'TeamsChannel' -and -not [System.String]::IsNullOrEmpty($Resource.TeamName)) { # Teams Channel displaynames are not tenant-unique (e.g. "General" is almost in every team), but should be unique per team From f5fa6f429fd9f028755b12e5ed7227a592d551bf Mon Sep 17 00:00:00 2001 From: Fabien Tschanz Date: Tue, 6 Feb 2024 20:08:20 +0100 Subject: [PATCH 3/3] Fix nested array resource comparison --- CHANGELOG.md | 1 + Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25e04b1dc7..ee57b6ed24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * M365DSCReport * Fix nested change detection for CIMInstances * Fix IntuneDeviceEnrolllmentPlatformRestriction comparison in report + FIXES [#4291](https://github.com/microsoft/Microsoft365DSC/issues/4291) # 1.24.131.2 diff --git a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 index 3fabb2eff1..db573948a1 100644 --- a/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 +++ b/Modules/Microsoft365DSC/Modules/M365DSCReport.psm1 @@ -726,10 +726,11 @@ function Compare-M365DSCConfigurations if ($null -ne $destinationResourceInstances) { - # There is a chance we found 2 instances of a CIMInstance based on its key property. + # There is a chance we found multiple instances of a CIMInstance based on its key property. # If that's the case, loop through each instance found and if at least one of them is # a perfect match, then don't consider this a drift. $foundOneMatch = $false + $foundMatchResource = $null $drift = $null foreach ($destinationResourceInstance in $destinationResourceInstances) { @@ -753,6 +754,7 @@ function Compare-M365DSCConfigurations if ($foundResourceMatch) { $foundOneMatch = $true + $foundMatchResource = $destinationResourceInstance } else { @@ -769,6 +771,7 @@ function Compare-M365DSCConfigurations { # If a match was found, clear the drift. $drift = $null + $destinationResource.$destinationPropertyName = $destinationResource.$destinationPropertyName | Where-Object { $_ -ne $foundMatchResource } } else {