@@ -61,140 +61,179 @@ function Compare-CIPPIntuneObject {
6161 $excludeProps = $defaultExcludeProperties + $ExcludeProperties
6262
6363 # Create a list to store comparison results
64- $compareProperties = [System.Collections.Generic.List [PSObject ]]::new()
65-
66- # Clean up objects by removing excluded properties
67- $obj1 = $ReferenceObject | Select-Object * - ExcludeProperty @ ($excludeProps | ForEach-Object { $_ })
68- $obj2 = $DifferenceObject | Select-Object * - ExcludeProperty @ ($excludeProps | ForEach-Object { $_ })
64+ $result = [System.Collections.Generic.List [PSObject ]]::new()
6965
70- # Skip OData properties and excluded properties
71- $skipProps = [System.Collections.Generic.List [string ]]::new()
72- foreach ($propName in ($obj1.PSObject.Properties | Select-Object Name).Name) {
73- if ($propName -like ' *@OData*' -or $propName -like ' #microsoft.graph*' -or $excludeProps -contains $propName ) {
74- $skipProps.Add ($propName )
75- }
66+ # Helper function to check if a property should be skipped
67+ function ShouldSkipProperty {
68+ param (
69+ [string ]$PropertyName
70+ )
71+ return ($PropertyName -like ' *@OData*' -or
72+ $PropertyName -like ' #microsoft.graph*' -or
73+ $excludeProps -contains $PropertyName )
7674 }
7775
78- # Define core properties to compare first
79- $coreProps = @ (' displayName' , ' Description' , ' Id' )
80- $postProps = @ (' Advertisements' )
81- $skipPropertiesToCompare = @ ()
76+ # Recursive function to compare objects deeply
77+ function Compare-ObjectsRecursively {
78+ param (
79+ [Parameter (Mandatory = $true )]
80+ $Object1 ,
8281
83- # Compare core properties
84- foreach ($propName in $coreProps ) {
85- if (-not ($obj1.PSObject.Properties | Where-Object Name -EQ $propName )) {
86- continue
87- }
88- $val1 = ($obj1 .$propName | ConvertTo-Json - Depth 10 )
89- $val2 = ($obj2 .$propName | ConvertTo-Json - Depth 10 )
90-
91- $value1 = if ($null -eq $val1 ) { ' ' } else { $val1.ToString ().Trim(' "' ) }
92- $value2 = if ($null -eq $val2 ) { ' ' } else { $val2.ToString ().Trim(' "' ) }
82+ [Parameter (Mandatory = $true )]
83+ $Object2 ,
9384
94- $match = ($value1 -eq $value2 )
85+ [Parameter (Mandatory = $false )]
86+ [string ]$PropertyPath = " "
87+ )
9588
96- if (-not $match ) {
97- $compareProperties.Add ([PSCustomObject ]@ {
98- PropertyName = $propName
99- Object1Value = $value1
100- Object2Value = $value2
101- Match = $match
102- })
89+ # If both objects are null or empty, they're equal
90+ if (($null -eq $Object1 -or $Object1 -eq ' ' ) -and ($null -eq $Object2 -or $Object2 -eq ' ' )) {
91+ return
10392 }
104- }
105-
106- # Compare all other properties
107- $addedProps = [System.Collections.Generic.List [string ]]::new()
108- foreach ($propName in ($obj1.PSObject.Properties | Select-Object Name).Name) {
109- if ($propName -in $coreProps ) { continue }
110- if ($propName -in $postProps ) { continue }
111- if ($propName -in $skipProps ) { continue }
112-
113- if ($propName -like ' *@OData*' -or $propName -like ' #microsoft.graph*' ) { continue }
11493
115- $addedProps.Add ($propName )
116- $val1 = ($obj1 .$propName | ConvertTo-Json - Depth 10 )
117- $val2 = ($obj2 .$propName | ConvertTo-Json - Depth 10 )
118-
119- $value1 = if ($null -eq $val1 ) { ' ' } else { $val1.ToString ().Trim(' "' ) }
120- $value2 = if ($null -eq $val2 ) { ' ' } else { $val2.ToString ().Trim(' "' ) }
121-
122- $match = ($value1 -eq $value2 )
94+ # If one object is null but the other isn't, they're different
95+ if (($null -eq $Object1 -or $Object1 -eq ' ' ) -xor ($null -eq $Object2 -or $Object2 -eq ' ' )) {
96+ $result.Add ([PSCustomObject ]@ {
97+ Property = $PropertyPath
98+ ExpectedValue = if ($null -eq $Object1 ) { ' ' } else { $Object1 }
99+ ReceivedValue = if ($null -eq $Object2 ) { ' ' } else { $Object2 }
100+ })
101+ return
102+ }
123103
124- if (-not $match ) {
125- $compareProperties.Add ([PSCustomObject ]@ {
126- PropertyName = $propName
127- Object1Value = $value1
128- Object2Value = $value2
129- Match = $match
130- })
104+ # If objects are of different types, they're different
105+ if ($Object1.GetType () -ne $Object2.GetType ()) {
106+ $result.Add ([PSCustomObject ]@ {
107+ Property = $PropertyPath
108+ ExpectedValue = $Object1
109+ ReceivedValue = $Object2
110+ })
111+ return
131112 }
132- }
133113
134- # Check for properties in obj2 that aren't in obj1
135- foreach ($propName in ($obj2.PSObject.Properties | Select-Object Name).Name) {
136- if ($propName -in $coreProps ) { continue }
137- if ($propName -in $postProps ) { continue }
138- if ($propName -in $skipProps ) { continue }
139- if ($propName -in $addedProps ) { continue }
114+ # Handle different object types
115+ if ($Object1 -is [System.Collections.IDictionary ]) {
116+ # Compare dictionaries
117+ $allKeys = @ ($Object1.Keys ) + @ ($Object2.Keys ) | Select-Object - Unique
140118
141- if ($propName -like ' *@OData*' -or $propName -like ' #microsoft.graph*' ) { continue }
119+ foreach ($key in $allKeys ) {
120+ if (ShouldSkipProperty - PropertyName $key ) { continue }
142121
143- $val1 = ($obj1 .$propName | ConvertTo-Json - Depth 10 )
144- $val2 = ($obj2 .$propName | ConvertTo-Json - Depth 10 )
122+ $newPath = if ($PropertyPath ) { " $PropertyPath .$key " } else { $key }
145123
146- $value1 = if ($null -eq $val1 ) { ' ' } else { $val1.ToString ().Trim(' "' ) }
147- $value2 = if ($null -eq $val2 ) { ' ' } else { $val2.ToString ().Trim(' "' ) }
124+ if ($Object1.ContainsKey ($key ) -and $Object2.ContainsKey ($key )) {
125+ Compare-ObjectsRecursively - Object1 $Object1 [$key ] - Object2 $Object2 [$key ] - PropertyPath $newPath
126+ }
127+ elseif ($Object1.ContainsKey ($key )) {
128+ $result.Add ([PSCustomObject ]@ {
129+ Property = $newPath
130+ ExpectedValue = $Object1 [$key ]
131+ ReceivedValue = ' '
132+ })
133+ }
134+ else {
135+ $result.Add ([PSCustomObject ]@ {
136+ Property = $newPath
137+ ExpectedValue = ' '
138+ ReceivedValue = $Object2 [$key ]
139+ })
140+ }
141+ }
142+ }
143+ elseif ($Object1 -is [Array ] -or $Object1 -is [System.Collections.IList ]) {
144+ # Compare arrays
145+ $maxLength = [Math ]::Max($Object1.Count , $Object2.Count )
148146
149- $match = ($value1 -eq $value2 )
147+ for ($i = 0 ; $i -lt $maxLength ; $i ++ ) {
148+ $newPath = " $PropertyPath .$i "
150149
151- if (-not $match ) {
152- $compareProperties.Add ([PSCustomObject ]@ {
153- PropertyName = $propName
154- Object1Value = $value1
155- Object2Value = $value2
156- Match = $match
150+ if ($i -lt $Object1.Count -and $i -lt $Object2.Count ) {
151+ Compare-ObjectsRecursively - Object1 $Object1 [$i ] - Object2 $Object2 [$i ] - PropertyPath $newPath
152+ }
153+ elseif ($i -lt $Object1.Count ) {
154+ $result.Add ([PSCustomObject ]@ {
155+ Property = $newPath
156+ ExpectedValue = $Object1 [$i ]
157+ ReceivedValue = ' '
158+ })
159+ }
160+ else {
161+ $result.Add ([PSCustomObject ]@ {
162+ Property = $newPath
163+ ExpectedValue = ' '
164+ ReceivedValue = $Object2 [$i ]
165+ })
166+ }
167+ }
168+ }
169+ elseif ($Object1 -is [PSCustomObject ] -or $Object1.PSObject.Properties.Count -gt 0 ) {
170+ # Compare PSCustomObjects or objects with properties
171+ $allPropertyNames = @ (
172+ $Object1.PSObject.Properties | Select-Object - ExpandProperty Name
173+ $Object2.PSObject.Properties | Select-Object - ExpandProperty Name
174+ ) | Select-Object - Unique
175+
176+ foreach ($propName in $allPropertyNames ) {
177+ if (ShouldSkipProperty - PropertyName $propName ) { continue }
178+
179+ $newPath = if ($PropertyPath ) { " $PropertyPath .$propName " } else { $propName }
180+ $prop1Exists = $Object1.PSObject.Properties.Name -contains $propName
181+ $prop2Exists = $Object2.PSObject.Properties.Name -contains $propName
182+
183+ if ($prop1Exists -and $prop2Exists ) {
184+ Compare-ObjectsRecursively - Object1 $Object1 .$propName - Object2 $Object2 .$propName - PropertyPath $newPath
185+ }
186+ elseif ($prop1Exists ) {
187+ $result.Add ([PSCustomObject ]@ {
188+ Property = $newPath
189+ ExpectedValue = $Object1 .$propName
190+ ReceivedValue = ' '
191+ })
192+ }
193+ else {
194+ $result.Add ([PSCustomObject ]@ {
195+ Property = $newPath
196+ ExpectedValue = ' '
197+ ReceivedValue = $Object2 .$propName
198+ })
199+ }
200+ }
201+ }
202+ else {
203+ # Compare primitive values
204+ $val1 = $Object1.ToString ()
205+ $val2 = $Object2.ToString ()
206+
207+ if ($val1 -ne $val2 ) {
208+ $result.Add ([PSCustomObject ]@ {
209+ Property = $PropertyPath
210+ ExpectedValue = $val1
211+ ReceivedValue = $val2
157212 })
213+ }
158214 }
159215 }
160216
161- # Compare post properties (like Advertisements)
162- foreach ($propName in $postProps ) {
163- if (-not ($obj1.PSObject.Properties | Where-Object Name -EQ $propName )) {
164- continue
165- }
166- $val1 = ($obj1 .$propName | ConvertTo-Json - Depth 10 )
167- $val2 = ($obj2 .$propName | ConvertTo-Json - Depth 10 )
168-
169- $value1 = if ($null -eq $val1 ) { ' ' } else { $val1.ToString ().Trim(' "' ) }
170- $value2 = if ($null -eq $val2 ) { ' ' } else { $val2.ToString ().Trim(' "' ) }
171-
172- $match = ($value1 -eq $value2 )
217+ # Convert objects to PowerShell objects if they're not already
218+ $obj1 = if ($ReferenceObject -is [string ]) {
219+ $ReferenceObject | ConvertFrom-Json - AsHashtable - Depth 100
220+ } else {
221+ $ReferenceObject
222+ }
173223
174- if (-not $match ) {
175- $compareProperties.Add ([PSCustomObject ]@ {
176- PropertyName = $propName
177- Object1Value = $value1
178- Object2Value = $value2
179- Match = $match
180- })
181- }
224+ $obj2 = if ($DifferenceObject -is [string ]) {
225+ $DifferenceObject | ConvertFrom-Json - AsHashtable - Depth 100
226+ } else {
227+ $DifferenceObject
182228 }
183229
230+ # Start the recursive comparison
231+ Compare-ObjectsRecursively - Object1 $obj1 - Object2 $obj2
232+
184233 # If no differences found, return null
185- if ($compareProperties .Count -eq 0 ) {
234+ if ($result .Count -eq 0 ) {
186235 return $null
187236 }
188-
189- # Convert to a more user-friendly format
190- $result = [System.Collections.Generic.List [PSObject ]]::new()
191- foreach ($diff in $compareProperties ) {
192- $result.Add ([PSCustomObject ]@ {
193- Property = $diff.PropertyName
194- ExpectedValue = $diff.Object1Value
195- ReceivedValue = $diff.Object2Value
196- })
197- }
198237 } else {
199238 $intuneCollection = Get-Content .\intuneCollection.json | ConvertFrom-Json - ErrorAction SilentlyContinue
200239
0 commit comments