Skip to content

Commit 3cdc94a

Browse files
Merge pull request #36 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 08bd618 + 9da444e commit 3cdc94a

189 files changed

Lines changed: 4865 additions & 1551 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Config/schemaDefinitions.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[
2+
{
3+
"id": "cippUser",
4+
"description": "CIPP User Schema",
5+
"targetTypes": ["User"],
6+
"properties": [
7+
{ "name": "jitAdminEnabled", "type": "Boolean" },
8+
{ "name": "jitAdminExpiration", "type": "DateTime" },
9+
{ "name": "mailboxType", "type": "String" },
10+
{ "name": "archiveEnabled", "type": "Boolean" },
11+
{ "name": "autoExpandingArchiveEnabled", "type": "Boolean" },
12+
{ "name": "perUserMfaState", "type": "String" }
13+
],
14+
"status": "Available"
15+
}
16+
]

ConversionTable.csv

Lines changed: 222 additions & 0 deletions
Large diffs are not rendered by default.

Modules/CIPPCore/Public/Authentication/Get-CippApiClient.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function Get-CippApiClient {
1818
if ($AppId) {
1919
$Table.Filter = "RowKey eq '$AppId'"
2020
}
21-
$Apps = Get-CIPPAzDataTableEntity @Table
21+
$Apps = Get-CIPPAzDataTableEntity @Table | Where-Object { ![string]::IsNullOrEmpty($_.RowKey) }
2222
$Apps = foreach ($Client in $Apps) {
2323
$Client = $Client | Select-Object -Property @{Name = 'ClientId'; Expression = { $_.RowKey } }, AppName, Role, IPRange, Enabled
2424

Modules/CIPPCore/Public/Authentication/New-CIPPAPIConfig.ps1

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ function New-CIPPAPIConfig {
99
[string]$AppId
1010
)
1111

12+
$Permissions = Get-GraphToken -tenantid $env:TenantID -scope 'https://graph.microsoft.com/.default' -AsApp $true -SkipCache $true -ReturnRefresh $true
13+
$Token = Read-JwtAccessDetails -Token $Permissions.access_token
14+
$Permissions = $Token.Roles | Where-Object { $_ -match 'Application.ReadWrite.All' -or $_ -match 'Directory.ReadWrite.All' }
15+
if (!$Permissions -or $Permissions.Count -lt 2) {
16+
Write-LogMessage -headers $Headers -API $APINAME -tenant 'None '-message 'Insufficient permissions to create API App' -Sev 'Error'
17+
throw 'Insufficient permissions to create API App. This integration requires the following Application permissions in the partner tenant. Application.ReadWrite.All, Directory.ReadWrite.All'
18+
}
19+
1220
try {
1321
if ($AppId) {
1422
$APIApp = New-GraphGetRequest -uri "https://graph.microsoft.com/v1.0/applications(appid='$($AppId)')" -NoAuthCheck $true

Modules/CIPPCore/Public/Authentication/Set-CippApiAuth.ps1

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
function Set-CippApiAuth {
22
[CmdletBinding(SupportsShouldProcess)]
3-
Param(
3+
param(
44
[string]$RGName,
55
[string]$FunctionAppName,
66
[string]$TenantId,
@@ -9,7 +9,9 @@ function Set-CippApiAuth {
99

1010
if ($env:MSI_SECRET) {
1111
Disable-AzContextAutosave -Scope Process | Out-Null
12-
$Context = (Connect-AzAccount -Identity).Context
12+
$null = Connect-AzAccount -Identity
13+
$SubscriptionId = $ENV:WEBSITE_OWNER_NAME -split '\+' | Select-Object -First 1
14+
$Context = Set-AzContext -SubscriptionId $SubscriptionId
1315
} else {
1416
$Context = Get-AzContext
1517
}

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

0 commit comments

Comments
 (0)