DEV Community

DeployHQ
DeployHQ

Posted on

Enable OpenSSH on Windows with a Single Script for Unified Deployments

At DeployHQ, we're all about making developers' lives easier through automation. A common friction point for teams working in mixed environments is dealing with different deployment setups for Windows and Linux. While SSH is the standard for Linux, setting it up on Windows has traditionally been a manual, multi-step process.

What if you could configure OpenSSH Server on any Windows machine with a single, reliable script? This would allow you to use the same secure, key-based deployment method you use on Linux, paving the way for consistent, automated deployments with tools like DeployHQ.

Today, we're sharing a powerful PowerShell script that does just that. It installs and configures the OpenSSH server on Windows, letting you choose between key-only authentication (the most secure method) or a combination of password and key.

PowerShell to Rule Them All

This script is designed to be run with Administrator privileges in PowerShell 5.1 or later. It automates the entire process: checking for an existing installation, installing OpenSSH Server if needed, starting the required services, and configuring the sshd_config file for your chosen authentication method.

# Requires PowerShell 5.1 or later for some cmdlets
# Run this script with Administrator privileges
param(
    [ValidateSet('KeyOnly', 'PasswordAndKey')]
    [string]$AuthenticationMethod = 'KeyOnly' # Default value is 'KeyOnly'
)

$sshdConfigPath = "$env:ProgramData\ssh\sshd_config"

Write-Host "--- OpenSSH Server Setup and Configuration Script ---"
Write-Host "Authentication Method Selected: $AuthenticationMethod"

# --- 1. Check for OpenSSH Server Installation ---
Write-Host "Checking if OpenSSH Server is already installed..."
$isInstalled = $false
try {
    $openSshCapability = Get-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -ErrorAction SilentlyContinue
    if ($openSshCapability -and $openSshCapability.State -eq 'Installed') {
        Write-Host "OpenSSH Server is already installed. Skipping installation."
        $isInstalled = $true
    } else {
        Write-Host "OpenSSH Server is not installed."
    }
} catch {
    Write-Warning "Could not determine OpenSSH Server installation status using Get-WindowsCapability. Attempting to install anyway."
}

# --- 2. Install OpenSSH Server if not already installed ---
if (-not $isInstalled) {
    Write-Host "Installing OpenSSH Server..."
    try {
        Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 -ErrorAction Stop
        Write-Host "OpenSSH Server installed successfully."

        Write-Host "Starting sshd service..."
        Start-Service sshd -ErrorAction Stop
        Write-Host "sshd service started."

        Write-Host "Setting sshd service to start automatically..."
        Set-Service -Name sshd -StartupType Automatic -ErrorAction Stop
        Write-Host "sshd service set to automatic startup."
    } catch {
        Write-Error "Failed to install or start OpenSSH Server: $($_.Exception.Message)"
        Write-Warning "Please ensure you are running PowerShell as Administrator and have internet access."
        exit 1 # Exit if installation fails
    }
} else {
    # Ensure the service is running even if already installed
    try {
        $service = Get-Service -Name sshd -ErrorAction SilentlyContinue
        if ($service) {
            if ($service.Status -ne 'Running') {
                Write-Host "sshd service is not running. Starting it now..."
                Start-Service sshd -ErrorAction Stop
                Write-Host "sshd service started."
            }
            if ($service.StartupType -ne 'Automatic') {
                Write-Host "sshd service is not set to automatic. Setting it now..."
                Set-Service -Name sshd -StartupType Automatic -ErrorAction Stop
                Write-Host "sshd service set to automatic startup."
            }
        } else {
             Write-Warning "sshd service not found. This is unexpected if OpenSSH Server is reported as installed. Manual check recommended."
        }
    } catch {
        Write-Warning "Could not manage sshd service. Please check its status manually. Error: $($_.Exception.Message)"
    }
}

# --- 3. Configure sshd_config ---
Write-Host "Configuring sshd_config based on '$AuthenticationMethod'..."
if (-not (Test-Path $sshdConfigPath)) {
    Write-Error "sshd_config file not found at '$sshdConfigPath'. OpenSSH Server might not be fully installed or configured correctly."
    exit 1
}

