Skip to content

Instantly share code, notes, and snippets.

@silverkorn
Last active March 10, 2023 21:41
Show Gist options
  • Save silverkorn/8da0b5127dde1f74f109414f2ebb38f6 to your computer and use it in GitHub Desktop.
Save silverkorn/8da0b5127dde1f74f109414f2ebb38f6 to your computer and use it in GitHub Desktop.

Revisions

  1. silverkorn revised this gist Mar 10, 2023. 1 changed file with 82 additions and 40 deletions.
    122 changes: 82 additions & 40 deletions ssh-askpass-gui.ps1
    Original file line number Diff line number Diff line change
    @@ -1,17 +1,96 @@
    ### Global Varaibles ###

    $global:windowsTopMost = $false
    $global:returnCode = 0
    $global:privateKeyPath = $args[0]
    $global:passphraseEnvName = $args[1]
    $global:sshJob = $null
    $global:sshPassEnvVarName = $null

    ### Main Functions ###

    function OpenSSHKeyFileDialog {
    param(
    $InitialDirectory
    )
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
    $openFileDialog = New-Object System.Windows.Forms.OpenFileDialog
    #$openFileDialog = (New-Object Microsoft.Win32.OpenFileDialog)
    if (Test-Path $InitialDirectory -PathType container) {
    $openFileDialog.InitialDirectory = $InitialDirectory
    }
    $openFileDialog.Title = "Select Private Key File"
    $openFileDialog.Filter = "All Files (*.*)| *.*"
    $openFileDialog.Multiselect = $false
    $openFileDialog.AutoUpgradeEnabled = $true

    $openFileDialogWindow = $null
    if ($global:windowsTopMost) {
    $openFileDialogWindow = (New-Object System.Windows.Forms.Form -Property @{TopMost = $true })
    }

    if ($openFileDialog.ShowDialog($openFileDialogWindow)) {
    return $openFileDialog.FileName
    }
    return $null
    }

    function SSHAddKey {
    param(
    $PrivateKeyPath,
    $Passphrase
    )
    $return=$false
    #Invoke-Expression 'ssh-agent'
    Start-Process -WindowStyle Hidden ssh-agent
    $global:sshJob = Start-Job -ScriptBlock {
    $encodedPassphrase = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Using:Passphrase))
    $global:sshPassEnvVarName = "SSH_TEMP_PASS_$((( 1..16 | foreach-object {'{0:x}' -f (Get-Random -Maximum 16)}) -join '').toUpper())"
    Set-Item -Path "env:$global:sshPassEnvVarName" -Value $encodedPassphrase

    $Env:DISPLAY="0"
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" `"$global:sshPassEnvVarName`""

    $global:LASTEXITCODE = 0
    Invoke-Expression 'ssh-add "$Using:PrivateKeyPath" 2> $null > $null'

    Write-Output $global:LASTEXITCODE
    if (Test-Path -Path "env:$global:sshPassEnvVarName"){
    Remove-Item -Path "env:$global:sshPassEnvVarName"
    }
    $global:sshPassEnvVarName = $null
    }
    $global:sshJob | Wait-Job -Timeout 3 # Unfortunately, 1 second is too low and might returns false-positive
    if ($global:sshJob.JobStateInfo.State -Eq "Running"){
    Remove-Job -Force -InstanceId $global:sshJob.InstanceId > $null
    return $false
    } else {
    Receive-Job $global:sshJob -OutVariable sshJobOutput > $null
    if ([String]$sshJobOutput -Eq "0"){
    $return=$true
    } else {
    return $false
    }
    }
    return $return
    }

    ### Main Process ###

    if (([string]::IsNullOrEmpty($global:privateKeyPath)) -Or -Not (Test-Path $global:privateKeyPath -PathType leaf)){
    Exit 1
    if (Test-Path "$env:USERPROFILE\.ssh" -PathType container){
    $global:privateKeyPath = (OpenSSHKeyFileDialog -InitialDirectory "$env:USERPROFILE\.ssh")
    } else {
    $global:privateKeyPath = ({ OpenSSHKeyFileDialog })
    }
    if (([string]::IsNullOrEmpty($global:privateKeyPath)) -Or -Not (Test-Path $global:privateKeyPath -PathType leaf)){
    Exit 1
    }
    }

    if (-Not ([string]::IsNullOrEmpty($global:passphraseEnvName))){
    $decodedPassphrase = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String((Get-Item -Path "env:$global:passphraseEnvName").Value))
    Write-Output $decodedPassphrase

    Exit $global:returnCode
    }

    @@ -21,7 +100,7 @@ Add-Type -AssemblyName System.Windows.Forms
    $frmPassphrase = New-Object system.Windows.Forms.Form
    $frmPassphrase.ClientSize = New-Object System.Drawing.Point(318,120)
    $frmPassphrase.text = "OpenSSH Agent Passphrase"
    $frmPassphrase.TopMost = $false
    $frmPassphrase.TopMost = $global:windowsTopMost
    $frmPassphrase.MaximizeBox = $false
    $frmPassphrase.MinimizeBox = $false
    $frmPassphrase.FormBorderStyle = 'Fixed3D'
    @@ -85,43 +164,6 @@ function cancel() {
    $frmPassphrase.Close()
    }

    function SSHAddKey {
    param(
    $PrivateKeyPath,
    $Passphrase
    )
    $return=$false
    Invoke-Expression 'ssh-agent'
    $global:sshJob = Start-Job -ScriptBlock {
    $encodedPassphrase = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Using:Passphrase))
    $global:sshPassEnvVarName = "SSH_TEMP_PASS_$((( 1..16 | foreach-object {'{0:x}' -f (Get-Random -Maximum 16)}) -join '').toUpper())"
    Set-Item -Path "env:$global:sshPassEnvVarName" -Value $encodedPassphrase

    $Env:DISPLAY="0"
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" `"$global:sshPassEnvVarName`""

    $global:LASTEXITCODE = 0
    Invoke-Expression 'ssh-add "$Using:PrivateKeyPath" 2> $null > $null'

    Write-Output $global:LASTEXITCODE
    Remove-Item -Path "env:$global:sshPassEnvVarName"
    $global:sshPassEnvVarName = $null
    }
    $global:sshJob | Wait-Job -Timeout 5 # Unfortunately, 1 second is too low and might returns false-positive
    if ($global:sshJob.JobStateInfo.State -Eq "Running"){
    Remove-Job -Force -InstanceId $global:sshJob.InstanceId > $null
    return $false
    } else {
    Receive-Job $global:sshJob -OutVariable sshJobOutput > $null
    if ([String]$sshJobOutput -Eq "0"){
    $return=$true
    } else {
    return $false
    }
    }
    return $return
    }

    $frmPassphrase.Add_Shown({$frmPassphrase.Activate(); $txtPassphrase.Focus()})
    [void]$frmPassphrase.ShowDialog()

  2. silverkorn revised this gist Mar 2, 2023. 1 changed file with 15 additions and 18 deletions.
    33 changes: 15 additions & 18 deletions ssh-askpass-gui.ps1
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,17 @@
    $global:returnCode = 0
    $global:privateKeyPath = $args[0]
    $global:passphraseTempFile = $args[1]
    $global:passphrase = $args[2]
    $global:passphraseEnvName = $args[1]
    $global:sshJob = $null
    $global:sshPassEnvVarName = $null

    if (([string]::IsNullOrEmpty($global:privateKeyPath)) -Or -Not (Test-Path $global:privateKeyPath -PathType leaf)){
    Exit 1
    }

    if (-Not ([string]::IsNullOrEmpty($global:passphraseTempFile)) -And (Test-Path $global:passphraseTempFile)){
    $decodedPassphrase = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($global:passphrase))
    if (-Not ([string]::IsNullOrEmpty($global:passphraseEnvName))){
    $decodedPassphrase = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String((Get-Item -Path "env:$global:passphraseEnvName").Value))
    Write-Output $decodedPassphrase

    $passphraseRetryCounter = [Int]::Parse((Get-Content -TotalCount 1 -Path $global:passphraseTempFile))
    Set-Content -Path $global:passphraseTempFile -Value ($passphraseRetryCounter + 1)
    if ($passphraseRetryCounter -gt 1){
    $global:returnCode = 1
    }

    Exit $global:returnCode
    }

    @@ -72,14 +67,11 @@ function ok ($text) {
    $btnOk.enabled = $false
    $btnCancel.enabled = $false
    $txtPassphrase.enabled = $false
    $fileTemp = New-TemporaryFile
    Set-Content -Path $fileTemp.FullName -Value "0"
    $sshPassphraseSuccess = (SSHAddKey -PrivateKeyPath $global:privateKeyPath -Passphrase $text -TempFile $fileTemp.FullName)
    $sshPassphraseSuccess = (SSHAddKey -PrivateKeyPath $global:privateKeyPath -Passphrase $text)
    if ( $sshPassphraseSuccess -Eq $true){
    # Good!
    $frmPassphrase.Close()
    }
    $fileTemp.Delete()
    $btnOk.enabled = $true
    $btnCancel.enabled = $true
    $txtPassphrase.enabled = $true
    @@ -96,21 +88,26 @@ function cancel() {
    function SSHAddKey {
    param(
    $PrivateKeyPath,
    $Passphrase,
    $TempFile
    $Passphrase
    )
    $return=$false
    Invoke-Expression 'ssh-agent'
    $global:sshJob = Start-Job -ScriptBlock {
    $encodedPassphrase = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Using:Passphrase))
    $global:sshPassEnvVarName = "SSH_TEMP_PASS_$((( 1..16 | foreach-object {'{0:x}' -f (Get-Random -Maximum 16)}) -join '').toUpper())"
    Set-Item -Path "env:$global:sshPassEnvVarName" -Value $encodedPassphrase

    $Env:DISPLAY="0"
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" `"$Using:TempFile`" `"$encodedPassphrase`""
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" `"$global:sshPassEnvVarName`""

    $global:LASTEXITCODE = 0
    Invoke-Expression 'ssh-add "$Using:PrivateKeyPath" 2> $null > $null'

    Write-Output $global:LASTEXITCODE
    Remove-Item -Path "env:$global:sshPassEnvVarName"
    $global:sshPassEnvVarName = $null
    }
    $global:sshJob | Wait-Job -Timeout 3 # Unfortunately, 1 second is too low and might returns false-positive
    $global:sshJob | Wait-Job -Timeout 5 # Unfortunately, 1 second is too low and might returns false-positive
    if ($global:sshJob.JobStateInfo.State -Eq "Running"){
    Remove-Job -Force -InstanceId $global:sshJob.InstanceId > $null
    return $false
  3. silverkorn revised this gist Feb 9, 2021. No changes.
  4. silverkorn revised this gist Feb 9, 2021. 1 changed file with 23 additions and 9 deletions.
    32 changes: 23 additions & 9 deletions ssh-askpass-gui.ps1
    Original file line number Diff line number Diff line change
    @@ -1,15 +1,22 @@
    $global:returnCode = 0
    $global:privateKeyPath = $args[0]
    $global:passphraseFlag = $args[1]
    $global:passphraseTempFile = $args[1]
    $global:passphrase = $args[2]
    $global:sshJob = $null

    if (([string]::IsNullOrEmpty($global:privateKeyPath)) -Or -Not (Test-Path $global:privateKeyPath -PathType leaf)){
    Exit 1
    }

    if (-Not [string]::IsNullOrEmpty($global:passphraseFlag)){
    Write-Output $global:passphrase
    if (-Not ([string]::IsNullOrEmpty($global:passphraseTempFile)) -And (Test-Path $global:passphraseTempFile)){
    $decodedPassphrase = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($global:passphrase))
    Write-Output $decodedPassphrase

    $passphraseRetryCounter = [Int]::Parse((Get-Content -TotalCount 1 -Path $global:passphraseTempFile))
    Set-Content -Path $global:passphraseTempFile -Value ($passphraseRetryCounter + 1)
    if ($passphraseRetryCounter -gt 1){
    $global:returnCode = 1
    }
    Exit $global:returnCode
    }

    @@ -65,10 +72,14 @@ function ok ($text) {
    $btnOk.enabled = $false
    $btnCancel.enabled = $false
    $txtPassphrase.enabled = $false
    $sshPassphraseSuccess = (SSHAddKey -PrivateKeyPath $global:privateKeyPath -Passphrase $text)
    $fileTemp = New-TemporaryFile
    Set-Content -Path $fileTemp.FullName -Value "0"
    $sshPassphraseSuccess = (SSHAddKey -PrivateKeyPath $global:privateKeyPath -Passphrase $text -TempFile $fileTemp.FullName)
    if ( $sshPassphraseSuccess -Eq $true){
    $frmPassphrase.Close() # Good!
    # Good!
    $frmPassphrase.Close()
    }
    $fileTemp.Delete()
    $btnOk.enabled = $true
    $btnCancel.enabled = $true
    $txtPassphrase.enabled = $true
    @@ -85,24 +96,27 @@ function cancel() {
    function SSHAddKey {
    param(
    $PrivateKeyPath,
    $Passphrase
    $Passphrase,
    $TempFile
    )
    $return=$false
    Invoke-Expression 'ssh-agent'
    $global:sshJob = Start-Job -ScriptBlock {
    $encodedPassphrase = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Using:Passphrase))
    $Env:DISPLAY="0"
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" -- `"$($Using:Passphrase -Replace '"','"""')`""
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" `"$Using:TempFile`" `"$encodedPassphrase`""

    $global:LASTEXITCODE = 0
    Invoke-Expression 'ssh-add "$Using:PrivateKeyPath" 2> $null > $null'
    Write-Output $global:LASTEXITCODE
    }
    $global:sshJob | Wait-Job -Timeout 3 # Unfortunately, 1 second is too low and returns false-positive
    $global:sshJob | Wait-Job -Timeout 3 # Unfortunately, 1 second is too low and might returns false-positive
    if ($global:sshJob.JobStateInfo.State -Eq "Running"){
    Remove-Job -Force -InstanceId $global:sshJob.InstanceId > $null
    return $false
    } else {
    Receive-Job $global:sshJob -OutVariable sshJobOutput > $null
    if ([string]$sshJobOutput -Eq "0"){
    if ([String]$sshJobOutput -Eq "0"){
    $return=$true
    } else {
    return $false
  5. silverkorn revised this gist Feb 9, 2021. 1 changed file with 8 additions and 0 deletions.
    8 changes: 8 additions & 0 deletions ssh-askpass-gui.vbs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    Dim objShell, objFSO, objFile, strArguments
    Set objShell = WScript.CreateObject("WScript.shell")
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objFile = objFSO.GetFile(WScript.ScriptFullName)
    For Each strArgument in WScript.Arguments
    strArguments = strArguments & " " & strArgument
    Next
    objShell.Run "powershell.exe -WindowStyle Hidden -File " & """" & objFSO.GetParentFolderName(objFile) & "\" & objFSO.GetBaseName(WScript.ScriptFullName) & ".ps1""" & strArguments, 0, False
  6. silverkorn created this gist Feb 9, 2021.
    117 changes: 117 additions & 0 deletions ssh-askpass-gui.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,117 @@
    $global:returnCode = 0
    $global:privateKeyPath = $args[0]
    $global:passphraseFlag = $args[1]
    $global:passphrase = $args[2]
    $global:sshJob = $null

    if (([string]::IsNullOrEmpty($global:privateKeyPath)) -Or -Not (Test-Path $global:privateKeyPath -PathType leaf)){
    Exit 1
    }

    if (-Not [string]::IsNullOrEmpty($global:passphraseFlag)){
    Write-Output $global:passphrase
    Exit $global:returnCode
    }

    Add-Type -AssemblyName System.Windows.Forms
    [System.Windows.Forms.Application]::EnableVisualStyles()

    $frmPassphrase = New-Object system.Windows.Forms.Form
    $frmPassphrase.ClientSize = New-Object System.Drawing.Point(318,120)
    $frmPassphrase.text = "OpenSSH Agent Passphrase"
    $frmPassphrase.TopMost = $false
    $frmPassphrase.MaximizeBox = $false
    $frmPassphrase.MinimizeBox = $false
    $frmPassphrase.FormBorderStyle = 'Fixed3D'
    $frmPassphrase.StartPosition = "CenterScreen"
    $frmPassphrase.KeyPreview = $true
    $frmPassphrase.ShowIcon = $false

    $frmPassphrase.Add_KeyDown({if($_.KeyCode -eq "Enter"){ok($txtPassphrase.Text)}})
    $frmPassphrase.Add_KeyDown({if($_.KeyCode -eq "Escape"){cancel}})

    $lblPassphrase = New-Object system.Windows.Forms.Label
    $lblPassphrase.text = "Passphare for `"" + (Split-Path $global:privateKeyPath -leaf) + "`":"
    $lblPassphrase.AutoSize = $true
    $lblPassphrase.width = 25
    $lblPassphrase.height = 10
    $lblPassphrase.location = New-Object System.Drawing.Point(10,20)

    $txtPassphrase = New-Object system.Windows.Forms.MaskedTextBox
    $txtPassphrase.multiline = $false
    $txtPassphrase.width = 298
    $txtPassphrase.height = 20
    $txtPassphrase.location = New-Object System.Drawing.Point(10,42)
    $txtPassphrase.PasswordChar = ''

    $btnOk = New-Object system.Windows.Forms.Button
    $btnOk.text = "OK"
    $btnOk.width = 74
    $btnOk.height = 30
    $btnOk.location = New-Object System.Drawing.Point(157,77)

    $btnCancel = New-Object system.Windows.Forms.Button
    $btnCancel.text = "Cancel"
    $btnCancel.width = 73
    $btnCancel.height = 30
    $btnCancel.location = New-Object System.Drawing.Point(235,77)

    $frmPassphrase.controls.AddRange(@($btnOk,$btnCancel,$lblPassphrase,$txtPassphrase))

    $btnOk.Add_Click({ ok($txtPassphrase.Text) })
    $btnCancel.Add_Click({ cancel })

    function ok ($text) {
    $btnOk.enabled = $false
    $btnCancel.enabled = $false
    $txtPassphrase.enabled = $false
    $sshPassphraseSuccess = (SSHAddKey -PrivateKeyPath $global:privateKeyPath -Passphrase $text)
    if ( $sshPassphraseSuccess -Eq $true){
    $frmPassphrase.Close() # Good!
    }
    $btnOk.enabled = $true
    $btnCancel.enabled = $true
    $txtPassphrase.enabled = $true
    $txtPassphrase.text = ""
    $frmPassphrase.Activate()
    $txtPassphrase.Focus()
    }

    function cancel() {
    $global:returnCode = 1
    $frmPassphrase.Close()
    }

    function SSHAddKey {
    param(
    $PrivateKeyPath,
    $Passphrase
    )
    $return=$false
    Invoke-Expression 'ssh-agent'
    $global:sshJob = Start-Job -ScriptBlock {
    $Env:DISPLAY="0"
    $Env:SSH_ASKPASS="$Env:COMSPEC /c powershell.exe -NoLogo -NonInteractive -F `"$Using:PSCommandPath`" `"$Using:PrivateKeyPath`" -- `"$($Using:Passphrase -Replace '"','"""')`""
    $global:LASTEXITCODE = 0
    Invoke-Expression 'ssh-add "$Using:PrivateKeyPath" 2> $null > $null'
    Write-Output $global:LASTEXITCODE
    }
    $global:sshJob | Wait-Job -Timeout 3 # Unfortunately, 1 second is too low and returns false-positive
    if ($global:sshJob.JobStateInfo.State -Eq "Running"){
    Remove-Job -Force -InstanceId $global:sshJob.InstanceId > $null
    return $false
    } else {
    Receive-Job $global:sshJob -OutVariable sshJobOutput > $null
    if ([string]$sshJobOutput -Eq "0"){
    $return=$true
    } else {
    return $false
    }
    }
    return $return
    }

    $frmPassphrase.Add_Shown({$frmPassphrase.Activate(); $txtPassphrase.Focus()})
    [void]$frmPassphrase.ShowDialog()

    Exit $global:returnCode