seed-ssh.ps1


function Add-Config($ssh_host,$ssh_user,$ssh_identity) {

    Write-Output ""
    Write-Output "add config identity ${ssh_identity} for target '${ssh_user}@${ssh_host}'"

    $text=@"
 
Host ${ssh_host}
  HostName ${ssh_host}
  IdentityFile ${ssh_identity}
  User ${ssh_user}
"@


    Add-Content -Path "$env:USERPROFILE/.ssh/config" "$text"

}

function Approve-Item($ssh_host,$ssh_user,$ssh_key,$ssh_options) {
    
    Write-Output ""
    Write-Output "authorize ssh public key ${ssh_key} for target '${ssh_user}@${ssh_host}'"
    
    Get-Content "$env:USERPROFILE/.ssh/${ssh_key}/id_rsa.pub" | 
        ssh "$ssh_options" "${ssh_user}@${ssh_host}" "mkdir -p ~/.ssh/ && cat >> ~/.ssh/authorized_keys"

}

Function Approve-Key($ssh_destination,$ssh_key,$ssh_options) {
    
    $_ssh_user = ''
    $_ssh_host = ''
    $_ssh_key = ''

    if ($ssh_key) {
        $_ssh_user_host = $ssh_key -Split '@'
    } else {
        $_ssh_list = $ssh_destination -split ';'
        $_ssh_user_host = $_ssh_list[0] -Split '@'
    }
    if ($_ssh_user_host.Count -eq 2) {
        $_ssh_key = $_ssh_user_host[1]
    } else {
        $_ssh_key = $_ssh_user_host[0]
    }
    $_key_ex = Test-Path -Path "$env:USERPROFILE/.ssh/${_ssh_key}/id_rsa.pub"        
    if ($_key_ex) {
        $ssh_destination -split ';' | ForEach-Object {

            $_ssh_user_host = $_ -Split '@'
            if ($_ssh_user_host.Count -eq 2) {
                $_ssh_user = $_ssh_user_host[0]
                $_ssh_host = $_ssh_user_host[1]
            } else {
                $_ssh_host = $_ssh_user_host[0]
            }
            Approve-Item -ssh_user $_ssh_user -ssh_host $_ssh_host -ssh_key $_ssh_key -ssh_options $ssh_options
            
            $ssh_identity = "~/.ssh/${_ssh_key}/id_rsa"
            Add-Config -ssh_host $_ssh_host -ssh_user $_ssh_user -ssh_identity $ssh_identity
        
        }
    
        Write-Output ""
        Write-Output "authorize done"
    } else {
        Write-Warning "authorize public key $_ssh_key not exist skip"
        Write-Warning "make sure file exist at $env:USERPROFILE/.ssh/${_ssh_key}/id_rsa.pub"
    }
}

function Set-Mode {    
    Write-Output ""
    Write-Output "fix key permission for windows docker and wsl"

    $chmod_docker = @"
docker run
--rm
--tty
--interactive
--privileged
--user root
-v '$env:USERPROFILE/.ssh:/root/.ssh'
--entrypoint bash
xiaoyao9184/docker-seed-ansible:latest
-c 'chmod -R 600 /root/.ssh/'
"@
 -replace "`r`n",''

    Invoke-Expression -Command "$chmod_docker"
}

function Save-Key($ssh_destination,$ssh_key,$ssh_options) {

    Write-Output ""
    Write-Output "save rsa key form '${ssh_destination}' to $env:USERPROFILE/.ssh/${ssh_key}"
    
    New-Item -Path "$env:USERPROFILE/.ssh/${ssh_key}/" -ItemType Directory -Force | Out-Null

    $key_public = ssh -t "$ssh_options" "${ssh_destination}" "cat ~/.ssh/id_rsa.pub"
    $key_public -join "`n" | Out-File "$env:USERPROFILE/.ssh/${ssh_key}/id_rsa.pub"

    $key_private = ssh -t "$ssh_options" "${ssh_destination}" "cat ~/.ssh/id_rsa"
    $key_private -join "`n" | Out-File "$env:USERPROFILE/.ssh/${ssh_key}/id_rsa"
    
}