try {
    # Read the content of the file
    $configContent = Get-Content -Path $sshdConfigPath -Raw

    # --- Configure PasswordAuthentication ---
    $passwordAuthLine = "PasswordAuthentication "
    if ($AuthenticationMethod -eq 'KeyOnly') {
        $passwordAuthLine += "no"
        Write-Host "Setting 'PasswordAuthentication no'."
    } else { # PasswordAndKey
        $passwordAuthLine += "yes"
        Write-Host "Setting 'PasswordAuthentication yes'."
    }

    if ($configContent -match '(?i)^\s*#?\s*PasswordAuthentication\s+(yes|no)') {
        $configContent = $configContent -replace '(?i)^\s*#?\s*PasswordAuthentication\s+(yes|no)', $passwordAuthLine
    } else {
        # Add the line if it doesn't exist
        $configContent += "`n$passwordAuthLine"
    }

    # --- Configure PubkeyAuthentication ---
    $pubkeyAuthLine = "PubkeyAuthentication yes" # Always enable for either method
    Write-Host "Setting 'PubkeyAuthentication yes'."

    if ($configContent -match '(?i)^\s*#?\s*PubkeyAuthentication\s+(yes|no)') {
        $configContent = $configContent -replace '(?i)^\s*#?\s*PubkeyAuthentication\s+(yes|no)', $pubkeyAuthLine
    } else {
        # Add the line if it doesn't exist
        $configContent += "`n$pubkeyAuthLine"
    }

    # Ensure AuthorizedKeysFile is set and uncommented
    $authorizedKeysFileLine = "AuthorizedKeysFile .ssh/authorized_keys"
    if ($configContent -notmatch '(?i)^\s*#?\s*AuthorizedKeysFile\s+\S+') {
        $configContent += "`n$authorizedKeysFileLine"
        Write-Host "Added default 'AuthorizedKeysFile .ssh/authorized_keys'."
    } elseif ($configContent -match '(?i)^\s*#\s*AuthorizedKeysFile\s+.ssh/authorized_keys') {
        $configContent = $configContent -replace '(?i)^\s*#\s*AuthorizedKeysFile\s+.ssh/authorized_keys', $authorizedKeysFileLine
        Write-Host "Uncommented 'AuthorizedKeysFile .ssh/authorized_keys'."
    }

    # Write the modified content back to the file
    Set-Content -Path $sshdConfigPath -Value $configContent -Force
    Write-Host "sshd_config updated successfully."

    # --- 4. Restart sshd service to apply changes ---
    Write-Host "Restarting sshd service to apply new configuration..."
    Restart-Service sshd -ErrorAction Stop
    Write-Host "sshd service restarted. OpenSSH Server configured."

} catch {
    Write-Error "Failed to configure sshd_config or restart service: $($_.Exception.Message)"
    exit 1
}

Write-Host "--- Script Finished ---"
Write-Host "Remember to add public keys to 'C:\Users\YourUser\.ssh\authorized_keys' for your users if you chose 'KeyOnly' or plan to use key authentication."
Enter fullscreen mode Exit fullscreen mode

How to Run the Script

  1. Save the code above as a PowerShell script file, for example, Configure-OpenSSH.ps1.

  2. Open PowerShell as an Administrator.

  3. Navigate to the directory where you saved the file.

Option 1: Default (Key-Only Authentication)

For the most secure setup, run the script without any parameters. This will disable password-based logins and enforce SSH key authentication.

.\Configure-OpenSSH.ps1
Enter fullscreen mode Exit fullscreen mode

Option 2: Enable Password and Key Authentication

If you need to allow both password and SSH key authentication as a fallback, run the script with the AuthenticationMethod parameter set to PasswordAndKey.

.\Configure-OpenSSH.ps1 -AuthenticationMethod PasswordAndKey
Enter fullscreen mode Exit fullscreen mode

What the Script Does

  1. Checks for OpenSSH: It first verifies if the OpenSSH Server feature is already installed to avoid redundant work.

  2. Installs and Starts Services: If not installed, it adds the Windows Capability for the server, starts the sshd service, and sets it to launch automatically on boot.

  3. Configures sshd_config: This is the core of the automation. The script reads the sshd_config file and intelligently modifies it:

-   It sets `PasswordAuthentication` to `no` or `yes` based on your chosen method.

-   It ensures `PubkeyAuthentication` is set to `yes`, which is essential for key-based deployments.

-   It verifies that the `AuthorizedKeysFile` directive is correctly pointing to `.ssh/authorized_keys` and is not commented out.
Enter fullscreen mode Exit fullscreen mode
  1. Applies Changes: Finally, it restarts the sshd service to ensure all the new configuration settings are applied immediately.

Unlocking Automated Deployments with DeployHQ

With OpenSSH running on your Windows server, you can now treat it just like a Linux machine in your DeployHQ projects. Simply add a new server using the standard SSH connection type, point it to your server's IP or hostname, and add the project's public key to the appropriate C:\Users\YourUser\.ssh\authorized_keys file on the Windows machine.

This simple script removes a major hurdle in cross-platform development, enabling you to build a single, streamlined deployment pipeline for all your servers, regardless of their operating system.

We at DeployHQ, have customers that have cut their expenses by following this strategy, and our support team is always happy to help :)

Top comments (0)