Public/Set-NSPConditionalAccessPlanDecision.ps1
|
function Set-NSPConditionalAccessPlanDecision { <# .SYNOPSIS Records Approve or Skip on plan items. This is the only way an item becomes eligible to run. .DESCRIPTION -ItemId accepts exact IDs or wildcards. An exact ID for an item with nothing to decide (NoChange, BlockedPrerequisite, PendingPrerequisite, Conflict) is an error. A wildcard silently passes over such items. Decisions are stamped with the time and the Windows user, and the plan file is rewritten atomically (temp file, then replace), so an interrupted save cannot leave a half-written plan. .EXAMPLE Set-NSPConditionalAccessPlanDecision -Plan $plan.Path -ItemId 'group*' -Decision Approve .EXAMPLE Set-NSPConditionalAccessPlanDecision -Plan $plan.Path -ItemId 'NSP-BASE-MFA-01' -Decision Skip -Note 'Keep the portal-added session control for now.' #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][string]$Plan, [Parameter(Mandatory)][string[]]$ItemId, [Parameter(Mandatory)][ValidateSet('Approve', 'Skip')][string]$Decision, [string]$Note ) $content = Get-Content -LiteralPath $Plan -Raw | ConvertFrom-Json if (-not $content.PlanId -or -not $content.Items) { throw "$Plan is not a deployment plan." } $decisionValue = if ($Decision -eq 'Approve') { 'Approved' } else { 'Skipped' } $changed = [System.Collections.Generic.List[object]]::new() foreach ($pattern in $ItemId) { $wildcard = [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($pattern) $matched = @($content.Items | Where-Object { $_.ItemId -like $pattern }) if (-not $matched.Count) { throw "No plan item matches '$pattern'." } foreach ($item in $matched) { if ($item.Decision -eq 'NotActionable') { if ($wildcard) { continue } throw "$($item.ItemId) is $($item.Action); there is nothing to decide." } $item.Decision = $decisionValue $stamp = [pscustomobject]@{ At = (Get-Date).ToUniversalTime().ToString('o'); By = $env:USERNAME; Note = $Note } if ($item.PSObject.Properties['DecisionRecord']) { $item.DecisionRecord = $stamp } else { $item | Add-Member -NotePropertyName DecisionRecord -NotePropertyValue $stamp } $changed.Add($item) } } if ($changed.Count -and $PSCmdlet.ShouldProcess($Plan, "$Decision $($changed.Count) item(s): $(($changed | ForEach-Object ItemId) -join ', ')")) { $temp = "$Plan.tmp" ConvertTo-Json -InputObject $content -Depth 32 | Set-Content -LiteralPath $temp -Encoding UTF8 Move-Item -LiteralPath $temp -Destination $Plan -Force } $changed | Select-Object ItemId, Action, Decision } |