Skip to content

Commit 472cfaa

Browse files
authored
Merge pull request #357 from KelvinTegelaar/dev
[pull] dev from KelvinTegelaar:dev
2 parents 11862e1 + 5702b8d commit 472cfaa

File tree

3 files changed

+259
-21
lines changed

3 files changed

+259
-21
lines changed
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
using namespace System.Net
2+
3+
function Invoke-ListTenantAlignment {
4+
<#
5+
.FUNCTIONALITY
6+
Entrypoint
7+
.ROLE
8+
Tenant.Standards.Read
9+
#>
10+
[CmdletBinding()]
11+
param($Request, $TriggerMetadata)
12+
13+
$APIName = $Request.Params.CIPPEndpoint
14+
$Headers = $Request.Headers
15+
16+
# Get all standard templates
17+
$TemplateTable = Get-CippTable -tablename 'templates'
18+
$TemplateFilter = "PartitionKey eq 'StandardsTemplateV2'"
19+
$Templates = (Get-CIPPAzDataTableEntity @TemplateTable -Filter $TemplateFilter) | ForEach-Object {
20+
$JSON = $_.JSON -replace '"Action":', '"action":'
21+
try {
22+
$RowKey = $_.RowKey
23+
$Data = $JSON | ConvertFrom-Json -Depth 100 -ErrorAction SilentlyContinue
24+
} catch {
25+
Write-Host "$($RowKey) standard could not be loaded: $($_.Exception.Message)"
26+
return
27+
}
28+
if ($Data) {
29+
$Data | Add-Member -NotePropertyName 'GUID' -NotePropertyValue $_.GUID -Force
30+
$Data
31+
}
32+
}
33+
34+
# Get standards comparison data using the same pattern as ListStandardsCompare
35+
$StandardsTable = Get-CIPPTable -TableName 'CippStandardsReports'
36+
$Standards = Get-CIPPAzDataTableEntity @StandardsTable
37+
38+
# Build tenant standards data structure like in ListStandardsCompare
39+
$TenantStandards = @{}
40+
foreach ($Standard in $Standards) {
41+
$FieldName = $Standard.RowKey
42+
$FieldValue = $Standard.Value
43+
$Tenant = $Standard.PartitionKey
44+
45+
# Process field value like in ListStandardsCompare
46+
if ($FieldValue -is [System.Boolean]) {
47+
$FieldValue = [bool]$FieldValue
48+
} elseif ($FieldValue -like '*{*') {
49+
$FieldValue = ConvertFrom-Json -InputObject $FieldValue -ErrorAction SilentlyContinue
50+
} else {
51+
$FieldValue = [string]$FieldValue
52+
}
53+
54+
if (-not $TenantStandards.ContainsKey($Tenant)) {
55+
$TenantStandards[$Tenant] = @{}
56+
}
57+
$TenantStandards[$Tenant][$FieldName] = @{
58+
Value = $FieldValue
59+
LastRefresh = $Standard.TimeStamp.ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ')
60+
}
61+
}
62+
63+
$Results = [System.Collections.Generic.List[object]]::new()
64+
65+
# Process each template against all tenants
66+
foreach ($Template in $Templates) {
67+
$TemplateStandards = $Template.standards
68+
if (-not $TemplateStandards) {
69+
continue
70+
}
71+
72+
# Check if template has tenant assignments (scope)
73+
$TemplateAssignedTenants = @()
74+
$AppliestoAllTenants = $false
75+
76+
if ($Template.tenantFilter -and $Template.tenantFilter.Count -gt 0) {
77+
# Extract tenant values from the tenantFilter array
78+
$TenantValues = $Template.tenantFilter | ForEach-Object { $_.value }
79+
80+
if ($TenantValues -contains 'AllTenants') {
81+
$AppliestoAllTenants = $true
82+
Write-Host "Template '$($Template.templateName)' applies to all tenants (AllTenants)"
83+
} else {
84+
$TemplateAssignedTenants = $TenantValues
85+
Write-Host "Template '$($Template.templateName)' is assigned to specific tenants: $($TemplateAssignedTenants -join ', ')"
86+
}
87+
} else {
88+
$AppliestoAllTenants = $true
89+
Write-Host "Template '$($Template.templateName)' applies to all tenants (no tenantFilter)"
90+
}
91+
92+
$AllStandards = [System.Collections.Generic.List[string]]::new()
93+
$ReportingEnabledStandards = [System.Collections.Generic.List[string]]::new()
94+
$ReportingDisabledStandards = [System.Collections.Generic.List[string]]::new()
95+
96+
foreach ($StandardKey in $TemplateStandards.PSObject.Properties.Name) {
97+
$StandardConfig = $TemplateStandards.$StandardKey
98+
$StandardId = "standards.$StandardKey"
99+
100+
101+
$Actions = @()
102+
if ($StandardConfig.action) {
103+
$Actions = $StandardConfig.action
104+
} elseif ($StandardConfig.Action) {
105+
$Actions = $StandardConfig.Action
106+
} elseif ($StandardConfig.PSObject.Properties['action']) {
107+
$Actions = $StandardConfig.PSObject.Properties['action'].Value
108+
}
109+
110+
$ReportingEnabled = $false
111+
if ($Actions -and $Actions.Count -gt 0) {
112+
$ReportingEnabled = ($Actions | Where-Object { $_.value -and ($_.value.ToLower() -eq 'report' -or $_.value.ToLower() -eq 'remediate') }).Count -gt 0
113+
}
114+
115+
$AllStandards.Add($StandardId)
116+
117+
if ($ReportingEnabled) {
118+
$ReportingEnabledStandards.Add($StandardId)
119+
} else {
120+
$ReportingDisabledStandards.Add($StandardId)
121+
}
122+
123+
if ($StandardKey -eq 'IntuneTemplate' -and $StandardConfig -is [array]) {
124+
$AllStandards.Remove($StandardId)
125+
if ($ReportingEnabled) {
126+
$ReportingEnabledStandards.Remove($StandardId)
127+
} else {
128+
$ReportingDisabledStandards.Remove($StandardId)
129+
}
130+
131+
foreach ($IntuneTemplate in $StandardConfig) {
132+
if ($IntuneTemplate.TemplateList.value) {
133+
$IntuneStandardId = "standards.IntuneTemplate.$($IntuneTemplate.TemplateList.value)"
134+
135+
$IntuneActions = if ($IntuneTemplate.action) { $IntuneTemplate.action } else { @() }
136+
$IntuneReportingEnabled = ($IntuneActions | Where-Object { $_.value -and ($_.value.ToLower() -eq 'report' -or $_.value.ToLower() -eq 'remediate') }).Count -gt 0
137+
138+
$AllStandards.Add($IntuneStandardId)
139+
140+
if ($IntuneReportingEnabled) {
141+
$ReportingEnabledStandards.Add($IntuneStandardId)
142+
} else {
143+
$ReportingDisabledStandards.Add($IntuneStandardId)
144+
}
145+
}
146+
}
147+
}
148+
}
149+
150+
foreach ($TenantName in $TenantStandards.Keys) {
151+
if (-not $AppliestoAllTenants -and $TenantName -notin $TemplateAssignedTenants) {
152+
Write-Host "Skipping tenant '$TenantName' for template '$($Template.templateName)' - not in assigned tenant list"
153+
continue
154+
}
155+
$AllCount = $AllStandards.Count
156+
157+
$CompliantStandards = 0
158+
$NonCompliantStandards = 0
159+
$ReportingDisabledStandardsCount = 0
160+
$LatestDataCollection = $null
161+
$ComparisonTable = @()
162+
163+
foreach ($StandardKey in $AllStandards) {
164+
$IsReportingDisabled = $ReportingDisabledStandards -contains $StandardKey
165+
166+
if ($TenantStandards[$TenantName].ContainsKey($StandardKey)) {
167+
$StandardObject = $TenantStandards[$TenantName][$StandardKey]
168+
$Value = $StandardObject.Value
169+
170+
if ($StandardObject.LastRefresh) {
171+
$RefreshTime = [DateTime]::Parse($StandardObject.LastRefresh)
172+
if (-not $LatestDataCollection -or $RefreshTime -gt $LatestDataCollection) {
173+
$LatestDataCollection = $RefreshTime
174+
}
175+
}
176+
177+
$IsCompliant = ($Value -eq $true)
178+
179+
if ($IsReportingDisabled) {
180+
$ReportingDisabledStandardsCount++
181+
$ComplianceStatus = 'Reporting Disabled'
182+
} elseif ($IsCompliant) {
183+
$CompliantStandards++
184+
$ComplianceStatus = 'Compliant'
185+
} else {
186+
$NonCompliantStandards++
187+
$ComplianceStatus = 'Non-Compliant'
188+
}
189+
190+
$ComparisonTable += [PSCustomObject]@{
191+
StandardName = $StandardKey
192+
Compliant = $IsCompliant
193+
StandardValue = ($Value | ConvertTo-Json -Compress)
194+
ComplianceStatus = $ComplianceStatus
195+
ReportingDisabled = $IsReportingDisabled
196+
}
197+
} else {
198+
if ($IsReportingDisabled) {
199+
$ReportingDisabledStandardsCount++
200+
$ComplianceStatus = 'Reporting Disabled'
201+
} else {
202+
$NonCompliantStandards++
203+
$ComplianceStatus = 'Non-Compliant'
204+
}
205+
206+
$ComparisonTable += [PSCustomObject]@{
207+
StandardName = $StandardKey
208+
Compliant = $false
209+
StandardValue = 'NOT FOUND'
210+
ComplianceStatus = $ComplianceStatus
211+
ReportingDisabled = $IsReportingDisabled
212+
}
213+
}
214+
}
215+
216+
217+
$AlignmentPercentage = if (($AllCount - $ReportingDisabledStandardsCount) -gt 0) {
218+
[Math]::Round(($CompliantStandards / ($AllCount - $ReportingDisabledStandardsCount)) * 100)
219+
} else {
220+
0
221+
}
222+
223+
$TenantOnlyStandards = $TenantStandards[$TenantName].Keys | Where-Object { $_ -notin $AllStandards }
224+
225+
$Result = [PSCustomObject]@{
226+
tenantFilter = $TenantName
227+
standardName = $Template.templateName
228+
standardId = $Template.GUID
229+
alignmentScore = $AlignmentPercentage
230+
latestDataCollection = if ($LatestDataCollection) { $LatestDataCollection } else { $null }
231+
}
232+
233+
$Results.Add($Result)
234+
}
235+
}
236+
237+
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
238+
StatusCode = [HttpStatusCode]::OK
239+
Body = @($Results)
240+
})
241+
}

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

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,31 +37,21 @@ function Invoke-CIPPStandardSendReceiveLimitTenant {
3737
return
3838
}
3939