function Add-Key($ssh_destination,$ssh_options) {

    Write-Output ""
    Write-Output "generate ssh rsa key on target '${ssh_destination}'"

    # https://serverfault.com/questions/939909/ssh-keygen-does-not-create-rsa-private-key
    ssh -t "$ssh_options" "$ssh_destination" "ssh-keygen -m PEM -t rsa -b 2048 -f ~/.ssh/id_rsa -q -P ''"

}

function Export-Key($ssh_destination,$ssh_options) {

    $_ssh_user_host = $ssh_destination -Split '@'
    if ($_ssh_user_host.Count -eq 2) {
        $_ssh_key = $_ssh_user_host[1]
    } else {
        $_ssh_key = $_ssh_user_host[0]
    }

    $_key_ex = Test-Path -Path "$env:USERPROFILE/.ssh/${_ssh_key}/id_rsa.pub"
    $_key_ex = $_key_ex -and (Test-Path -Path "$env:USERPROFILE/.ssh/${_ssh_key}/id_rsa")
    if (! $_key_ex) {
        Add-Key -ssh_destination $ssh_destination -ssh_options $ssh_options

        Save-Key -ssh_destination $ssh_destination -ssh_key $_ssh_key -ssh_options $ssh_options

        Set-Mode

        Write-Output ""
        Write-Output "export done"
    } else {
        Write-Warning "export private/public key $_ssh_key exist skip"
        Write-Warning "not need generate again. see $env:USERPROFILE/.ssh/${_ssh_key}/"
    }
}

function Reset-Password($ssh_destination,$ssh_options) {

    Write-Output ""
    Write-Output "reset 'root' password on target '${ssh_destination}'"

    ssh -t "$ssh_options" "$ssh_destination" "sudo passwd"

}

function Restart-SSH($ssh_destination,$ssh_options) {

    Write-Output ""
    Write-Output "restart ssh service on target '${ssh_destination}'"

    ssh -t "$ssh_options" "$ssh_destination" "sudo systemctl restart ssh"

}

function Edit-Config($ssh_destination,$ssh_options) {

    Write-Output ""
    Write-Output "config sshd 'PermitRootLogin yes' on target '${ssh_destination}'"

    ssh -t "$ssh_options" "$ssh_destination" "sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config"

}

function Enable-Root($ssh_destination,$ssh_options) {
    
    $ssh_destination -split ';' | ForEach-Object {

        Edit-Config -ssh_destination $_ -ssh_options $ssh_options

        Restart-SSH -ssh_destination $_ -ssh_options $ssh_options

        Reset-Password -ssh_destination $_ -ssh_options $ssh_options
    }

    Write-Output ""
    Write-Output "enable done"
}

function Invoke-SeedSSH() {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [Alias("root")]
        [string[]] $PermitRoot
        ,
        [Parameter(Mandatory = $false)]
        [Alias("e")]
        [string] $Export
        ,
        [Parameter(Mandatory = $false)]
        [Alias("a")]
        [string[]] $Authorize
        ,
        [Parameter(Mandatory = $false)]
        [Alias("opt")]
        [string[]] $Options
    )

    Write-Verbose ($PSBoundParameters | Format-Table | Out-String)

    if ($PermitRoot) {
        Write-Output "enable 'root' user ssh login"
        Enable-Root -ssh_destination $PermitRoot -ssh_options ($Options -join ' ')
    }

    if ($Export) {
        Write-Output "export ssh key into user home"
        Export-Key -ssh_destination $Export -ssh_options ($Options -join ' ')
    }
    
    if ($Authorize) {
        Write-Output "authorize multiple host use ssh key"
        Approve-Key -ssh_destination $Authorize -ssh_key $Export -ssh_options ($Options -join ' ')
    }
}

Set-Alias -Name "seed-ssh" -Value Invoke-SeedSSH