PowerShellでcerファイルからSSL用のpemファイルを生成する

# 目的
SSL証明書にcerファイルをWindowsのローカルマシンに登録してpemファイルを生成するPowerShellスクリプトです。
Windowsからcertlm.msc操作でも同じことができますが、スクリプト化することが作業時間を短縮して自動化することが可能です。

# 環境
path = D:\ssl
domain = test.ozawa

例:
```
 D:\ssl
    test.ozawa.com
       test.ozawa.cer # インポートするcertファイル
       password.txt   # 生成されるパスワードファイル。opensslコマンドを実行するときに必要
       test.ozawa.pfx # 生成されるpfxファイル
       privkey.pem    # 生成されるプライベートキー
       test.ozawa.pem # 生成されるパブリックキー
```

# PowerShellスクリプト
```
param(
    [string]$domain, # domain name to generate ssl certificate for
    [string]$path    # certification folder path
)

function Get-Password([int]$length=20) {
    <#
        .SYNOPSIS
            Return a random password with specified length
        .DESCRIPTION
            This function takes a length and returns a random password with the given length
        .PARAMETER len
            Length of the password to return
    #>

    $charSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()"
 
    $rng = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
    $bytes = New-Object byte[]($length)
    $rng.GetBytes($bytes)
 
    $result = New-Object char[]($length)
    for ($i = 0 ; $i -lt $length ; $i++) {
        $result[$i] = $charSet[$bytes[$i] % $charSet.Length]
    }
    $password = (-join $result)
    return $password
}

function Get-Pemfiles([string]$domain, [string]$path="C:\cert") {
    <#
        .SYNOPSIS
            Generate private and public key pem files from cert file.
        .DESCRIPTION
            This function imports cer file to Windows localmachine and export pfx file and then generate private and public pem files.
        .PARAMETER domain
            Name of the domain to generate ssl certificates.
        .PARAMETER path
            Path of certification folder. cer files should be in "path" + "domain name" folder.
    #>

    # check parameters if they have values
    if ([string]::IsNullOrWhiteSpace($domain)) {
        Write-Host "please set argument 'domain'"
        return
    }
    if ([string]::IsNullOrWhiteSpace($path)) {
        Write-Host "please set argument 'path'"
        return
    }
    try {
        # Generate password
        $pwd = Get-Password(20)  # generate random password
        $outputFile = "$($path)\$($domain)\password.txt"
        $pwd | Out-File $outputFile  # save password to a file
        Write-Host "$($path)\$($domain)\$($domain).cer"

        # import cer file into localMachine
        Import-Certificate -FilePath "$($path)\$($domain)\$($domain).cer" -CertStoreLocation cert:\LocalMachine\My

        # export certificate as pfx file
        $securePassword = ConvertTo-SecureString -String $pwd -Force -AsPlainText
        Get-ChildItem -Path cert:\LocalMachine\My | Where-Object {$_.Subject -like "CN=$($domain)*" } | Export-PfxCertificate -CryptoAlgorithmOption AES256_SHA256 -FilePath "$($path)\$($domain)\$($domain).pfx" -Password $securePassword

        # generate private key and public key pem files
        openssl pkcs12 -in "$($path)\$($domain)\$($domain).pfx" -nocerts -nodes -out "$($path)\$($domain)\privkey.pem" -passin pass:$pwd
        openssl pkcs12 -in "$($path)\$($domain)\$($domain).pfx" -clcerts -nokeys -out "$($path)\$($domain)\$($domain).pem" -passin pass:$pwd
    } catch {
      Write-Host "There was an error generating pem file: $($_.Exception.Message)"
    }
}

Get-Pemfiles -domain $domain -path $path

# 操作
1. Windowsのコマンドプロンプトを管理者として開く
2. powershell.exe -ExecutionPolicy Bypass -File "generate_pem.ps1" -domain "test.ozawa.com" -path "D:\ssl"

以上