40+
# Input validation
4041
if ([Int32]$Settings.ReceiveLimit -lt 1 -or [Int32]$Settings.ReceiveLimit -gt 150) {
4142
Write-LogMessage -API 'Standards' -tenant $tenant -message 'SendReceiveLimitTenant: Invalid ReceiveLimit parameter set' -sev Error
4243
return
4344
}
4445

46+
4547
$AllMailBoxPlans = New-ExoRequest -tenantid $Tenant -cmdlet 'Get-MailboxPlan' | Select-Object DisplayName, MaxSendSize, MaxReceiveSize, GUID
46-
$MaxSendSize = "$($Settings.SendLimit)MB"
47-
$MaxReceiveSize = "$($Settings.ReceiveLimit)MB"
48-
$MaxSendSizeBytes = $Settings.SendLimit * 1MB
49-
$MaxReceiveSizeBytes = $Settings.ReceiveLimit * 1MB
48+
$MaxSendSize = [int64]"$($Settings.SendLimit)MB"
49+
$MaxReceiveSize = [int64]"$($Settings.ReceiveLimit)MB"
5050

5151
$NotSetCorrectly = foreach ($MailboxPlan in $AllMailBoxPlans) {
52-
if ($MailboxPlan.MaxSendSize -eq 'Unlimited') {
53-
$PlanMaxSendSize = [int64]::MaxValue
54-
} else {
55-
$PlanMaxSendSize = [int64]($MailboxPlan.MaxSendSize -replace '.*\(([\d,]+).*', '$1' -replace ',', '')
56-
}
57-
58-
if ($MailboxPlan.MaxReceiveSize -eq 'Unlimited') {
59-
$PlanMaxReceiveSize = [int64]::MaxValue
60-
} else {
61-
$PlanMaxReceiveSize = [int64]($MailboxPlan.MaxReceiveSize -replace '.*\(([\d,]+).*', '$1' -replace ',', '')
62-
}
63-
64-
if ($PlanMaxSendSize -ne $MaxSendSizeBytes -or $PlanMaxReceiveSize -ne $MaxReceiveSizeBytes) {
52+
$PlanMaxSendSize = [int64]($MailboxPlan.MaxSendSize -replace '.*\(([\d,]+).*', '$1' -replace ',', '')
53+
$PlanMaxReceiveSize = [int64]($MailboxPlan.MaxReceiveSize -replace '.*\(([\d,]+).*', '$1' -replace ',', '')
54+
if ($PlanMaxSendSize -ne $MaxSendSize -or $PlanMaxReceiveSize -ne $MaxReceiveSize) {
6555
$MailboxPlan
6656
}
6757
}
@@ -86,6 +76,7 @@ function Invoke-CIPPStandardSendReceiveLimitTenant {
8676
}
8777

8878
if ($Settings.alert -eq $true) {
79+
8980
if ($NotSetCorrectly.Count -eq 0) {
9081
Write-LogMessage -API 'Standards' -tenant $tenant -message "The tenant send($($Settings.SendLimit)MB) and receive($($Settings.ReceiveLimit)MB) limits are set correctly" -sev Info
9182
} else {

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,23 @@ function Invoke-CIPPStandardintuneDeviceRetirementDays {
3232
param($Tenant, $Settings)
3333
##$Rerun -Type Standard -Tenant $Tenant -Settings $Settings 'intuneDeviceRetirementDays'
3434

35-
$CurrentInfo = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/managedDeviceCleanupSettings' -tenantid $Tenant)
35+
$CurrentInfo = (New-GraphGetRequest -Uri 'https://graph.microsoft.com/beta/deviceManagement/managedDeviceCleanupRules' -tenantid $Tenant)
3636
$StateIsCorrect = if ($CurrentInfo.DeviceInactivityBeforeRetirementInDays -eq $Settings.days) { $true } else { $false }
3737

38-
If ($Settings.remediate -eq $true) {
38+
if ($Settings.remediate -eq $true) {
3939

4040
if ($CurrentInfo.DeviceInactivityBeforeRetirementInDays -eq $Settings.days) {
4141
Write-LogMessage -API 'Standards' -tenant $tenant -message "DeviceInactivityBeforeRetirementInDays for $($Settings.days) days is already enabled." -sev Info
4242
} else {
43+
if ($CurrentInfo) {
44+
$Type = 'Patch'
45+
$id = "('$($CurrentInfo.id)')"
46+
} else {
47+
$Type = 'Post'
48+
}
4349
try {
44-
$body = @{ DeviceInactivityBeforeRetirementInDays = $Settings.days } | ConvertTo-Json
45-
(New-GraphPostRequest -tenantid $tenant -Uri 'https://graph.microsoft.com/beta/deviceManagement/managedDeviceCleanupSettings' -Type PATCH -Body $body -ContentType 'application/json')
50+
$body = '{"displayName":"Default Policy","description":"Default Policy","deviceCleanupRulePlatformType":"all","deviceInactivityBeforeRetirementInDays":' + $Settings.days + '}'
51+
(New-GraphPostRequest -tenantid $tenant -Uri "https://graph.microsoft.com/beta/deviceManagement/managedDeviceCleanupRules$id" -Type $Type -Body $body -ContentType 'application/json')
4652
Write-LogMessage -API 'Standards' -tenant $tenant -message "Enabled DeviceInactivityBeforeRetirementInDays for $($Settings.days) days." -sev Info
4753
} catch {
4854
$ErrorMessage = Get-NormalizedError -Message $_.Exception.Message

0 commit comments

Comments
 (0)