OpenSSH Sunucusunu Windows 10'a Dağıtın


PowerShell 7, onu benimsemek için bir dizi zorlayıcı neden sunuyor. En iyilerinden biri, PowerShell uzaktan iletişim protokolü olarak SSH'yi desteklemektir. Ne yazık ki bu, genellikle Windows merkezli BT Uzmanlarının gündeme getirdiği bir konu değildir. Bunun benim durumumda kesinlikle doğru olduğunu ve üzerinde çalıştığım bir eksiklik olduğunu biliyorum. Artı tarafta, Windows 10, OpenSSH istemcisi kurulu ve kullanıma hazır olarak gelir. Peki OpenSSH Sunucusu ne olacak? Windows platformlarında PowerShell'de SSH uzaktan iletişimini kullanmak istiyorsanız bu öğeyi etkinleştirmeniz ve yapılandırmanız gerekir. Doğal olarak bunu PowerShell ile ve uzaktan da yapmak isterim. Öncelikle Windows 10'da OpenSSH Sunucu bileşeninin nasıl kurulacağını göstermek istiyorum.

Elle kurulum

Windows 10'da OpenSSH Sunucu bileşenini yüklemek için PowerShell komutları oldukça basittir. Öncelikle yeteneğe ihtiyacım var. Bu komutları etkileşimli olarak çalıştırıyorum.

Get-WindowsCapability -online -name openssh.server* | Add-WindowsCapability -online

Sürüm numarasının bir noktada değişmesi ihtimaline karşı Get-WindowsCapability'yi joker karakterle kullanıyorum. Bunun işe yaradığını görebiliyorum.

Bu, çalışmayan ve manuel olarak başlayacak şekilde yapılandırılmış olan sshd hizmetini ayarlayacaktır. Hizmeti otomatik olarak başlayacak ve başlayacak şekilde yapılandırmak istiyorum.

Set-Service -Name sshd -StartupType Automatic
Start-Service -Name sshd

Ssh hakkında öğrendiğim bir şey var, özellikle de onu PowerShell uzaktan iletişimi ile kullanmak istiyorsanız ve bu da ssh'nin PowerShell dışında çalıştığını doğrulamaktır.

ssh localhost

Anahtarları kabul etme ve şifre girmeniz istenebilir. Kurulumunuz benimki gibiyse, bir CMD istemiyle karşılaşacaksınız. Ama belki ssh üzerinden bağlanırken farklı bir kabuk istersiniz. Henüz PowerShell'in ssh üzerinden uzaktan iletişiminden konuşmadığımı unutmayın. Bilgisayarınızdaki kayıt defterini değiştirebilirsiniz.

$regPath = "HKLM:\SOFTWARE\OpenSSH\"
$regProperty = "DefaultShell"
$regValue = (Get-Command powershell.exe).source
Set-ItemProperty -Path $regPath -Name $regProperty -Value $regValue

Değişiklik anında yapılmalı ve sshd hizmetinin yeniden başlatılmasını gerektirmemelidir. Localhost'a bağlanmak için ssh kullanmak artık bana bir Windows PowerShell oturumu sağlıyor. Bu komutları etkileşimli olarak çalıştırmak için basit bir PowerShell betiğini oluşturmak çok fazla zaman almaz.

Uzaktan Kurulum

Ancak bunu uzaktan yapmak istiyorum. Ssh ile bağlanmak istediğim bazı Windows 10 VM'lerim var. Geleneksel PowerShell uzaktan iletişimini kullanmam gerekecek. Evet, psexec.exe gibi bir üçüncü taraf aracı veya İstenilen Durum Yapılandırması gibi bir şey kullanabilirsiniz, ancak ben muhtemelen zaten sahip olduğunuz araçlara ve becerilere bağlı kalmak istiyorum.

Bunun üzerinde çalışırken, size az önce gösterdiğim adımları çalıştıran basit bir PowerShell betiğim vardı. Yapmam gereken tek şeyin betiği Invoke-Command kullanarak çalıştırmak olduğunu düşündüm. Hayır. Add-WindowsCapability komutunun uzaktan iletişim oturumunda çalışmadığı ortaya çıktı. Görünüşe göre bu, isteğe bağlı özellik kurulumunda bilinen bir sınırlamadır. Ama bunun beni durdurmasına izin vermeyecektim. Nihai geçici çözümüm, OpenSSH.Server'ı SİSTEM olarak ekleyecek geçici bir zamanlanmış görev oluşturmaktı.

$Time = New-ScheduledTaskTrigger -At 23:59 -Once
$User = New-ScheduledTaskPrincipal System
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument '-noprofile -command "& { Get-WindowsCapability -online -name openssh.server* | Add-WindowsCapability -online}"'
$tmpTask = Register-ScheduledTask -taskpath \ -TaskName "AddTask" -Trigger $Time -Principal $user -Action $Action
Start-ScheduledTask -TaskName AddTask

#give the task a chance to finish
Start-Sleep -Seconds 20

$tmpTask | Unregister-ScheduledTask -confirm:$false

Tetikleme süresinin bir önemi yok çünkü görevi manuel olarak başlatacağım ve sonra kaldıracağım. Gece yarısına bu kadar yakın koşmadığım sürece sorun yok.

Ayrıca, kod uzaktan çalışıyor olsa bile betiğimin -WhatIf'i desteklemesini ve Verbose çıktısı sunmasını istedim. İşte bulduğum senaryo.

#requires -version 5.1

<#
This is used to setup SSHD on a Windows 10 Client through PowerShell remoting

Sample usage
Verbose and Whatif
invoke-command -FilePath .\Setup-SSHServer.ps1 -ComputerName win10 -cred $artd -ArgumentList @("Continue",$True)

Verbose
invoke-command -FilePath .\Setup-SSHServer.ps1 -ComputerName win10 -cred $artd -ArgumentList @("Continue")
#>

[cmdletbinding(SupportsShouldProcess)]
param ([string]$VerboseOption = "SilentlyContinue", [bool]$WhatIfOption = $False)

$VerbosePreference = $VerboseOption
$WhatIfPreference = $WhatIfOption

Write-Verbose "Starting SSHD setup process"
Try {
    Write-Verbose "Testing for sshd service"
    $svc = Get-Service -Name sshd -ErrorAction Stop
    if ($svc.status -eq 'Running') {
        Write-Verbose "sshd service appears to be installed and running"
    }
    else {
        Write-Warning "sshd service found but it isn't running"
    }
    #take no further action
    Return "OpenSSH Server installation appears to be complete."
}
Catch {
    Write-Verbose "sshd service not found. Continuing with installation"
}

Write-Verbose "Testing OpenSSH.Server Windows capability"
if (-Not $svc) {
    Try {
        $cap = Get-WindowsCapability -Name OpenSSH.Server* -Online -ErrorAction Stop
        $cap | Out-String | Write-Verbose
    }
    Catch {
        Throw $_
    }
}

if ($cap.State -eq 'NotPresent' -And $cap.name -match "OpenSSH") {
    #install capability
    Try {
        Write-Verbose "Adding $($cap.name)"
        if ($pscmdlet.ShouldProcess($cap.Name)) {
            #installing with a Scheduledtask as System to get around the limitation
            #with Add-WindowsCapability in a PowerShell remoting session
            $Time = New-ScheduledTaskTrigger -At 23:59 -Once
            $User = New-ScheduledTaskPrincipal System
            $action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument '-noprofile -command "& { Get-WindowsCapability -online -name openssh.server* | Add-WindowsCapability -online}"'
            $tmpTask = Register-ScheduledTask -taskpath \ -TaskName "AddTask" -Trigger $Time -Principal $user -Action $Action
            Start-ScheduledTask -TaskName AddTask

            #give the task a chance to finish
            Start-Sleep -Seconds 20

            $tmpTask | Unregister-ScheduledTask -confirm:$false
        } #Whatif
    }
    Catch {
        Throw $_
    }
}

Write-Verbose "Set sshd to auto start"
Try {
    if ($pscmdlet.ShouldProcess("sshd", "Configure service")) {
        Set-Service -Name sshd -StartupType Automatic -ErrorAction stop
        Write-Verbose "Start the sshd service"
        Start-Service -Name sshd -ErrorAction Stop
        Get-Service sshd | Select-Object -Property * | Out-String | Write-Verbose
    }
}
Catch {
    Write-Warning "There was a problem configuring the sshd service."
}

if (-Not $WhatIfOption) {
    #only display the summary if not using -WhatIf
    $msg = @"
SSH setup complete. Edit $ENV:ProgramData\ssh\sshd_config for additional configurations options
or to enable remoting under PowerShell 7.

You will need to restart the sshd service for changes to take effect.

"@
    Write-Host $msg -ForegroundColor green
}

Write-Verbose "Ending SSHD setup process."

Kod, etkileşimli olarak çalıştıracağınızdan biraz farklıdır. Invoke-Command'ı çalıştırdığınızda ve bir dosya belirttiğinizde, PowerShell dosyanın içeriğini bir komut dosyası bloğu olarak ele alır ve onu uzak bir çalışma alanında çalıştırır. Bu nedenle parametreler tipik fonksiyon parametreleri değildir. Verbose ve WhatIf tercihlerini orijinal komuttan betiğe aktarıyorum.

Invoke-Command -FilePath .\Setup-SSHServer.ps1 -ComputerName win10 -cred $artd -ArgumentList @("Continue", $True)

Bu bana uzak Windows 10 makinesinden Verbose ve Whatif çıktısını veriyor. Komut dosyasını varsayılan değerlerle çalıştırmak gayet iyi çalışıyor. İsterseniz varsayılan kabuğu ayarlamak için kayıt defteri satırlarını ekleyebilirsiniz. Ancak sonuçta onlara ihtiyacım kalmaması için ssh üzerinden PowerShell uzaktan iletişimini yapılandırmak istiyorum.

PowerShell 7 SSH Uzaktan İletişim

Uzaktan iletişimi ssh kullanacak şekilde yapılandırmanın son bir adımı vardır ve bu, uzaktaki makinede gerçekleşir. $env:ProgramData\ssh içinde bulunan sshd_config dosyasını düzenlemeniz gerekir. İşte gerekli PowerShell gereksinimleriyle düzenlenmiş kopyam.

# This is the sshd server system-wide configuration file.  See
# sshd_config(5) for more information.

# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented.  Uncommented options override the
# default value.

#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::

#HostKey __PROGRAMDATA__/ssh/ssh_host_rsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_dsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_ecdsa_key
#HostKey __PROGRAMDATA__/ssh/ssh_host_ed25519_key

# Ciphers and keying
#RekeyLimit default none

# Logging
#SyslogFacility AUTH
#LogLevel INFO

# Authentication:

#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10

#ENABLED
PubkeyAuthentication yes

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
# but this is overridden so installations will only check .ssh/authorized_keys
AuthorizedKeysFile	.ssh/authorized_keys

#AuthorizedPrincipalsFile none

# For this to work you will also need host keys in %programData%/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes

# To disable tunneled clear text passwords, change to no here!
# ENABLED: Set this to YES for PowerShell remoting
PasswordAuthentication yes

#PermitEmptyPasswords no

#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
#PermitTTY yes
#PrintMotd yes
#PrintLastLog yes
#TCPKeepAlive yes
#UseLogin no
#PermitUserEnvironment no
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none

# no default banner path
#Banner none

# override default of no subsystems
Subsystem	sftp	sftp-server.exe
#ADDED
Subsystem     powershell c:\progra~1\powershell\7\pwsh.exe -sshs -NoLogo

# Example of overriding settings on a per-user basis
#Match User anoncvs
#	AllowTcpForwarding no
#	PermitTTY no
#	ForceCommand cvs server

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys

Kuruluşunuza bağlı olarak ek değişikliklere ihtiyacınız olabilir. OpenSSH.Server ve PowerShell 7'nin kurulu olduğunu varsayarak bu dosyayı uzaktaki bilgisayara kopyalamak için PowerShell'i kullanabilirim.

Copy-Item -Path .\sshd_config_default -Destination $env:ProgramData\ssh\sshd_config -ToSession $sess

Değişikliklerin etkili olması için sshd hizmetinin yeniden başlatılması gerekir.

Dağıtım

