Public/Deploy-AGEsc1.ps1
|
function Deploy-AGEsc1 { <# .SYNOPSIS Deploys the ESC1 scenario: "Copy of Web Server" with Client Authentication added by mistake. .DESCRIPTION Implements the ESC1 recipe settled in ADCSGoat issue #22, riding the shared scenario pipeline (Invoke-AGTemplateScenario, issue #27). The clone of the built-in Web Server template gets Client Authentication (1.3.6.1.5.5.7.3.2) APPENDED to both pKIExtendedKeyUsage and msPKI-Certificate-Application-Policy (existing Server Auth preserved), Domain Users granted Read + Enroll layered on the copied source DACL, and publication on the selected CA. The Web Server source is never written. .PARAMETER CAName The cn of the enterprise CA to publish to. Optional; autodetected when the forest has exactly one enterprise CA. .PARAMETER StatePath Where the deploy state file lives. Defaults to ADCSGoat.State.xml next to the module root. .PARAMETER Server The domain controller to write to. Defaults to the logon server. .PARAMETER Force Replaces an ADCSGoat-owned existing clone without prompting. Required for non-interactive redeploy. .OUTPUTS System.Management.Automation.PSCustomObject with CloneCn, Oid, and CompanionOidObjectDN. .EXAMPLE Deploy-AGEsc1 Clones Web Server, adds Client Auth, grants Domain Users enroll, and publishes on the forest's single CA. .EXAMPLE Deploy-AGEsc1 -CAName 'LabRootCA1' -Force Redeploys against the named CA, replacing any owned clone. #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'AD writes gated by the Copy-AGTemplate collision prompt / -Force contract per module precedent.')] [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string]$CAName, [Parameter()] [ValidateNotNullOrEmpty()] [string]$StatePath, [Parameter()] [ValidateNotNullOrEmpty()] [string]$Server, [Parameter()] [switch]$Force ) begin { if ([string]::IsNullOrEmpty($StatePath)) { $StatePath = Join-Path -Path $PSScriptRoot -ChildPath '..\ADCSGoat.State.xml' } $clientAuthOid = '1.3.6.1.5.5.7.3.2' $enrollGuid = [guid]'0e10c968-78fb-11d2-90d4-00c04f79dc55' $allPropsGuid = [guid]'00000000-0000-0000-0000-000000000000' # Recipe: append Client Auth to both EKU attributes, preserving the # existing Server Auth value. The v2-only application-policy attribute # may be absent on a v1-sourced clone; create it. $recipe = { param($clone) $existingEku = @($clone.Properties['pKIExtendedKeyUsage'] | ForEach-Object { "$_" }) if ($existingEku -notcontains $clientAuthOid) { $clone.Properties['pKIExtendedKeyUsage'].Add($clientAuthOid) | Out-Null } $existingAp = @($clone.Properties['msPKI-Certificate-Application-Policy'] | ForEach-Object { "$_" }) if ($existingAp.Count -eq 0) { foreach ($v in $existingEku) { $clone.Properties['msPKI-Certificate-Application-Policy'].Add($v) | Out-Null } if ($existingEku -notcontains $clientAuthOid) { $clone.Properties['msPKI-Certificate-Application-Policy'].Add($clientAuthOid) | Out-Null } } elseif ($existingAp -notcontains $clientAuthOid) { $clone.Properties['msPKI-Certificate-Application-Policy'].Add($clientAuthOid) | Out-Null } $clone.CommitChanges() } # Rights: Domain Users Read + Enroll, layered on the copied DACL. $accessRules = { param($domainSid) New-Object System.DirectoryServices.ActiveDirectoryAccessRule $domainSid, ([System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight), ([System.Security.AccessControl.AccessControlType]::Allow), $enrollGuid New-Object System.DirectoryServices.ActiveDirectoryAccessRule $domainSid, ([System.DirectoryServices.ActiveDirectoryRights]::GenericRead), ([System.Security.AccessControl.AccessControlType]::Allow), $allPropsGuid } } process { $pipelineParams = @{ Scenario = 'ESC1' SourceName = 'WebServer' DestinationName = 'Copy of Web Server' Recipe = $recipe AccessRules = $accessRules StatePath = $StatePath } if ($PSBoundParameters.ContainsKey('CAName')) { $pipelineParams['CAName'] = $CAName } if ($PSBoundParameters.ContainsKey('Server')) { $pipelineParams['Server'] = $Server } if ($Force.IsPresent) { $pipelineParams['Force'] = $true } Invoke-AGTemplateScenario @pipelineParams } } |