Advertisement
J2897

OpenSSH Server Configurator

Nov 25th, 2024
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # Check if the script is running with administrative privileges
  2. if (-not (New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
  3.     Write-Host "This script requires administrative privileges..."
  4.     Read-Host "Press Enter to end"
  5.     exit
  6. }
  7.  
  8. # Function to display instructions
  9. function Show-Instructions {
  10.     Clear-Host
  11.     Write-Host "==== OpenSSH Server Configuration Instructions ===="
  12.     Write-Host ""
  13.     Write-Host "This script configures the OpenSSH server on this Windows machine."
  14.     Write-Host "After installing and configuring the server settings, you need to"
  15.     Write-Host "generate and deploy SSH keys for secure access."
  16.     Write-Host ""
  17.     Write-Host "1. First, complete all necessary server configurations through this script."
  18.     Write-Host "   - Install or reinstall the OpenSSH Server."
  19.     Write-Host "   - Configure SSHD settings, the firewall rule, and SSH agent as needed."
  20.     Write-Host ""
  21.     Write-Host "2. After configuring the server, run the 'SSH_Key_Deployment_and_Connection.ps1'"
  22.     Write-Host "   script on your local machine to generate SSH keys and deploy them to this server."
  23.     Write-Host ""
  24.     Write-Host "3. Finally, use the key-based SSH connection to access this server securely."
  25.     Write-Host ""
  26.     Write-Host "Press Enter to return to the main menu..."
  27.     Read-Host
  28. }
  29.  
  30. # Function to install OpenSSH Server
  31. function Install-OpenSSHServer {
  32.     <#
  33.     .SYNOPSIS
  34.     Installs the OpenSSH Server capability.
  35.  
  36.     .DESCRIPTION
  37.     Installs the OpenSSH Server capability if it's available.
  38.  
  39.     .EXAMPLE
  40.     Install-OpenSSHServer
  41.     #>
  42.     Install-OrReinstallOpenSSHServer -InstallOnly
  43. }
  44.  
  45. # Function to reinstall OpenSSH Server
  46. function Reinstall-OpenSSHServer {
  47.     <#
  48.     .SYNOPSIS
  49.     Reinstalls the OpenSSH Server capability.
  50.  
  51.     .DESCRIPTION
  52.     Removes and reinstalls the OpenSSH Server capability if it's available.
  53.  
  54.     .EXAMPLE
  55.     Reinstall-OpenSSHServer
  56.     #>
  57.     Install-OrReinstallOpenSSHServer -Reinstall
  58. }
  59.  
  60. # Helper function to install or reinstall OpenSSH Server
  61. function Install-OrReinstallOpenSSHServer {
  62.     param (
  63.         [switch]$InstallOnly,
  64.         [switch]$Reinstall
  65.     )
  66.  
  67.     # Locate the OpenSSH Server capability
  68.     $opensshCapability = Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*'
  69.  
  70.     if ($opensshCapability) {
  71.         try {
  72.             if ($Reinstall -and $opensshCapability.State -eq 'Installed') {
  73.                 # Remove OpenSSH Server capability
  74.                 Write-Output "Removing OpenSSH Server..."
  75.                 Remove-WindowsCapability -Online -Name $opensshCapability.Name -ErrorAction Stop
  76.                 Write-Output "OpenSSH Server removed successfully."
  77.             }
  78.  
  79.             # Attempt to install OpenSSH Server capability
  80.             Write-Output "Installing OpenSSH Server..."
  81.             Add-WindowsCapability -Online -Name $opensshCapability.Name -ErrorAction Stop
  82.             Write-Output "OpenSSH Server installed successfully."
  83.         }
  84.         catch {
  85.             Write-Error "Failed to $(if ($Reinstall) {"reinstall"} else {"install"}) OpenSSH Server: $($_.Exception.Message)"
  86.         }
  87.     }
  88.     else {
  89.         Write-Error "OpenSSH Server capability not found."
  90.     }
  91. }
  92.  
  93. # Function to start and set OpenSSH service
  94. function Set-OpenSSHService {
  95.     [string]$serviceName = 'sshd'
  96.     if (Get-Service -Name $serviceName -ErrorAction SilentlyContinue) {
  97.         try {
  98.             Start-Service $serviceName
  99.             Set-Service -Name $serviceName -StartupType 'Automatic'
  100.             Write-Output "OpenSSH service started and set to start automatically."
  101.         }
  102.         catch {
  103.             Write-Error "Failed to configure OpenSSH service: $($_.Exception.Message)"
  104.         }
  105.     } else {
  106.         Write-Error "Service '$serviceName' does not exist."
  107.     }
  108. }
  109.  
  110. # Function to configure sshd_config file settings
  111. function Configure-SSHDConfig {
  112.     param (
  113.         [string]$Port
  114.     )
  115.  
  116.     $configPath = "C:\ProgramData\ssh\sshd_config"
  117.     $defaultConfigPath = "C:\Windows\System32\OpenSSH\sshd_config_default"
  118.  
  119.     # Check if the sshd_config file exists
  120.     if (-not (Test-Path -Path $configPath)) {
  121.         # If it doesn't exist, copy the default config file
  122.         try {
  123.             Copy-Item -Path $defaultConfigPath -Destination $configPath -Force
  124.             Write-Output "Copied default sshd_config file to $configPath"
  125.         }
  126.         catch {
  127.             Write-Error "Failed to copy default sshd_config file: $($_.Exception.Message)"
  128.             return
  129.         }
  130.     }
  131.  
  132.     # Function to modify or add settings in sshd_config file
  133.     function Set-ConfigLine {
  134.         param (
  135.             [string]$FilePath,
  136.             [string]$Setting,
  137.             [string]$Value
  138.         )
  139.  
  140.         # Read the file content as a single string
  141.         $content = Get-Content -Path $FilePath -Raw
  142.  
  143.         # Special handling for 'Port' to ensure it's placed before any 'Match' block
  144.         if ($Setting -eq 'Port') {
  145.             $pattern = "^\s*#?\s*Port\s+.*"  # Match lines with or without comment
  146.            
  147.             # Check if the 'Port' line exists, either commented or uncommented
  148.             if ($content -match $pattern) {
  149.                 # Replace the line with the uncommented port setting
  150.                 $content = $content -replace "^\s*#?\s*Port\s+.*", "Port $Value"
  151.             } else {
  152.                 # If the setting doesn't exist, add it before any Match block
  153.                 $matchIndex = $content.IndexOf("Match ")
  154.                 if ($matchIndex -ne -1) {
  155.                     # Insert before the 'Match' block
  156.                     $content = $content.Insert($matchIndex, "`r`nPort $Value`r`n")
  157.                 }
  158.                 else {
  159.                     # If no 'Match' block, append to the end
  160.                     $content += "`r`nPort $Value"
  161.                 }
  162.             }
  163.         }
  164.         else {
  165.             # Generic pattern for other settings
  166.             $pattern = "^\s*#?\s*$Setting\s+.*"
  167.            
  168.             if ($content -match $pattern) {
  169.                 # Replace the matched line with the uncommented version of the setting
  170.                 $content = $content -replace "^\s*#?\s*$Setting\s+.*", "$Setting $Value"
  171.             }
  172.             else {
  173.                 # If the setting isn't found, add it before any Match block or at the end
  174.                 $matchIndex = $content.IndexOf("Match ")
  175.                 if ($matchIndex -ne -1) {
  176.                     $content = $content.Insert($matchIndex, "$Setting $Value`r`n")
  177.                 }
  178.                 else {
  179.                     $content += "`r`n$Setting $Value"
  180.                 }
  181.             }
  182.         }
  183.  
  184.         # Write the updated content back to the file, trimming extra newlines
  185.         Set-Content -Path $FilePath -Value ($content.TrimEnd() + "`r`n")
  186.     }
  187.  
  188.     # Configure each setting, replacing any matching commented-out or uncommented lines
  189.     Set-ConfigLine -FilePath $configPath -Setting 'Port' -Value $Port
  190.     Set-ConfigLine -FilePath $configPath -Setting 'PasswordAuthentication' -Value 'no'
  191.     Set-ConfigLine -FilePath $configPath -Setting 'PermitRootLogin' -Value 'no'
  192.     Set-ConfigLine -FilePath $configPath -Setting 'MaxAuthTries' -Value '3'
  193.     Set-ConfigLine -FilePath $configPath -Setting 'LoginGraceTime' -Value '20'
  194.     Set-ConfigLine -FilePath $configPath -Setting 'PubkeyAuthentication' -Value 'yes'
  195.     Set-ConfigLine -FilePath $configPath -Setting 'KbdInteractiveAuthentication' -Value 'no'
  196.  
  197.     # Restart SSH service after configuration
  198.     function Restart-SSHService {
  199.         try {
  200.             Restart-Service sshd
  201.             Write-Output "SSH service restarted successfully after configuration changes."
  202.         }
  203.         catch {
  204.             Write-Error "Failed to restart SSH service: $($_.Exception.Message)"
  205.         }
  206.     }
  207.  
  208.     Restart-SSHService
  209. }
  210.  
  211. # Function to create firewall rule with optional port and force creation
  212. function New-OpenSSHFirewallRule {
  213.     param(
  214.         [int]$Port,
  215.         [switch]$Force
  216.     )
  217.  
  218.     $ruleName = "OpenSSH-Server-Custom-Port"
  219.     $existingRule = Get-NetFirewallRule -Name $ruleName -ErrorAction SilentlyContinue
  220.     if ($existingRule) {
  221.         if ($Force) {
  222.             # Remove existing rule if -Force is specified
  223.             Remove-NetFirewallRule -Name $ruleName
  224.             Write-Output "Existing firewall rule '$ruleName' was removed due to -Force."
  225.         } else {
  226.             # Notify if rule already exists and -Force is not specified
  227.             Write-Output "Firewall rule '$ruleName' already exists. Use -Force to overwrite it."
  228.             return
  229.         }
  230.     }
  231.  
  232.     # Attempt to create the new firewall rule
  233.     try {
  234.         New-NetFirewallRule -Name $ruleName -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort $Port
  235.         Write-Output "Firewall rule '$ruleName' created successfully on port $Port."
  236.     }
  237.     catch {
  238.         Write-Error "Failed to create firewall rule: $($_.Exception.Message)"
  239.     }
  240. }
  241.  
  242. # Function to start and configure ssh-agent
  243. function Start-SSHAgent {
  244.     $sshAgentService = Get-Service ssh-agent -ErrorAction SilentlyContinue
  245.     if ($sshAgentService) {
  246.         if ($sshAgentService.Status -eq "Running") {
  247.             Write-Output "SSH Agent is already running."
  248.         }
  249.         else {
  250.             try {
  251.                 Start-Service ssh-agent
  252.                 Set-Service -Name ssh-agent -StartupType 'Automatic'
  253.                 Write-Output "SSH Agent started and set to start automatically."
  254.             }
  255.             catch {
  256.                 Write-Error "Failed to start SSH Agent: $($_.Exception.Message)"
  257.             }
  258.         }
  259.     } else {
  260.         Write-Error "SSH Agent service does not exist."
  261.     }
  262. }
  263.  
  264. # Function to verify SSH setup, including service status check and local connection tests
  265. function Verify-SSHSetup {
  266.     # Path to SSHD configuration
  267.     $sshdConfigPath = "C:\ProgramData\ssh\sshd_config"
  268.  
  269.     # Display SSHD config port setting
  270.     Write-Host "sshd_config port setting:"
  271.     try {
  272.         $portSetting = (Get-Content -Path $sshdConfigPath | Select-String -Pattern '^Port').Line
  273.         Write-Output "Configured SSH Port: $portSetting"
  274.     }
  275.     catch {
  276.         Write-Error "Could not retrieve Port setting from sshd_config: $($_.Exception.Message)"
  277.     }
  278.  
  279.     # Display SSH firewall rule ports
  280.     Write-Host "SSH server firewall rule port(s):"
  281.     try {
  282.         $firewallPorts = Get-NetFirewallRule -DisplayName 'OpenSSH Server (sshd)' | Get-NetFirewallPortFilter | ForEach-Object { $_.LocalPort }
  283.         Write-Output "Firewall Rule Ports: $firewallPorts"
  284.     }
  285.     catch {
  286.         Write-Error "Could not retrieve firewall rule ports: $($_.Exception.Message)"
  287.     }
  288.  
  289.     # Check if sshd service is running
  290.     Write-Host "Checking SSH service status..."
  291.     $sshdService = Get-Service -Name 'sshd' -ErrorAction SilentlyContinue
  292.     if ($sshdService -and $sshdService.Status -eq 'Running') {
  293.         Write-Output "SSH service is running. Proceeding with connection tests..."
  294.        
  295.         # Connection test using password authentication
  296.         Write-Host "Testing SSH connection with password authentication..."
  297.         try {
  298.             $passwordAuthResult = & ssh -o PreferredAuthentications=password -o ConnectTimeout=3 -p 1337 localhost "echo 'Password authentication successful'" 2>&1
  299.             if ($passwordAuthResult -match "Password authentication successful") {
  300.                 Write-Host "Password authentication was successful."
  301.             } else {
  302.                 Write-Warning "Password authentication failed or is disabled."
  303.             }
  304.         } catch {
  305.             Write-Error "An error occurred during password authentication test: $($_.Exception.Message)"
  306.         }
  307.  
  308.         # Connection test using key authentication
  309.         Write-Host "Testing SSH connection with key authentication..."
  310.         try {
  311.             $keyAuthResult = & ssh -o PreferredAuthentications=publickey -o ConnectTimeout=3 -p 1337 localhost "echo 'Key authentication successful'" 2>&1
  312.             if ($keyAuthResult -match "Key authentication successful") {
  313.                 Write-Host "Key authentication was successful."
  314.             } else {
  315.                 Write-Warning "Key authentication failed or is disabled."
  316.             }
  317.         } catch {
  318.             Write-Error "An error occurred during key authentication test: $($_.Exception.Message)"
  319.         }
  320.     }
  321.     elseif ($sshdService) {
  322.         Write-Host "SSH service is installed but currently stopped. Skipping connection tests."
  323.     }
  324.     else {
  325.         Write-Error "SSH service ('sshd') is not installed or cannot be found."
  326.     }
  327.  
  328.     Write-Host "`nSSH setup verification complete."
  329. }
  330.  
  331. # Function to set up key-based authentication
  332. function Setup-KeyAuthentication {
  333.     $sshDir = "$env:USERPROFILE\.ssh"
  334.     $authKeysFile = "$sshDir\authorized_keys"
  335.  
  336.     # Ensure .ssh directory exists
  337.     if (-not (Test-Path -Path $sshDir)) {
  338.         New-Item -ItemType Directory -Path $sshDir -Force | Out-Null
  339.         Write-Output ".ssh directory created at $sshDir"
  340.     }
  341.  
  342.     # Create authorized_keys file with public key if it doesn't exist
  343.     if (-not (Test-Path -Path $authKeysFile)) {
  344.         # Generate keys if they don't exist
  345.         if (-not (Test-Path -Path "$sshDir\id_ed25519.pub")) {
  346.             ssh-keygen -t ed25519 -f "$sshDir\id_ed25519" -N "" | Out-Null
  347.             Write-Output "SSH key pair generated."
  348.         }
  349.  
  350.         # Copy public key to authorized_keys
  351.         $publicKey = Get-Content -Path "$sshDir\id_ed25519.pub" -Raw
  352.         Set-Content -Path $authKeysFile -Value $publicKey
  353.         Write-Output "Public key added to authorized_keys."
  354.     }
  355.     else {
  356.         Write-Output "authorized_keys file already exists."
  357.     }
  358.  
  359.     # Set appropriate permissions on authorized_keys
  360.     icacls $authKeysFile /inheritance:r /grant "$env:USERNAME:F" /grant "SYSTEM:F" | Out-Null
  361.     Write-Output "Permissions set on authorized_keys."
  362.  
  363.     # Restart SSH service to apply changes
  364.     Restart-Service sshd
  365.     Write-Output "SSH service restarted to apply key-based authentication changes."
  366. }
  367.  
  368. # Function to set up key-based authentication for administrator access
  369. function Setup-AdminKeyAuthentication {
  370.     $sshDir = "C:\ProgramData\ssh"
  371.     $authKeysFile = "$sshDir\administrators_authorized_keys"
  372.  
  373.     # Ensure ssh directory exists
  374.     if (-not (Test-Path -Path $sshDir)) {
  375.         New-Item -ItemType Directory -Path $sshDir -Force | Out-Null
  376.         Write-Output "SSH directory created at $sshDir"
  377.     }
  378.  
  379.     # Define paths for the admin key files
  380.     $adminKeyPath = "$env:USERPROFILE\.ssh\admin_id_ed25519"
  381.     $adminPublicKeyPath = "$adminKeyPath.pub"
  382.  
  383.     # Generate admin key pair if public key doesn't exist
  384.     if (-not (Test-Path -Path $adminPublicKeyPath)) {
  385.         Start-Process ssh-keygen -ArgumentList "-t", "ed25519", "-f", "$adminKeyPath" -NoNewWindow -Wait
  386.         if (Test-Path -Path $adminPublicKeyPath) {
  387.             Write-Output "Admin SSH key pair generated."
  388.         }
  389.         else {
  390.             Write-Output "Error: Failed to generate admin SSH key pair."
  391.             return  # Exit if key generation failed
  392.         }
  393.     }
  394.     else {
  395.         Write-Output "Admin SSH key pair already exists."
  396.     }
  397.  
  398.     # Copy public key to administrators_authorized_keys
  399.     $publicKey = Get-Content -Path $adminPublicKeyPath -Raw
  400.     Set-Content -Path $authKeysFile -Value $publicKey
  401.     Write-Output "Admin public key added to administrators_authorized_keys."
  402.  
  403.     # Set appropriate permissions on administrators_authorized_keys
  404.     icacls $authKeysFile /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" | Out-Null
  405.     Write-Output "Permissions set on administrators_authorized_keys."
  406.  
  407.     # Restart SSH service to apply changes
  408.     Restart-Service sshd
  409.     Write-Output "SSH service restarted to apply administrator key-based authentication changes."
  410. }
  411.  
  412. # Display menu
  413. function Show-Menu {
  414.     Clear-Host
  415.     Write-Host "1. Display Instructions"
  416.     Write-Host "2. Install OpenSSH Server"
  417.     Write-Host "3. Reinstall OpenSSH Server"
  418.     Write-Host "4. Configure OpenSSH Service"
  419.     Write-Host "5. Configure SSHD Settings"
  420.     Write-Host "6. Add Firewall Rule"
  421.     Write-Host "7. Start SSH Agent"
  422.     Write-Host "8. Verify SSH Setup"
  423.     Write-Host "9. Setup Key-Based Authentication for User"
  424.     Write-Host "10. Setup Key-Based Authentication for Administrator"
  425.     Write-Host "11. Exit"
  426. }
  427.  
  428. # Update the main loop to include the new admin key authentication function
  429. do {
  430.     Show-Menu
  431.     $choice = Read-Host "Select an option [1-11]"
  432.     switch ($choice) {
  433.         "1" { Show-Instructions }
  434.         "2" { Install-OpenSSHServer }
  435.         "3" { Reinstall-OpenSSHServer }
  436.         "4" { Set-OpenSSHService }
  437.         "5" {
  438.             $Port = Read-Host "Enter the SSH Port (default is 1337)"
  439.             if (-not $Port) { $Port = "1337" }
  440.             Configure-SSHDConfig -Port $Port
  441.         }
  442.         "6" {
  443.             $Port = Read-Host "Enter the SSH Port for Firewall Rule (default is 1337)"
  444.             if (-not $Port) { $Port = "1337" }
  445.             New-OpenSSHFirewallRule -Port $Port
  446.         }
  447.         "7" { Start-SSHAgent }
  448.         "8" { Verify-SSHSetup }
  449.         "9" { Setup-KeyAuthentication }
  450.         "10" { Setup-AdminKeyAuthentication }
  451.         "11" { Write-Host "Exiting..."; break }
  452.         default { Write-Host "Invalid selection. Please choose a valid option." }
  453.     }
  454.     Read-Host "Press Enter to continue..."
  455. } while ($choice -ne "11")
  456.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement