Skip to content

Instantly share code, notes, and snippets.

@Pandry
Last active August 27, 2020 11:46
Show Gist options
  • Save Pandry/8494d9dab993b72148272b00ff4fa8e0 to your computer and use it in GitHub Desktop.
Save Pandry/8494d9dab993b72148272b00ff4fa8e0 to your computer and use it in GitHub Desktop.
SSH Server on Windows
# Author: github.com/Pandry
# Version: 1.1
# Tested: Windows Server 2012 with Powershell 4
# Lowest system tested: Windows Server 2008 R2 SP1 with Powershell 3
#Your Public Key
$SSHPublicKey = ""
if ((Get-Host).Version.Major -lt 3){
Write-Host -ForegroundColor Red "Warning! This script has not been tested with your powershell version $((Get-Host).Version.Major)!"
exit 1
}
# Check for permissions to execute actions
if (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")){
Write-Host -ForegroundColor Red "Error! Needed Administrator permissions to run!"
exit 1
}
try {
if ((Get-Command "Get-WindowsCapability" -errorAction SilentlyContinue) -And ((Invoke-Expression "(Get-WindowsCapability -Online | ? Name -like 'OpenSSH*').count") -eq 2) ) {
Write-Host -ForegroundColor Green "Installing as Windows Capability"
# OpenSSH can be installed as a windows feature
# If installing the feature returns an error (0x800f0954), there is a gp that blocks the installation
# gpedit.msc => "Computer Configuration/Administrative Templates/System" "Specify settings for optional component installation and component repair" => Enable and tick the Download content from windows update checkbox (or delete this block )
Get-WindowsCapability -Online | ? name -like *OpenSSH.Client* | Add-WindowsCapability -Online
Get-WindowsCapability -Online | ? name -like *OpenSSH.Server* | Add-WindowsCapability -Online
# Create a firewall rule if necessary
if ((Get-NetFirewallRule -Name *ssh* | group Name).count -eq 0) {
# The rule name is the same as the one the installation of the feature creates
New-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
}
} else {
if (-not (Test-Path "C:\Program Files\OpenSSH" -PathType container )){
Write-Host -ForegroundColor Green "Installing downloading the binary"
# OpenSSH cannot be installed as a Windows feature
# "Hacky" way to set the SecurityProtocol to the latest version
# This is required (at least TLS1.1) to maange the HTTPS link
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::$([Net.SecurityProtocolType].GetEnumNames()[[Net.SecurityProtocolType].GetEnumNames().count -1])
# The previous line can create some issue from time to time, temporarly using TLS12
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
#Download the latest version of the SSH server
$opensshUrlPath = "https://github.com/PowerShell/Win32-OpenSSH/releases/latest/download/OpenSSH-Win64.zip"
$downloadPath = "$env:temp\OpenSSH-Win64.zip"
(New-Object -TypeName System.Net.WebClient).DownloadFile("$opensshUrlPath", "$downloadPath")
# Unzip the file into the program files path
if (Get-Command "Expand-Archive" -errorAction SilentlyContinue) {
Expand-Archive -LiteralPath "$downloadPath" -DestinationPath "C:\Program Files\" -Force
} else {
[System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
[System.IO.Compression.ZipFile]::ExtractToDirectory($downloadPath, "C:\Program Files\")
}
# Remove the ZIP file
Remove-Item "$downloadPath"
# Rename the openssh version to the lastet version
Rename-Item "C:\Program Files\OpenSSH-Win64" "C:\Program Files\OpenSSH"
powershell.exe -ExecutionPolicy ByPass -File "C:\Program Files\OpenSSH\install-sshd.ps1"
}else{
Write-Host -ForegroundColor Yellow "Seems like the server is already installed"
}
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'
}
try {
# Create a firewall rule if necessary
if (Get-Command "Get-WindowsCapability" -errorAction SilentlyContinue) {
if ((Get-NetFirewallRule -Name *ssh* | group Name).count -eq 0 ) {
# The rule name is the same as the one the installation of the feature creates
New-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
}
}else{
netsh advfirewall firewall add rule name="OpenSSH-Server-In-TCP" description="OpenSSH Server (sshd)" dir=in action=allow protocol=TCP localport=22
}
} catch {
Write-Host -ForegroundColor Red "Error in checking or creating the firewall rule:"
Write-Host $_
}
# Adding SSH Key
if ($SSHPublicKey -ne "" -And (-not (Test-Path "C:\ProgramData\ssh\administrators_authorized_keys" -PathType leaf ))) {
Set-Content -Path "C:\ProgramData\ssh\administrators_authorized_keys" -Value $SSHPublicKey
Write-Host -ForegroundColor Green "Setted public key"
}
$acl = Get-Acl "C:\ProgramData\ssh\administrators_authorized_keys"
$acl.SetAccessRuleProtection($true, $false)
$administratorsRule = New-Object system.security.accesscontrol.filesystemaccessrule("Administrators","FullControl","Allow")
$systemRule = New-Object system.security.accesscontrol.filesystemaccessrule("SYSTEM","FullControl","Allow")
$acl.SetAccessRule($administratorsRule)
$acl.SetAccessRule($systemRule)
$acl | Set-Acl
} catch [System.Management.Automation.CommandNotFoundException] {
Write-Host -ForegroundColor Red "Error in executing the script. Command not found:"
Write-Host $_
} catch {
Write-Host -ForegroundColor Red "Error in executing the script."
Write-Host "${$_.Exception.ItemName}: ${$_.Exception.Message}"
Write-Host -ForegroundColor Red "Full exception:"
Write-Host $_
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment