zigford.org/win32-openssh-package.html
2020-07-21 06:49:32 +10:00

374 lines
12 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="main.css" type="text/css" />
<link rel="stylesheet" href="blog.css" type="text/css" />
<link rel="alternate" type="application/rss+xml" title="Subscribe to this page..." href="feed.rss" />
<title>Win32 OpenSSH Package</title>
</head><body>
<div id="divbodyholder">
<div class="headerholder"><div class="header">
<div id="title">
<h1 class="nomargin"><a class="ablack" href="http://zigford.org/index.html">zigford.org</a></h1>
<div id="description"><a href="about.html">About</a><a href="links.html"> | Links</a><a href="scripts.html"> | Scripts</a><br>Sharing linux/windows scripts and tips</br></div>
</div></div></div>
<div id="divbody"><div class="content">
<!-- entry begin -->
<h3><a class="ablack" href="win32-openssh-package.html">
Win32 OpenSSH Package
</a></h3>
<!-- bashblog_timestamp: #201808140553.41# -->
<div class="subtitle">August 14, 2018 &mdash;
Jesse Harris
</div>
<!-- text begin -->
<h4 id="update-20092018">Update 20/09/2018</h4>
<p>Updated the script to UseBasicParsing so it works on Server core out of the box.
Also, if you have to allow the port on Windows Firewall:</p>
<p><code>New-NetFirewallRule -DisplayName &quot;Allow SSH&quot; -Direction Inbound -LocalPort 22 -Protocol TCP -Action Allow</code></p>
<h4 id="update-11092018">Update 11/09/2018</h4>
<p>I've made a copy of this <a href="scripts.html">script</a> which downloads the dependencies (including
PSCore. Also of note, on a machine I ran it on, I had to set the allowed .Net
TLS modes before it would let me download from github.</p>
<p><code>[Net.ServicePointManager]::SecurityProtocol = &quot;tls12, tls11, tls&quot;</code></p>
<hr />
<p>I've recently been using Macos at work in order to share
admin responsibilities across the team. Still suppporting Windows, however
there are a couple of tools I use to make working Windows from a Mac
simpler.</p>
<h2 id="powershell">PowerShell</h2>
<p>Microsoft Open-Sourced PowerShell in <a href="https://azure.microsoft.com/en-us/blog/powershell-is-open-sourced-and-is-available-on-linux/">2016</a> and today
in 2018, you can get stable installations for Macos, Linux and Windows on
<a href="https://github.com/Powershell/Powershell">github</a> which is often referred
to as PSCore.</p>
<p>As an aside, this new version of powershell is not nativly backward
compatible with compiled binary modules of the previous &quot;Windows Powershell&quot;,
however recently in development is a new module:
<a href="https://github.com/PowerShell/WindowsCompatibility">WindowsCompatibility</a>
(currently only available on Windows Insider builds) that allows your to
import &quot;Windows Powershell&quot; modules into PSCore.</p>
<p>When alpha and beta builds first became available I started testing remote
sessions from Linux and Macos to Windows (As I would prefer to work from a
unix system at work), but quickly found that the native &quot;Enter-PSSession&quot;
wasn't supported from PSCore.</p>
<h2 id="openssh">OpenSSH</h2>
<p>Around the same time, Microsoft began working with the OpenBSD's OpenSSH
project to bring official OpenSSH builds to Windows and the PSCore team
found a way to make &quot;Enter-PSSession&quot; work with this.</p>
<h2 id="packaging-pscore">Packaging PSCore</h2>
<p>Packaging PSCore is very straightforward and I won't go into detail here.
Suffice it to say that PSCore is released as an
<a href="https://en.wikipedia.org/wiki/Windows_Installer">MSI</a> and these are very
simple to deploy using tools like <a href="https://aka.ms/sccm">Configuration Manager</a>.</p>
<h2 id="openssh-package">OpenSSH Package</h2>
<p>Essentially I created a Windows Powershell script which follows the
installation directions on the Win32 OpenSSH github <a href="https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH">Installation</a> page.</p>
<h3 id="the-scripts">The Scripts</h3>
<p>Deploying an application using scripts in Configuration Manager, usually
requires 3 scripts, and this case is no exception. I have provided the all
needed scripts below:</p>
<h4 id="install.ps1">Install.ps1</h4>
<pre><code>[CmdLetBinding()]
Param()
#region Helper functions
function Get-Path {
[CmdLetBinding()]
Param(
[ValidateSet(
&quot;Machine&quot;,
&quot;User&quot;
)]$Context = &quot;User&quot;,
[Switch]$Raw
)
If ($Context -eq &quot;Machine&quot;) {
$Root = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
} else {
$Root = 'HKCU:'
}
If ($Raw){
Get-ItemPropertyValue -Path &quot;$Root\Environment&quot; -Name Path
} Else {
Try {
(Get-ItemPropertyValue -Path &quot;$Root\Environment&quot; `
-Name Path -EA SilentlyContinue) -split ';'
} Catch {
Write-Warning &quot;No user environment variables found&quot;
}
}
}
function Add-Path {
[CmdLetBinding()]
Param(
[Parameter(Mandatory=$True)]
[ValidateScript({
if (Test-Path -Path $_) {
$True
} else {
throw &quot;Unable to validate path $_&quot;
}
})]$Path,
[ValidateSet(
&quot;Machine&quot;,
&quot;User&quot;
)]$Context
)
Write-Verbose &quot;Adding $Path to environment&quot;
if ($Context -eq 'Machine') {
If (! $Path -in (Get-Path -Context Machine)){
Write-Verbose &quot;Adding $Path to machine context&quot;
setx /m PATH &quot;$(Get-Path -Context Machine -Raw);$Path&quot;
}
} else {
Write-Verbose &quot;Adding $Path to user context&quot;
If (! $Path -in (Get-Path -Context User)){
Write-Verbose &quot;Adding $Path to user context&quot;
setx PATH &quot;$(Get-Path -Context Use -Raw);$Path&quot;
}
}
}
function New-SymbolicLink {
Param($Link,$Target)
If (-Not (Test-Path -Path $Link)){
If ((Get-Item $Target).PSIsContainer) {
cmd.exe /c mklink /D $Link $Target
} Else {
cmd.exe /c mklink $Link $Target
}
}
}
#endregion
# Extract OpenSSH
$Archive = Get-ChildItem -Filter *.zip
Expand-Archive -Path $Archive -DestinationPath $env:ProgramFiles
Rename-Item -Path $Env:ProgramFiles\OpenSSH-Win64 -NewName OpenSSH
#Add InstallDir to Path
Add-Path -Path $Env:ProgramFiles\OpenSSH -Context Machine -Verbose
# Configure OpenSSH
&amp; $Env:ProgramFiles\OpenSSH\install-sshd.ps1
# Start sshd service
Start-Service -Name sshd
# Set service startup
Set-Service sshd -StartupType Automatic
Set-Service ssh-agent -StartupType Automatic
# Setup pwsh link to work around
# https://github.com/PowerShell/Win32-OpenSSH/issues/784
# Find PSCore Install and Make symbolic link
$PSCoreDir = Get-ChildItem -Path $env:ProgramFiles\PowerShell `
-Directory | Select-Object -Last 1
New-SymbolicLink -Link $env:SystemDrive\pwsh -Target $PSCoreDir.FullName
# Enable Password Authentication and set pwsh as default shell
$NewConfig = Get-Content -Path $Env:ProgramData\ssh\sshd_config |
ForEach-Object {
Switch ($_) {
{$_ -match '^#PasswordAuthentication\syes'} {$_.replace('#','')}
{$_ -match '^#PubkeyAuthentication\syes'} {$_.replace('#','')}
{$_ -match '^Subsystem\s+sftp\s+'} {
'Subsystem powershell c:\pwsh\pwsh.exe -sshs -NoLogo -NoProfile'
}
Default {$_}
}
}
# Update sshd config
Set-Content -Path $Env:ProgramData\ssh\sshd_config -Value $NewConfig `
-Force
# Restart sshd
Restart-Service sshd
</code></pre>
<h4 id="uninstall.ps1">Uninstall.ps1</h4>
<pre><code>[CmdLetBinding()]
Param()
#region Helper functions
function Remove-SymbolicLink {
Param($Link,$Target)
If (Test-Path -Path $Link){
If ((Get-Item $Target).PSIsContainer) {
cmd.exe /c rmdir $Link
} Else {
cmd.exe /c del $Link
}
}
}
function Get-Path {
[CmdLetBinding()]
Param(
[ValidateSet(
&quot;Machine&quot;,
&quot;User&quot;
)]$Context = &quot;User&quot;,
[Switch]$Raw
)
If ($Context -eq &quot;Machine&quot;) {
$Root = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager'
} else {
$Root = 'HKCU:'
}
If ($Raw){
Get-ItemPropertyValue -Path &quot;$Root\Environment&quot; -Name Path
} Else {
Try {
(Get-ItemPropertyValue -Path &quot;$Root\Environment&quot; `
-Name Path -EA SilentlyContinue) -split ';'
} Catch {
Write-Warning &quot;No user environment variables found&quot;
}
}
}
function Remove-Path {
[CmdLetBinding()]
Param(
[Parameter(Mandatory=$True)]
$Path,
[ValidateSet(
&quot;Machine&quot;,
&quot;User&quot;
)]$Context
)
Write-Verbose &quot;Removing $Path from environment&quot;
if ($Context -eq 'Machine') {
If ($Path -in (Get-Path -Context Machine)){
Write-Verbose &quot;Removing $Path from machine context&quot;
$NewPath = &quot;&quot;
Get-Path -Context Machine | Where-Object {
$psItem -ne $Path -and
$psItem -ne &quot;&quot;
} ForEach-Object {
$NewPath += &quot;$psItem;&quot;
}
setx /m PATH &quot;$NewPath&quot;
}
} else {
Write-Verbose &quot;Removing $Path from user context&quot;
If ($Path -in (Get-Path -Context User)){
Write-Verbose &quot;Removing $Path from user context&quot;
$NewPath = &quot;&quot;
Get-Path -Context User | Where-Object {
$psItem -ne $Path -and
$psItem -ne &quot;&quot;
} ForEach-Object {
$NewPath += &quot;$psItem;&quot;
}
setx PATH &quot;$NewPath&quot;
}
}
}
#endregion
&amp; $Env:ProgramFiles\OpenSSH\uninstall-sshd.ps1
# Extract OpenSSH
Remove-Item -Path $env:ProgramFiles\OpenSSH -Recurse -Force
Remove-Path -Path $env:ProgramFiles\OpenSSH -Context Machine -Verbose
# Find PSCore Install and remove symbolic link
$PSCoreDir = Get-ChildItem -Path $env:ProgramFiles\PowerShell -Directory | Select-Object -Last 1
Remove-SymbolicLink -Link $env:SystemDrive\pwsh -Target $PSCoreDir.FullName
# Remove old config
Remove-Item -Path $env:ProgramData\ssh -Recurse -Force
</code></pre>
<h4 id="detect.ps1">Detect.ps1</h4>
<pre><code>$AssumeInstalled = $True
If (-Not (Test-Path $Env:ProgramFiles\OpenSSH)) {
$AssumeInstalled = $False
}
If (-Not (Test-Path $Env:SystemDrive\pwsh)) {
$AssumeInstalled = $False
}
If (-Not (Get-Service sshd -ErrorAction SilentlyContinue)) {
$AssumeInstalled = $False
}
If ($AssumeInstalled) {
Write-Output &quot;True&quot;
}
</code></pre>
<h2 id="using-openssh-with-powershell">Using OpenSSH with Powershell</h2>
<p>Now that I have used these scripts to deploy OpenSSH and PSCore, I can
PSRemote to a PC using my Mac.</p>
<p>The old way to use &quot;Enter-PSSession&quot; was by specifying the ComputerName
parameter like so:</p>
<pre><code>PS\&gt; Enter-PSSession -ComputerName Blah
</code></pre>
<p>However, when using OpenSSH with a PS Session you do the following:</p>
<pre><code>PS\&gt; Enter-PSSession -HostName Blah -UserName MrBlah
</code></pre>
<p>You could also setup a session in a variable and resue it multiple times
in a session:</p>
<pre><code>PS\&gt; $s = New-PSSesssion -HostName Blah -UserName MrBlah
PS\&gt; Enter-PSSession -Session $s
[Blah] PS\&gt;
</code></pre>
<p>I hope you have found this usefull.</p>
<p>Tags: <a href='tag_powershell.html'>powershell</a>, <a href='tag_pscore.html'>pscore</a>, <a href='tag_openssh.html'>openssh</a>, <a href='tag_windows.html'>windows</a>, <a href='tag_macos.html'>macos</a></p>
<!-- text end -->
<!-- entry end -->
</div>
<div id="footer">&copy <a href="http://twitter.com/zigford_org">Jesse Harris</a> &mdash; <a href="mailto:jesse&#64;zigford&#46;org">jesse&#64;zigford&#46;org</a><br/>
Generated with <a href="https://github.com/cfenollosa/bashblog">bashblog</a>, a single bash script to easily create blogs like this one</div>
</div></div>
</body></html>