Public/Invoke-NSPEntraPairingAddressPreparation.ps1
|
function Invoke-NSPEntraPairingAddressPreparation { <# .SYNOPSIS Previews AD preparation, or explicitly applies it and invalidates the pairing queue first. .DESCRIPTION Uses the AD specialist's planner and writer. Apply requires a saved queue path and retains results there as addressPreparation. Any apply attempt requires fresh inventories and queue revalidation before hard match, even if a write fails. No synchronization is started. .EXAMPLE Invoke-NSPEntraPairingAddressPreparation -Queue $queue -Inventory $inventory -OldDomain old.example -NewDomain new.example .EXAMPLE Invoke-NSPEntraPairingAddressPreparation -Queue $queue -Inventory $inventory -OldDomain old.example -NewDomain new.example -Apply -Path $path #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] param([Parameter(Mandatory)]$Queue, [Parameter(Mandatory)]$Inventory, [Parameter(Mandatory)][string]$OldDomain, [Parameter(Mandatory)][string]$NewDomain, [ValidateSet('ReplaceSuffix','SamAccountName','FLast','First.Last','LastF')][string]$Format = 'ReplaceSuffix', [hashtable]$AddressPolicy = @{}, [ValidateSet('Block','UsePlannedAD')][string]$CloudPrimaryConflictAction = 'Block', [ValidatePattern('^[A-Za-z][A-Za-z0-9]*$')][string[]]$CloudProxyAddressType = @('SMTP','SIP','X500'), [switch]$Apply, [string]$Path) $plans = @(Get-NSPEntraPairingAddressPlan -Queue $Queue -Inventory $Inventory -OldDomain $OldDomain -NewDomain $NewDomain -Format $Format -AddressPolicy $AddressPolicy -CloudProxyAddressType $CloudProxyAddressType -CloudPrimaryConflictAction $CloudPrimaryConflictAction) if (-not $Apply -or $WhatIfPreference) { if ($Apply) { [void]$PSCmdlet.ShouldProcess('selected AD users', 'Apply reviewed address preparation') } $plans return } if (-not $plans.Count) { return } if (@($plans | Where-Object Blocked).Count) { throw 'Address preparation is blocked; review the plan reasons.' } if (-not $Path) { throw 'Apply requires -Path for saving queue invalidation and results.' } Assert-NSPEntraPairingStatePath -Path $Path if (-not $PSCmdlet.ShouldProcess('selected AD users', 'Apply reviewed address preparation; hard match remains separate')) { return } foreach ($pair in @($Queue.pairs | Where-Object decision -eq 'selected')) { if ($pair.executionState -ne 'pending') { throw 'An attempted hard match must be reconciled before AD address preparation.' } } Assert-NSPEntraAddressCloudState -Queue $Queue -Plan $plans $Queue.needsRevalidation = $true $Queue.revalidatedAtUtc = $null foreach ($pair in @($Queue.pairs | Where-Object decision -eq 'selected')) { $pair.history = @($pair.history) + [pscustomobject]@{ decision=$pair.decision; adObjectGuid=$pair.adObjectGuid; decidedAtUtc=$pair.decidedAtUtc; decidedBy=$pair.decidedBy; note=$pair.note } $pair.decision = 'needs-review' $pair.desiredImmutableId = $null } $state = [pscustomobject]@{ StartedAtUtc = [datetime]::UtcNow.ToString('o'); Outcome = 'started'; Results = @(); Error = $null } $Queue | Add-Member -NotePropertyName addressPreparation -NotePropertyValue $state -Force Export-NSPEntraPairingQueue -Queue $Queue -Path $Path | Out-Null try { Set-NSPADUserAddress -Plan $plans -Apply | ForEach-Object { $state.Results = @($state.Results) + $_ Export-NSPEntraPairingQueue -Queue $Queue -Path $Path | Out-Null } $state.Outcome = if (@($state.Results | Where-Object { $_.Result -in @('Failed','WriteUnverified','VerificationFailed') }).Count) { 'needs-inspection' } else { 'requires-refresh' } } catch { $state.Outcome = 'unknown' $state.Error = $_.Exception.Message } Export-NSPEntraPairingQueue -Queue $Queue -Path $Path | Out-Null $state } |