Skip to content

Commit c0adea2

Browse files
committed
OpenSSH: install via scheduled task
It appears that Windows blocks the use of `Add-WindowsCapability` when connected to a machine via WinRM[1]. This commit updates the installation of OpenSSH components to use a scheduled task to side-step this issue. [1] https://attuneops.io/attune-hub/install-openssh-server-on-windows-via-add-windowscapability/#link4
1 parent 66bf12b commit c0adea2

File tree

2 files changed

+57
-24
lines changed

2 files changed

+57
-24
lines changed

modules/BOSH.SSH/BOSH.SSH.Tests.ps1

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,50 +61,58 @@ Describe "BOSH.SSH" {
6161
Mock Set-Service { } -ModuleName BOSH.SSH
6262
Mock Edit-DefaultOpenSSHConfig { } -ModuleName BOSH.SSH
6363

64-
Mock -ModuleName BOSH.SSH -CommandName Get-WindowsCapability { }
64+
Mock -ModuleName BOSH.SSH -CommandName shouldInstallSshComponents { $False }
6565
}
6666

67-
Context "when 'Get-OSVersion' returns 'windows2019'" {
67+
Context "When SSH components should be installed" {
6868
BeforeEach {
69-
Mock -ModuleName BOSH.SSH -CommandName Get-OSVersion { "windows2019" }
69+
Mock -ModuleName BOSH.SSH -CommandName shouldInstallSshComponents { $True }
70+
71+
Mock -ModuleName BOSH.SSH -CommandName Get-WindowsCapability { }
72+
73+
Mock -ModuleName BOSH.SSH -CommandName Start-Sleep { } -Verifiable
74+
Mock -ModuleName BOSH.SSH -CommandName Register-ScheduledTask { } -Verifiable
7075
}
7176

7277
Context "When OpenSSH components are installed" {
7378
BeforeEach {
79+
$openSshClientPackageSpecifier = "OpenSSH.Client~~~~0.0.1.0"
7480
Mock -ModuleName BOSH.SSH -CommandName Get-WindowsCapability {
7581
[PSCustomObject]@{
7682
State = "NotPresent"
77-
Name = "$Name"
83+
Name = $openSshClientPackageSpecifier
7884
}
79-
}
85+
} -ParameterFilter { $Name -eq "OpenSSH.Client*" }
8086

81-
Mock -ModuleName BOSH.SSH -CommandName Add-WindowsCapability { } -Verifiable
87+
$openSshServerPackageSpecifier = "OpenSSH.Server~~~~0.0.1.0"
88+
Mock -ModuleName BOSH.SSH -CommandName Get-WindowsCapability {
89+
[PSCustomObject]@{
90+
State = "NotPresent"
91+
Name = $openSshServerPackageSpecifier
92+
}
93+
} -ParameterFilter { $Name -eq "OpenSSH.Server*" }
8294
}
8395

8496
It "attempts to install the packages" {
8597
Install-SSHD
8698

87-
Should -Invoke -ModuleName BOSH.SSH -CommandName Add-WindowsCapability -Times 1 -ParameterFilter {
88-
$Name -like "OpenSSH.Client*"
99+
Should -Invoke -ModuleName BOSH.SSH -CommandName Start-Sleep -Times 2 -ParameterFilter { $Seconds -eq 120 }
100+
101+
Should -Invoke -ModuleName BOSH.SSH -CommandName Register-ScheduledTask -Times 1 -ParameterFilter {
102+
$TaskName -like "Run: 'Add-WindowsCapability -Online -Name $openSshClientPackageSpecifier'"
89103
}
90-
Should -Invoke -ModuleName BOSH.SSH -CommandName Add-WindowsCapability -Times 1 -ParameterFilter {
91-
$Name -like "OpenSSH.Server*"
104+
105+
Should -Invoke -ModuleName BOSH.SSH -CommandName Register-ScheduledTask -Times 1 -ParameterFilter {
106+
$TaskName -like "Run: 'Add-WindowsCapability -Online -Name $openSshServerPackageSpecifier'"
92107
}
93108
}
94109
}
95110

96111
Context "When OpenSSH components are NOT installed" {
97-
BeforeEach {
98-
Mock -ModuleName BOSH.SSH -CommandName Get-WindowsCapability {
99-
[PSCustomObject]@{ State = "NOT-NotPresent" }
100-
}
101-
Mock -ModuleName BOSH.SSH -CommandName Add-WindowsCapability { } -Verifiable
102-
}
103-
104112
It "does not attempt to install the packages" {
105113
Install-SSHD
106114

107-
Should -Not -Invoke -ModuleName BOSH.SSH -CommandName Add-WindowsCapability
115+
Should -Not -Invoke -ModuleName BOSH.SSH -CommandName Register-ScheduledTask
108116
}
109117
}
110118
}

modules/BOSH.SSH/BOSH.SSH.psm1

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,36 @@
11
function Install-SSHD
22
{
3-
if (Get-OSVersion == "windows2019") {
3+
if (shouldInstallSshComponents)
4+
{
45
# Microsoft privided OpenSSH must be installed on Windows 2019
56
# => https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?tabs=powershell&pivots=windows-server-2019
7+
8+
# Using `Add-WindowsCapability` via WinRM is blocked, as a workaround we create a task to run the install for us ¯\_(ツ)_/¯
9+
# => https://attuneops.io/attune-hub/install-openssh-server-on-windows-via-add-windowscapability/
10+
# => https://gitlab.com/attuneops/attune/-/issues/21
11+
612
$sshPackages = @("OpenSSH.Client", "OpenSSH.Server")
13+
714
foreach ($sshPackage in $sshPackages) {
8-
try {
9-
$moduleName = (Get-WindowsCapability -Online -Name "$sshPackage*" | ForEach-Object Name)
10-
Add-WindowsCapability -Online -Name $moduleName
11-
} catch {
12-
Write-Output "Error installing $moduleName : $_"
15+
$packageResult = Get-WindowsCapability -Online -Name "$sshPackage*"
16+
17+
$packageState = ($packageResult | ForEach-Object State)
18+
if ($packageState -eq "NotPresent") {
19+
$packageSpecifier = ($packageResult | ForEach-Object Name)
20+
21+
$runIn15Seconds = New-ScheduledTaskTrigger -Once -At ((Get-date) + (New-TimeSpan -Seconds 15))
22+
$runAsCurrentUserHighestPrivileges = New-ScheduledTaskPrincipal -GroupId "BUILTIN\Administrators" -RunLevel Highest
23+
$taskCommand = "-Command `"Add-WindowsCapability -Online -Name $packageSpecifier`""
24+
25+
Register-ScheduledTask `
26+
-TaskName "InstallSSHComponents" `
27+
-Description "Run: '$taskCommand'" `
28+
-Trigger $runIn15Seconds `
29+
-Principal $runAsCurrentUserHighestPrivileges `
30+
-Action (New-ScheduledTaskAction -Execute "powershell.exe" -Argument $taskCommand) `
31+
-Force
32+
33+
Start-Sleep -Seconds 120 # wait for install to trigger
1334
}
1435
}
1536
}
@@ -20,6 +41,10 @@
2041
Set-Service -Name ssh-agent -StartupType Disabled
2142
}
2243

44+
function shouldInstallSshComponents {
45+
Get-OSVersion == "windows2019"
46+
}
47+
2348
function Enable-SSHD
2449
{
2550
# Remove existing OpenSSH firewall rule and recreate with '-Profile Any' option

0 commit comments

Comments
 (0)