-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bdd3794
commit 2b4e7c4
Showing
4 changed files
with
295 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 4 additions & 1 deletion
5
Modules/CIPPCore/Public/Standards/ConvertTo-CippStandardObject.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,18 @@ | ||
function ConvertTo-CippStandardObject { | ||
|
||
param( | ||
[Parameter(Mandatory = $true)] | ||
$StandardObject | ||
) | ||
# If it's an array of items, process each item | ||
if ($StandardObject -is [System.Collections.IEnumerable] -and -not ($StandardObject -is [string])) { | ||
$ProcessedItems = New-Object System.Collections.ArrayList | ||
foreach ($Item in $StandardObject) { | ||
$ProcessedItems.Add((Convert-SingleStandardObject $Item)) | Out-Null | ||
} | ||
return [System.Collections.ArrayList]$ProcessedItems | ||
return $ProcessedItems | ||
} else { | ||
# Single object | ||
return Convert-SingleStandardObject $StandardObject | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,264 @@ | ||
function Get-CIPPStandards { | ||
param( | ||
[Parameter(Mandatory = $false)] | ||
[string]$TenantFilter = 'allTenants', | ||
|
||
[Parameter(Mandatory = $false)] | ||
[switch]$ListAllTenants, | ||
|
||
[Parameter(Mandatory = $false)] | ||
$TemplateId = '*', | ||
|
||
[Parameter(Mandatory = $false)] | ||
$runManually = $false | ||
) | ||
|
||
# 1. Get all JSON-based templates from the "templates" table | ||
$Table = Get-CippTable -tablename 'templates' | ||
$Filter = "PartitionKey eq 'StandardsTemplateV2'" | ||
$Templates = (Get-CIPPAzDataTableEntity @Table -Filter $Filter | Sort-Object TimeStamp).JSON | | ||
ForEach-Object { | ||
try { | ||
# Fix old "Action" => "action" | ||
$JSON = $_ -replace '"Action":', '"action":' | ||
ConvertFrom-Json -InputObject $JSON -ErrorAction SilentlyContinue | ||
} catch {} | ||
} | | ||
Where-Object { | ||
$_.GUID -like $TemplateId -and $_.runManually -eq $runManually | ||
} | ||
|
||
# 2. Get tenant list, filter if needed | ||
$AllTenantsList = Get-Tenants | ||
if ($TenantFilter -ne 'allTenants') { | ||
$AllTenantsList = $AllTenantsList | Where-Object { | ||
$_.defaultDomainName -eq $TenantFilter -or $_.customerId -eq $TenantFilter | ||
} | ||
} | ||
|
||
# 3. If -ListAllTenants, build standards for "AllTenants" only | ||
if ($ListAllTenants.IsPresent) { | ||
$AllTenantsTemplates = $Templates | Where-Object { | ||
$_.tenantFilter.value -contains 'AllTenants' | ||
} | ||
|
||
$ComputedStandards = [ordered]@{} | ||
|
||
foreach ($Template in $AllTenantsTemplates) { | ||
$Standards = $Template.standards | ||
|
||
foreach ($StandardName in $Standards.PSObject.Properties.Name) { | ||
$Value = $Standards.$StandardName | ||
$IsArray = $Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string]) | ||
|
||
if ($IsArray) { | ||
# e.g. IntuneTemplate with 2 items | ||
foreach ($Item in $Value) { | ||
$CurrentStandard = $Item.PSObject.Copy() | ||
$CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force | ||
|
||
$Actions = $CurrentStandard.action.value | ||
if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { | ||
if (-not $ComputedStandards.Contains($StandardName)) { | ||
$ComputedStandards[$StandardName] = $CurrentStandard | ||
} else { | ||
$MergedStandard = Merge-CippStandards -Existing $ComputedStandards[$StandardName] -New $CurrentStandard -StandardName $StandardName | ||
$ComputedStandards[$StandardName] = $MergedStandard | ||
} | ||
} | ||
} | ||
} else { | ||
# single object | ||
$CurrentStandard = $Value.PSObject.Copy() | ||
$CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force | ||
|
||
$Actions = $CurrentStandard.action.value | ||
if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { | ||
if (-not $ComputedStandards.Contains($StandardName)) { | ||
$ComputedStandards[$StandardName] = $CurrentStandard | ||
} else { | ||
$MergedStandard = Merge-CippStandards -Existing $ComputedStandards[$StandardName] -New $CurrentStandard -StandardName $StandardName | ||
$ComputedStandards[$StandardName] = $MergedStandard | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
# Output result for 'AllTenants' | ||
foreach ($Standard in $ComputedStandards.Keys) { | ||
$TempCopy = $ComputedStandards[$Standard].PSObject.Copy() | ||
|
||
# Remove 'TemplateId' from final output | ||
if ($TempCopy -is [System.Collections.IEnumerable] -and -not ($TempCopy -is [string])) { | ||
foreach ($subItem in $TempCopy) { | ||
$subItem.PSObject.Properties.Remove('TemplateId') | Out-Null | ||
} | ||
} else { | ||
$TempCopy.PSObject.Properties.Remove('TemplateId') | Out-Null | ||
} | ||
|
||
$Normalized = ConvertTo-CippStandardObject $TempCopy | ||
|
||
[pscustomobject]@{ | ||
Tenant = 'AllTenants' | ||
Standard = $Standard | ||
Settings = $Normalized | ||
TemplateId = if ($ComputedStandards[$Standard] -is [System.Collections.IEnumerable] -and -not ($ComputedStandards[$Standard] -is [string])) { | ||
# If multiple items from multiple templates, you may have multiple TemplateIds | ||
$ComputedStandards[$Standard] | ForEach-Object { $_.TemplateId } | ||
} else { | ||
$ComputedStandards[$Standard].TemplateId | ||
} | ||
} | ||
} | ||
} else { | ||
# 4. For each tenant, figure out which templates apply, merge them, and output. | ||
foreach ($Tenant in $AllTenantsList) { | ||
$TenantName = $Tenant.defaultDomainName | ||
|
||
# Determine which templates apply to this tenant | ||
$ApplicableTemplates = $Templates | ForEach-Object { | ||
$template = $_ | ||
$tenantFilterValues = $template.tenantFilter | ForEach-Object { $_.value } | ||
$excludedTenantValues = @() | ||
|
||
if ($template.excludedTenants) { | ||
if ($template.excludedTenants -is [System.Collections.IEnumerable] -and -not ($template.excludedTenants -is [string])) { | ||
$excludedTenantValues = $template.excludedTenants | ForEach-Object { $_.value } | ||
} else { | ||
$excludedTenantValues = @($template.excludedTenants) | ||
} | ||
} | ||
|
||
$AllTenantsApplicable = $false | ||
$TenantSpecificApplicable = $false | ||
|
||
if ($tenantFilterValues -contains 'AllTenants' -and -not ($excludedTenantValues -contains $TenantName)) { | ||
$AllTenantsApplicable = $true | ||
} | ||
if ($tenantFilterValues -contains $TenantName) { | ||
$TenantSpecificApplicable = $true | ||
} | ||
|
||
if ($AllTenantsApplicable -or $TenantSpecificApplicable) { | ||
$template | ||
} | ||
} | ||
|
||
# Separate them into AllTenant vs. TenantSpecific sets | ||
$AllTenantTemplatesSet = $ApplicableTemplates | Where-Object { | ||
$_.tenantFilter.value -contains 'AllTenants' | ||
} | ||
$TenantSpecificTemplatesSet = $ApplicableTemplates | Where-Object { | ||
$_.tenantFilter.value -notcontains 'AllTenants' | ||
} | ||
|
||
$ComputedStandards = [ordered]@{} | ||
|
||
# 4a. Merge the AllTenantTemplatesSet | ||
foreach ($Template in $AllTenantTemplatesSet) { | ||
$Standards = $Template.standards | ||
|
||
foreach ($StandardName in $Standards.PSObject.Properties.Name) { | ||
$Value = $Standards.$StandardName | ||
$IsArray = $Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string]) | ||
|
||
if ($IsArray) { | ||
foreach ($Item in $Value) { | ||
$CurrentStandard = $Item.PSObject.Copy() | ||
$CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force | ||
|
||
$Actions = $CurrentStandard.action.value | ||
if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { | ||
if (-not $ComputedStandards.Contains($StandardName)) { | ||
$ComputedStandards[$StandardName] = $CurrentStandard | ||
} else { | ||
$MergedStandard = Merge-CippStandards -Existing $ComputedStandards[$StandardName] -New $CurrentStandard -StandardName $StandardName | ||
$ComputedStandards[$StandardName] = $MergedStandard | ||
} | ||
} | ||
} | ||
} else { | ||
$CurrentStandard = $Value.PSObject.Copy() | ||
$CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force | ||
|
||
$Actions = $CurrentStandard.action.value | ||
if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { | ||
if (-not $ComputedStandards.Contains($StandardName)) { | ||
$ComputedStandards[$StandardName] = $CurrentStandard | ||
} else { | ||
$MergedStandard = Merge-CippStandards -Existing $ComputedStandards[$StandardName] -New $CurrentStandard -StandardName $StandardName | ||
$ComputedStandards[$StandardName] = $MergedStandard | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
# 4b. Merge the TenantSpecificTemplatesSet | ||
foreach ($Template in $TenantSpecificTemplatesSet) { | ||
$Standards = $Template.standards | ||
|
||
foreach ($StandardName in $Standards.PSObject.Properties.Name) { | ||
$Value = $Standards.$StandardName | ||
$IsArray = $Value -is [System.Collections.IEnumerable] -and -not ($Value -is [string]) | ||
|
||
if ($IsArray) { | ||
foreach ($Item in $Value) { | ||
$CurrentStandard = $Item.PSObject.Copy() | ||
$CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force | ||
|
||
# Filter actions only 'Remediate','warn','Report' | ||
$Actions = $CurrentStandard.action.value | Where-Object { $_ -in 'Remediate', 'warn', 'Report' } | ||
if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { | ||
if (-not $ComputedStandards.Contains($StandardName)) { | ||
$ComputedStandards[$StandardName] = $CurrentStandard | ||
} else { | ||
$MergedStandard = Merge-CippStandards -Existing $ComputedStandards[$StandardName] -New $CurrentStandard -StandardName $StandardName | ||
$ComputedStandards[$StandardName] = $MergedStandard | ||
} | ||
} | ||
} | ||
} else { | ||
$CurrentStandard = $Value.PSObject.Copy() | ||
$CurrentStandard | Add-Member -NotePropertyName 'TemplateId' -NotePropertyValue $Template.GUID -Force | ||
|
||
$Actions = $CurrentStandard.action.value | Where-Object { $_ -in 'Remediate', 'warn', 'Report' } | ||
if ($Actions -contains 'Remediate' -or $Actions -contains 'warn' -or $Actions -contains 'Report') { | ||
if (-not $ComputedStandards.Contains($StandardName)) { | ||
$ComputedStandards[$StandardName] = $CurrentStandard | ||
} else { | ||
$MergedStandard = Merge-CippStandards -Existing $ComputedStandards[$StandardName] -New $CurrentStandard -StandardName $StandardName | ||
$ComputedStandards[$StandardName] = $MergedStandard | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
# 4c. Output each final standard for this tenant | ||
foreach ($Standard in $ComputedStandards.Keys) { | ||
$TempCopy = $ComputedStandards[$Standard].PSObject.Copy() | ||
# Remove local 'TemplateId' from final object(s) | ||
if ($TempCopy -is [System.Collections.IEnumerable] -and -not ($TempCopy -is [string])) { | ||
foreach ($subItem in $TempCopy) { | ||
$subItem.PSObject.Properties.Remove('TemplateId') | Out-Null | ||
} | ||
} else { | ||
$TempCopy.PSObject.Properties.Remove('TemplateId') | Out-Null | ||
} | ||
|
||
$Normalized = ConvertTo-CippStandardObject $TempCopy | ||
|
||
[pscustomobject]@{ | ||
Tenant = $TenantName | ||
Standard = $Standard | ||
Settings = $Normalized | ||
TemplateId = $ComputedStandards[$Standard].TemplateId | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
34 changes: 19 additions & 15 deletions
34
Modules/CIPPCore/Public/Standards/Merge-CippStandards.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,26 @@ | ||
function Merge-CippStandards { | ||
param( | ||
[Parameter(Mandatory = $true)] | ||
[object]$Existing, | ||
[Parameter(Mandatory = $true)] | ||
[object]$New | ||
[Parameter(Mandatory = $true)][object]$Existing, | ||
[Parameter(Mandatory = $true)][object]$New, | ||
[Parameter(Mandatory = $true)][string]$StandardName | ||
) | ||
|
||
if (-not $Existing) { | ||
return $New | ||
} | ||
$ExistingIsArray = ($Existing -is [System.Collections.IEnumerable] -and -not ($Existing -is [string])) | ||
$NewIsArray = ($New -is [System.Collections.IEnumerable] -and -not ($New -is [string])) | ||
# If $Existing or $New is $null/empty, just return the other. | ||
if (-not $Existing) { return $New } | ||
if (-not $New) { return $Existing } | ||
|
||
if (-not $ExistingIsArray) { | ||
$Existing = @($Existing) | ||
} | ||
if (-not $NewIsArray) { | ||
$New = @($New) | ||
# If the standard name ends with 'Template', we treat them as arrays to merge. | ||
if ($StandardName -like '*Template') { | ||
$ExistingIsArray = $Existing -is [System.Collections.IEnumerable] -and -not ($Existing -is [string]) | ||
$NewIsArray = $New -is [System.Collections.IEnumerable] -and -not ($New -is [string]) | ||
|
||
# Make sure both are arrays | ||
if (-not $ExistingIsArray) { $Existing = @($Existing) } | ||
if (-not $NewIsArray) { $New = @($New) } | ||
|
||
return $Existing + $New | ||
} else { | ||
# Single‐value standard: override the old with the new | ||
return $New | ||
} | ||
return $Existing + $New | ||
} |