Automating PuTTY Agent SSH Key Loading on Windows Server Startup for Service Accounts


7 views

When implementing SSH public key authentication for automated processes on Windows Server environments, we face a persistent pain point: loading SSH keys into Pageant (PuTTY Agent) before any user logs in. Traditional approaches using the Startup folder fail because services often need SSH access before interactive logon occurs.

The robust approach involves creating a scheduled task that triggers at system startup, combined with proper key management:

@echo off
REM startup_ssh.cmd - Run as SYSTEM account
SET PAGENT="C:\Program Files\PuTTY\pageant.exe"
SET KEYFILE="C:\secure\keys\service_key.ppk"

%PAGENT% %KEYFILE% -c "C:\Program Files\PuTTY\plink.exe" -agent

1. Key Security First: Store the PPK file with restricted permissions (SYSTEM and Administrators only):

icacls "C:\secure\keys\service_key.ppk" /inheritance:r
icacls "C:\secure\keys\service_key.ppk" /grant:r "SYSTEM:(R)"
icacls "C:\secure\keys\service_key.ppk" /grant:r "Administrators:(R)"

2. Scheduled Task Configuration:

schtasks /create /tn "Load SSH Keys at Startup" /tr "C:\scripts\startup_ssh.cmd" /sc onstart /ru SYSTEM /rp /rl HIGHEST

Create a test script to validate the agent availability:

# check_agent.vbs
Set objShell = CreateObject("WScript.Shell")
Set objExec = objShell.Exec("plink -batch -agent -no-antispoof example.com echo OK")

Do While objExec.Status = 0
    WScript.Sleep 100
Loop

If objExec.ExitCode = 0 Then
    WScript.Echo "SSH Agent is functional"
Else
    WScript.Echo "Agent failure: " & objExec.StdErr.ReadAll()
End If

For environments requiring multiple keys or automated rotation:

# PowerShell alternative for key rotation
$pageant = Start-Process "pageant.exe" -ArgumentList @(
    "C:\keys\primary.ppk",
    "C:\keys\backup.ppk"
) -PassThru

Register-ObjectEvent -InputObject $pageant -EventName Exited -Action {
    Write-EventLog -LogName Application -Source "SSH Agent" -EntryType Error -EventId 100 -Message "Pageant crashed"
}

For Windows Server 2003, modify the approach using AutoIt scripting:

; pageant_loader.au3
Run('"' & @ProgramFilesDir & '\PuTTY\pageant.exe" "' & @ScriptDir & '\service_key.ppk"')
WinWait("Pageant")
WinSetState("Pageant", "", @SW_HIDE)

Compile this script and launch via Scheduled Tasks with highest privileges.


When implementing SSH public key authentication for automated processes on Windows Server (particularly versions 2003 and 2008), we face a critical infrastructure gap: Pageant (PuTTY's authentication agent) requires manual key loading during interactive sessions, but services often need SSH access before any user logs in.

After testing multiple methods across different Windows Server versions, these approaches prove most reliable:

Method 1: Scheduled Task with System Account

schtasks /create /tn "LoadSSHKey" /tr "\"C:\path\to\pageant.exe\" \"C:\path\to\privatekey.ppk\" -c \"C:\path\to\plink.exe\" -batch" /sc onstart /ru SYSTEM

Method 2: Windows Service Wrapper

Create a service that executes this PowerShell script at startup:

Start-Process "C:\path\to\pageant.exe" -ArgumentList "C:\keys\service_account.ppk" -WindowStyle Hidden
Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
"@
$hwnd = [Win32]::FindWindow("PuTTY", "Pageant")
[Win32]::ShowWindow($hwnd, 0) # SW_HIDE

When implementing this solution:

  • Store PPK files with 400 permissions (Administrators:FullControl)
  • Use encrypted key files with passphrases (though this complicates automation)
  • Consider Group Policy to restrict access to pageant.exe

For troubleshooting failures:

# Check Pageant process status:
tasklist /fi "imagename eq pageant.exe" /v

# Test key availability:
echo y | plink -v -agent username@hostname "exit" > plink_debug.log 2>&1

For modern Windows Server versions (2012+), consider:

  • Windows Subsystem for Linux (WSL) with ssh-agent
  • OpenSSH for Windows (included since Windows 10 1809/Server 2019)
  • Commercial solutions like Bitvise SSH Server