functions/New-SshKey.ps1

function New-WUSshKey {
    <#
        .SYNOPSIS
        Create SSH key using ssh-keygen.
 
        .DESCRIPTION
        Create an ssh key using ssh-keygen. This cmdlet use the new OpenSSH format rather than the more compatible PEM format. The new format has increased resistance to brute-force password cracking but is not supported by versions of OpenSSH prior to 6.5.
 
        .OUTPUTS
        System.String
 
        Returns the path of the created key file.
 
        .EXAMPLE
        PS C:\>New-WUSshKey -Path test_rsa
 
        This example creates test_rsa and test_rsa.pub in the path $env:USERPROFILE/.ssh and returns test_rsa path.
 
        .LINK
        Edit-WUSshKey
    #>


    [CmdletBinding(SupportsShouldProcess)]
    param (
        # Specify the location of the key file to be created, relative path from '~/.ssh' or absolute path.
        [Parameter(Mandatory,
            Position = 0,
            ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
        [ValidateNotNullOrEmpty()]
        [Alias('Path', 'LiteralPath')]
        [string]
        $KeyPath,

        # Specify a comment.
        [string]
        $Comment,

        # Specify a passphrase. Passphrase must be a minimum of 5 characters.
        [Alias('NewPassphrase')]
        [string]
        $Passphrase,

        # Specify bits. The default value is 4096.
        [ValidateNotNullOrEmpty()]
        [int]
        $Bits = 4096,

        # Specify the cipher algorithms type. The default type is rsa.
        [ValidateSet('dsa', 'ecdsa', 'ecdsa-sk', 'ed25519', 'ed25519-sk', 'rsa')]
        [string]
        $Type = 'rsa',

        # Overwrites the key file if it exists.
        [switch]
        $Force
    )

    begin {
        Set-StrictMode -Version 'Latest'

        # Escape when specifying an empty string in the command argument
        $emptyParam = @{
            '' = '""'
        }
        if ($emptyParam.ContainsKey($Comment)) {
            $Comment = $emptyParam.$Comment
        }
        if ($emptyParam.ContainsKey($Passphrase)) {
            $Passphrase = $emptyParam.$Passphrase
        }
        elseif ($Passphrase.Length -lt 5) {
            Write-Error 'Passphrase must be a minimum of 5 characters.'
            return
        }
    }

    process {
        # Get the full path of the key file and create the parent directory
        $KeyFullPath = ConvertTo-WUFullPath -LiteralPath $KeyPath -BasePath '~/.ssh' -Parents
        if (!$KeyFullPath) {
            return
        }

        # Test the parent directory of the key file
        $keyParentPath = Split-Path $KeyFullPath -Parent
        if (!$keyParentPath) {
            Write-Error "Failed to get the parent directory of path '$KeyFullPath'."
            return
        }
        if (!(Test-Path -LiteralPath $keyParentPath) -or !(Assert-WUPathProperty -LiteralPath $keyParentPath -PSProvider FileSystem -PathType Container)) {
            return
        }

        if ((Test-Path -LiteralPath $KeyFullPath)) {
            # If the key path already exists
            if (!$Force) {
                Write-Error "Path '$KeyFullPath' already exists. Specify -Force to delete the item and create a new key file."
                return
            }

            try {
                Remove-Item -LiteralPath $KeyFullPath -Force -ErrorAction Stop
            }
            catch {
                Write-Error $_ -ErrorAction $ErrorActionPreference
                return
            }
        }

        $cmd = '& ssh-keygen -qo'
        $cmd = '{0} -t "{1}" -b "{2}" -C "{3}" -N "{4}" -f "{5}"' -f $cmd, $Type, $Bits, (Convert-WUString -String $Comment -Type EscapeForPowerShellDoubleQuotation), (Convert-WUString -String $Passphrase -Type EscapeForPowerShellDoubleQuotation), (Convert-WUString -String $KeyFullPath -Type EscapeForPowerShellDoubleQuotation)

        if ($pscmdlet.ShouldProcess($cmd, 'Execute')) {
            $result = (Invoke-Expression $cmd | ForEach-Object ToString) -join [System.Environment]::NewLine
            Write-Verbose $result

            if (!(Test-Path -LiteralPath $KeyFullPath)) {
                Write-Error 'Failed to create ssh key.'
                return
            }

            return (Get-Item -LiteralPath $keyFullPath)
        }
    }
}