Son adım, tüm bunları bir ana kontrol komut dosyasına bir araya getirmektir. PSReleaseTools modülümü kullanarak PowerShell 7'yi de yüklemek için kod eklemeye karar verdim.

#requires -version 5.1

#Deployment control script to setup SSH server on a remote Windows 10 desktop
#It is assumed PowerShell 7 is, or will be, installed.

[cmdletbinding(SupportsShouldProcess)]
Param(
    [Parameter(Position = 0, Mandatory)]
    [string]$Computername,
    [pscredential]$Credential,
    [switch]$InstallPowerShell
)

#remove parameters from PSBoundparameter that don't apply to New-PSSession
if ($PSBoundParameters.ContainsKey("InstallPowerShell")) {
    [void]($PSBoundParameters.remove("InstallPowerShell"))
}

if ($PSBoundParameters.ContainsKey("WhatIf")) {
    [void]($PSBoundParameters.remove("WhatIf"))
}

#parameters for Write-Progress
$prog = @{
    Activity = "Deploy SSH Server to Windows 10"
    Status = $Computername.toUpper()
    CurrentOperation = ""
    PercentComplete = 0
}
#create the PSSession
Try {
    Write-Verbose "Creating a PSSession to $Computername"
    $prog.CurrentOperation = "Creating a temporary PSSession"
    $prog.PercentComplete = 10
    Write-Progress @prog
    $sess = New-PSSession @PSBoundParameters -ErrorAction Stop
}
Catch {
    Throw $_
}

if ($sess) {
    if ($InstallPowerShell) {
        $prog.currentOperation = "Installing PowerShell 7"
        $prog.percentComplete = 25
        Write-Progress @prog
        #install PowerShell
        if ($pscmdlet.ShouldProcess($Computername.toUpper(),"Install PowerShell 7")) {

            Invoke-Command -ScriptBlock {
                [void](Install-PackageProvider -Name nuget -force -forcebootstrap)
                Install-Module PSReleaseTools -Force
                Install-PowerShell -EnableRemoting -EnableContextMenu -mode Quiet
            } -session $sess
        } #whatif
    }

    #setup SSH
    $prog.currentOperation = "Installing OpenSSH Server"
    $prog.percentComplete = 50
    Write-Progress @prog
    Invoke-Command -FilePath .\Setup-SSHServer.ps1 -Session $sess -ArgumentList @($VerbosePreference, $WhatIfPreference)

    #copy the sshd_config file. This assumes you've installed PowerShell 7 on the remote computer
    Write-Verbose "Copying sshd_config to target"
    $prog.currentOperation = "Copying default sshd_config to target"
    $prog.percentcomplete = 60
    Write-Progress @prog
    Copy-Item -Path .\sshd_config_default -Destination $env:ProgramData\ssh\sshd_config -ToSession $sess

    #restart the service
    Write-Verbose "Restarting the sshd service on the target"
    $prog.currentOperation = "Restarting the ssh service target"
    $prog.percentComplete = 75
    Write-Progress @prog
    if ($pscmdlet.ShouldProcess("sshd","Restart service")) {
        Invoke-Command { Restart-Service -Name sshd } -Session $sess
    }

    Write-Verbose "Removing the temporary PSSession"
    $prog.currentOperation = "Removing temporary PSSession"
    $prog.percentComplete = 90
    Write-Progress @prog
    $sess | Remove-PSSession

    Write-Progress @prog -completed
    $msg = @"

SSH Server deployment complete for $($Computername.toUpper()).

If PowerShell 7 is installed remotely, you should be able to test
with an expression like:

Enter-PSSession -hostname $Computername -username <user> -sshtransport

"@

    Write-Host $msg -ForegroundColor yellow
} #if $sess

Muhtemelen sshd hizmetini yapılandırma konusunda daha iyi hata yönetimi eklemeliyim ancak bu, bunu yapabilmem için her şeyi ayarlamalıdır:

Sonraki adımlar

Ssh ve PowerShell ile Windows yolculuğumun bir sonraki kısmı Windows sunucularımı yapılandırmak. Bu yapıldıktan sonra, hemen hemen her şey için ssh üzerinden PowerShell uzaktan iletişimini kullanabilirim. Yarın bu konuya dalacağım.

İlgili makaleler