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
    }
}