Public/New-TMConsoleCertificate.ps1

function New-TMConsoleCertificate {
    param (
    )

    ## Perform Windows Setup
    if ($IsWindows) {

        ## Only admins can create certificates
        if (-Not (Test-IsAdmin)) {
            throw 'Creating a certificate requires administrative permission.'
        }

        ## Provide naming details for the certificate
        $SubjectName = $env:COMPUTERNAME

        ## Create File Path variables
        $OutFolder = Join-Path -Path $Env:ProgramData -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:\LocalMachine\My'
            KeyLength         = 2048
            KeyFriendlyName   = $SubjectName
            KeyAlgorithm      = 'RSA'
            KeyUsageProperty  = 'All'
            Provider          = 'Microsoft Enhanced RSA and AES Cryptographic Provider'
            FriendlyName      = $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:\LocalMachine\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

        ## Import this certificate to the user's trusted root certificates
        try {

            Import-Certificate -FilePath $OutCertificatePath -CertStoreLocation "cert:\LocalMachine\Root" -Confirm:$False | Out-Null
        } catch {
            throw "Unable to import certificate to Local Machine Root store: $_"
        }
    }
    ## 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
    }
}