Public/New-TMConsoleCertificate.ps1
function New-TMConsoleCertificate { param ( [Parameter()][ValidateSet('LocalMachine', 'CurrentUser')] [String]$Scope = 'LocalMachine' ) ## Perform Windows Setup if ($IsWindows) { # Only admins can create certificates if ($Scope -eq 'LocalMachine' -and -Not (Test-IsAdmin)) { Write-Verbose 'Creating a LocalMachine certificate requires administrative permission, which is not available. Switching to CurrentUser' $Scope = 'CurrentUser' } ## Provide naming details for the certificate $SubjectName = $env:COMPUTERNAME ## Check for existing Certificates $ExistingCerts = Get-ChildItem "Cert:\$Scope\My\" | Where-Object { $_.FriendlyName -like "*$SubjectName" -and $_.Issuer -like "CN=$SubjectName" } if ($ExistingCerts) { $ExistingCerts | ForEach-Object { Write-Host "An existing Cert was found, Thumbprint: $($_.Thumbprint), Removing it" Remove-Item "Cert:\$Scope\My\$($_.Thumbprint)" -Force -Confirm:$false -Recurse } } ## Create File Path variables $OutFolderRoot = $Scope -eq 'LocalMachine' ? $Env:ProgramData : $ENV:APPDATA $OutFolder = Join-Path -Path $OutFolderRoot -ChildPath "tmconsole" -AdditionalChildPath "certificates" $OutServerKeyPath = Join-Path -Path $OutFolder -ChildPath 'TMConsole.key' $OutCertificatePath = Join-Path -Path $OutFolder -ChildPath 'TMConsole.pem' $TempDERKeyPath = Join-Path -Path $OutFolder -ChildPath 'TMConsole.der' ## Create the Certificates Folder if it's not already present Test-FolderPath -FolderPath $OutFolder ## Remove Existing Certificates Get-ChildItem -Path $OutFolder -Recurse -Force | Remove-Item -Force -Recurse ## Create the Self Signed Certificate $CertSettingsSplat = @{ DnsName = $SubjectName CertStorelocation = "Cert:\$Scope\My" KeyLength = 2048 KeyFriendlyName = $SubjectName KeyAlgorithm = 'RSA' KeyUsageProperty = 'All' Provider = 'Microsoft Enhanced RSA and AES Cryptographic Provider' FriendlyName = "TMConsole Certificate for $SubjectName" HashAlgorithm = 'Sha256' KeyExportPolicy = 'Exportable' Keyspec = 'KeyExchange' NotAfter = (Get-Date).AddYears(2) } try { Write-Verbose "New Cert Settings: $CertSettingsSplat" $TempCert = New-SelfSignedCertificate @CertSettingsSplat $NewCert = Get-ChildItem "Cert:\$Scope\My\$($TempCert.Thumbprint)" } catch { throw "Failed to create certificate: $_" } if (-Not $NewCert.PrivateKey) { throw "There was an error creating the TLS Certificate for TMConsole. No Private Key was available for export." } ## Convert the Certificate to an RSA Certificate format to export the Private Key $RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($NewCert); $RsaPrivateKeyBytesB64 = [Convert]::ToBase64String($RSACng.ExportRsaPrivateKey(), "InsertLineBreaks") ## Create the output string $PrivateKeyString = "-----BEGIN RSA PRIVATE KEY-----`r`n" $PrivateKeyString += $RsaPrivateKeyBytesB64 $PrivateKeyString += "`r`n-----END RSA PRIVATE KEY-----" ## Write the output string to the key file $PrivateKeyString | Set-Content $OutServerKeyPath -Force ## Convert the certificate to get a Public Certificate Export-Certificate -Cert $NewCert -FilePath $TempDERKeyPath -Type CERT -Force | Out-Null certutil -encode $TempDERKeyPath $OutCertificatePath | Out-Null Remove-Item -Path $TempDERKeyPath } ## Perform Mac Setup if ($IsMacOS) { ## Ensure OpenSSL is installed if (-Not (Test-Path -Path '/usr/bin/openssl')) { throw 'Open SSL is not installed' } ## Get the Hostname as the Cert Subject Name (used throught the script) $SubjectName = ($(&hostname -s)).toLower() ## ## Configure paths ## $CertFolder = Join-Path -Path '/' -ChildPath 'Users' -AdditionalChildPath $env:USER, 'Library', 'Application Support', 'tmconsole', 'certificates' Test-FolderPath -FolderPath $CertFolder $DeviceConfigFile = Join-Path -Path $CertFolder -ChildPath "$SubjectName-openssl.cnf" $AppKeyPath = Join-Path -Path $CertFolder -ChildPath 'TMConsole.key' $AppCertPath = Join-Path -Path $CertFolder -ChildPath 'TMConsole.crt' ## Create a new OpenSSL Config file for this request $OpenSSLConfigLines = @" [req] distinguished_name = req_distinguished_name x509_extensions = v3_req prompt = no [req_distinguished_name] C = US ST = MA L = Boston O = TransitionManager OU = TMConsole CN = {hostname} [v3_req] keyUsage = keyEncipherment, dataEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [alt_names] DNS.1 = {hostname} DNS.2 = {hostname}.local "@ ## Replace the {hostname} token with the Subject name $DeviceConfigLines = [System.Collections.ArrayList]@() foreach ($OpenSSLConfigLine in $OpenSSLConfigLines) { [void]$DeviceConfigLines.Add(($OpenSSLConfigLine -replace "\{hostname\}", $SubjectName)) } Set-Content -Path $DeviceConfigFile -Value $DeviceConfigLines -Force ## ## Generate a self signed cert, one request command ## ## Construct the OpenSSL command to produce the certificate $CreateSelfSignedCertComamndArgs = @( "req" "-x509" "-new" "-keyout" "$AppKeyPath" "-out" "$AppCertPath" "-nodes" "-days" "1000" "-config" "$DeviceConfigFile" ) ## Generate Certificate Write-Verbose ('Running Command: openssl ' + ($CreateSelfSignedCertComamndArgs -join ', ')) & openssl $CreateSelfSignedCertComamndArgs ## Import the Certificate to the Trusted Root store sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $AppCertPath } } |