#Requires -Version 5.1 [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)] [ValidatePattern('^[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$')] [string]$ClientName, [string]$OutputDirectory = (Join-Path $PSScriptRoot '..\artifacts\azure-p2s'), [securestring]$ClientPfxPassword, [string]$RootSubject = 'CN=SGU Azure P2S Root', [ValidateRange(1, 10)] [int]$ClientValidityYears = 2, [switch]$Force ) $ErrorActionPreference = 'Stop' $resolvedOutputDirectory = [IO.Path]::GetFullPath($OutputDirectory) New-Item -ItemType Directory -Path $resolvedOutputDirectory -Force | Out-Null $rootCertificatePath = Join-Path $resolvedOutputDirectory 'sgu-azure-p2s-root.cer' $clientCertificatePath = Join-Path $resolvedOutputDirectory "sgu-azure-p2s-$ClientName.pfx" if ((Test-Path -LiteralPath $clientCertificatePath -PathType Leaf) -and -not $Force) { throw "$clientCertificatePath already exists. Use -Force only when you intend to replace that exported client credential." } if (-not $ClientPfxPassword) { $ClientPfxPassword = Read-Host 'Password that will protect the exported P2S client certificate' -AsSecureString } $rootCertificate = Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.Subject -eq $RootSubject -and $_.HasPrivateKey -and $_.NotAfter -gt (Get-Date).AddYears($ClientValidityYears) } | Sort-Object NotAfter -Descending | Select-Object -First 1 if (-not $rootCertificate) { if (-not $PSCmdlet.ShouldProcess($RootSubject, 'Create a non-exportable Azure P2S root certificate authority')) { return } $rootCertificate = New-SelfSignedCertificate ` -Type Custom ` -Subject $RootSubject ` -CertStoreLocation Cert:\CurrentUser\My ` -KeyAlgorithm RSA ` -KeyLength 4096 ` -HashAlgorithm SHA256 ` -KeySpec Signature ` -KeyExportPolicy NonExportable ` -KeyUsage CertSign,CRLSign,DigitalSignature ` -NotAfter (Get-Date).AddYears(10) ` -TextExtension @('2.5.29.19={critical}{text}ca=1&pathlength=1') } if (-not $PSCmdlet.ShouldProcess($ClientName, 'Issue and export an Azure P2S machine certificate')) { return } $clientSubject = "CN=SGU Azure P2S $ClientName" $clientCertificate = New-SelfSignedCertificate ` -Type Custom ` -Subject $clientSubject ` -DnsName "sgu-p2s-$ClientName" ` -Signer $rootCertificate ` -CertStoreLocation Cert:\CurrentUser\My ` -KeyAlgorithm RSA ` -KeyLength 3072 ` -HashAlgorithm SHA256 ` -KeySpec Signature ` -KeyExportPolicy Exportable ` -KeyUsage DigitalSignature ` -NotAfter (Get-Date).AddYears($ClientValidityYears) ` -TextExtension @('2.5.29.37={text}1.3.6.1.5.5.7.3.2') Export-Certificate -Cert $rootCertificate -FilePath $rootCertificatePath -Force | Out-Null Export-PfxCertificate -Cert $clientCertificate -FilePath $clientCertificatePath ` -Password $ClientPfxPassword -ChainOption BuildChain -CryptoAlgorithmOption AES256_SHA256 ` -Force | Out-Null [pscustomobject]@{ RootCertificatePath = $rootCertificatePath RootCertificateThumbprint = $rootCertificate.Thumbprint RootCertificateData = [Convert]::ToBase64String($rootCertificate.RawData) ClientName = $ClientName ClientCertificatePath = $clientCertificatePath ClientCertificateThumbprint = $clientCertificate.Thumbprint ClientCertificateExpires = $clientCertificate.NotAfter RootPrivateKeyExportable = $false }