Skip to content

Commit 472c74a

Browse files
authored
Merge pull request #164 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents bc881cf + 63e559d commit 472c74a

30 files changed

+257
-243
lines changed

Modules/CIPPCore/Public/Authentication/Test-CIPPAccess.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ function Test-CIPPAccess {
115115
}
116116

117117
if ($APIAllowed) {
118-
$TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter ?? $env:TenantID
118+
$TenantFilter = $Request.Query.tenantFilter ?? $Request.Body.tenantFilter ?? $Request.Query.tenantId ?? $Request.Body.tenantId ?? $env:TenantID
119119
# Check tenant level access
120120
if (($Role.BlockedTenants | Measure-Object).Count -eq 0 -and $Role.AllowedTenants -contains 'AllTenants') {
121121
$TenantAllowed = $true

Modules/CIPPCore/Public/Compare-CIPPIntuneObject.ps1

Lines changed: 147 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Modules/CIPPCore/Public/Entrypoints/HTTP Functions/CIPP/Scheduler/Invoke-ListScheduledItems.ps1

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ Function Invoke-ListScheduledItems {
6363
if ($Task.Recurrence -eq 0 -or [string]::IsNullOrEmpty($Task.Recurrence)) {
6464
$Task.Recurrence = 'Once'
6565
}
66+
try {
67+
$Task.ExecutedTime = [DateTimeOffset]::FromUnixTimeSeconds($Task.ExecutedTime).UtcDateTime
68+
} catch {
69+
$Task.ExecutedTime = [DateTime]::MinValue
70+
}
71+
try {
72+
$Task.ScheduledTime = [DateTimeOffset]::FromUnixTimeSeconds($Task.ScheduledTime).UtcDateTime
73+
} catch {
74+
$Task.ScheduledTime = [DateTime]::MinValue
75+
}
6676
$Task
6777
}
6878

Modules/CIPPCore/Public/New-CIPPAlertTemplate.ps1

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,14 @@ function New-CIPPAlertTemplate {
2929
}
3030
if ($InputObject -eq 'standards') {
3131
$DataHTML = foreach ($object in $data) {
32-
"<p>For the standard $($object.standardName) in template {{Template Name }} we've detected the following:</p> <li>$($object.message)</li>"
32+
"<p>For the standard $($object.standardName) we've detected the following:</p> <li>$($object.message)</li>"
3333
if ($object.object) {
3434
$StandardObject = $object.object | ConvertFrom-Json
35-
$StandardObject = $newobject | Select-Object * -ExcludeProperty Etag, PartitionKey, TimeStamp
35+
$StandardObject = $StandardObject | Select-Object * -ExcludeProperty Etag, PartitionKey, TimeStamp
3636
if ($StandardObject.compare) {
3737
'<p>The following differences have been detected:</p>'
3838
($StandardObject.compare | ConvertTo-Html -Fragment | Out-String).Replace('<table>', ' <table class="table-modern">')
3939
} else {
40-
'<p>This is a table representation of the current settings:</p>'
4140
($StandardObject | ConvertTo-Html -Fragment -As List | Out-String).Replace('<table>', ' <table class="table-modern">')
4241
}
4342
}

Modules/CIPPCore/Public/New-CIPPOneDriveShortCut.ps1

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ function New-CIPPOneDriveShortCut {
1414
$SiteInfo = New-GraphGetRequest -uri 'https://graph.microsoft.com/beta/sites/' -tenantid $TenantFilter -asapp $true | Where-Object -Property weburl -EQ $url
1515
$ListItemUniqueId = (New-GraphGetRequest -uri "https://graph.microsoft.com/beta/sites/$($siteInfo.id)/drive?`$select=SharepointIds" -tenantid $TenantFilter -asapp $true).SharePointIds
1616
$body = [PSCustomObject]@{
17-
#remove any item from the name that is not allowed in a file name
18-
name = $SiteInfo.displayName -replace '[^a-zA-Z0-9\.\-]', ''
17+
name = 'Documents'
1918
remoteItem = @{
2019
sharepointIds = @{
2120
listId = $($ListItemUniqueId.listid)

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAddDKIM.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ function Invoke-CIPPStandardAddDKIM {
107107
}
108108

109109
if ($Settings.report -eq $true) {
110-
$DKIMState = if ($null -eq $NewDomains -and $null -eq $SetDomains) { $true } else { $false }
110+
$DKIMState = if ($null -eq $NewDomains -and $null -eq $SetDomains) { $true } else { $SetDomains, $NewDomains }
111111
Set-CIPPStandardsCompareField -FieldName 'standards.AddDKIM' -FieldValue $DKIMState -TenantFilter $tenant
112112
Add-CIPPBPAField -FieldName 'DKIM' -FieldValue $DKIMState -StoreAs bool -Tenant $tenant
113113
}

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardAppDeploy.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function Invoke-CIPPStandardAppDeploy {
6969
}
7070

7171
if ($Settings.report -eq $true) {
72-
$StateIsCorrect = $MissingApps.Count -eq 0 ? $true : @{appids = $MissingApps -join ',' }
72+
$StateIsCorrect = $MissingApps.Count -eq 0 ? $true : @{ 'Missing Apps' = $MissingApps -join ',' }
7373
Set-CIPPStandardsCompareField -FieldName 'standards.AppDeploy' -FieldValue $StateIsCorrect -TenantFilter $tenant
7474
Add-CIPPBPAField -FieldName 'AppDeploy' -FieldValue $StateIsCorrect -StoreAs bool -Tenant $tenant
7575
}

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableReshare.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ function Invoke-CIPPStandardDisableReshare {
6161
}
6262

6363
if ($Settings.report -eq $true) {
64-
Set-CIPPStandardsCompareField -FieldName 'standards.DisableReshare' -FieldValue $CurrentInfo.isResharingByExternalUsersEnabled -TenantFilter $Tenant
64+
$state = $CurrentInfo.isResharingByExternalUsersEnabled ? ($CurrentInfo | Select-Object isResharingByExternalUsersEnabled) : $true
65+
Set-CIPPStandardsCompareField -FieldName 'standards.DisableReshare' -FieldValue $state -TenantFilter $Tenant
6566
Add-CIPPBPAField -FieldName 'DisableReshare' -FieldValue $CurrentInfo.isResharingByExternalUsersEnabled -StoreAs bool -Tenant $tenant
6667
}
6768
}

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSecurityGroupUsers.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ function Invoke-CIPPStandardDisableSecurityGroupUsers {
5959
}
6060

6161
if ($Settings.report -eq $true) {
62-
Set-CIPPStandardsCompareField -FieldName 'standards.DisableSecurityGroupUsers' -FieldValue $CurrentInfo.defaultUserRolePermissions.allowedToCreateSecurityGroups -Tenant $tenant
62+
$state = $CurrentInfo.defaultUserRolePermissions.allowedToCreateSecurityGroups -eq $false ? $true : ($currentInfo.defaultUserRolePermissions | Select-Object allowedToCreateSecurityGroups)
63+
Set-CIPPStandardsCompareField -FieldName 'standards.DisableSecurityGroupUsers' -FieldValue $state -Tenant $tenant
6364
Add-CIPPBPAField -FieldName 'DisableSecurityGroupUsers' -FieldValue $CurrentInfo.defaultUserRolePermissions.allowedToCreateSecurityGroups -StoreAs bool -Tenant $tenant
6465
}
6566
}

Modules/CIPPCore/Public/Standards/Invoke-CIPPStandardDisableSharePointLegacyAuth.ps1

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ function Invoke-CIPPStandardDisableSharePointLegacyAuth {
6262
}
6363
}
6464
if ($Settings.report -eq $true) {
65-
Set-CIPPStandardsCompareField -FieldName 'standards.DisableSharePointLegacyAuth' -FieldValue $CurrentInfo.isLegacyAuthProtocolsEnabled -TenantFilter $Tenant
65+
$state = $CurrentInfo.isLegacyAuthProtocolsEnabled ? ($CurrentInfo | Select-Object isLegacyAuthProtocolsEnabled) : $true
66+
Set-CIPPStandardsCompareField -FieldName 'standards.DisableSharePointLegacyAuth' -FieldValue $state -TenantFilter $Tenant
6667
Add-CIPPBPAField -FieldName 'SharePointLegacyAuthEnabled' -FieldValue $CurrentInfo.isLegacyAuthProtocolsEnabled -StoreAs bool -Tenant $tenant
6768
}
6869
}

0 commit comments

Comments
 (0)