Skip to content

Commit 311be56

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 c428863 commit 311be56

File tree

2 files changed

+65
-24
lines changed

2 files changed

+65
-24
lines changed

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

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -61,50 +61,59 @@ 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
75+
Mock -ModuleName BOSH.SSH -CommandName Get-ScheduledTaskInfo { }
7076
}
7177

7278
Context "When OpenSSH components are installed" {
7379
BeforeEach {
80+
$openSshClientPackageSpecifier = "OpenSSH.Client~~~~0.0.1.0"
7481
Mock -ModuleName BOSH.SSH -CommandName Get-WindowsCapability {
7582
[PSCustomObject]@{
7683
State = "NotPresent"
77-
Name = "$Name"
84+
Name = $openSshClientPackageSpecifier
7885
}
79-
}
86+
} -ParameterFilter { $Name -eq "OpenSSH.Client*" }
8087

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

8497
It "attempts to install the packages" {
8598
Install-SSHD
8699

87-
Should -Invoke -ModuleName BOSH.SSH -CommandName Add-WindowsCapability -Times 1 -ParameterFilter {
88-
$Name -like "OpenSSH.Client*"
100+
Should -Invoke -ModuleName BOSH.SSH -CommandName Start-Sleep -Times 2
101+
102+
Should -Invoke -ModuleName BOSH.SSH -CommandName Register-ScheduledTask -Times 1 -ParameterFilter {
103+
$TaskName -like "Install-$openSshClientPackageSpecifier"
89104
}
90-
Should -Invoke -ModuleName BOSH.SSH -CommandName Add-WindowsCapability -Times 1 -ParameterFilter {
91-
$Name -like "OpenSSH.Server*"
105+
106+
Should -Invoke -ModuleName BOSH.SSH -CommandName Register-ScheduledTask -Times 1 -ParameterFilter {
107+
$TaskName -like "Install-$openSshServerPackageSpecifier"
92108
}
93109
}
94110
}
95111

96112
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-
104113
It "does not attempt to install the packages" {
105114
Install-SSHD
106115

107-
Should -Not -Invoke -ModuleName BOSH.SSH -CommandName Add-WindowsCapability
116+
Should -Not -Invoke -ModuleName BOSH.SSH -CommandName Register-ScheduledTask
108117
}
109118
}
110119
}

modules/BOSH.SSH/BOSH.SSH.psm1

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,43 @@
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+
$taskPrincipal = New-ScheduledTaskPrincipal -GroupId "BUILTIN\Administrators" -RunLevel Highest
23+
$taskCommand = "-Command `"Add-WindowsCapability -Online -Name $packageSpecifier`""
24+
$taskName = "Install-$packageSpecifier"
25+
26+
try {
27+
Register-ScheduledTask `
28+
-TaskName $taskName `
29+
-Trigger $runIn15Seconds `
30+
-Principal $taskPrincipal `
31+
-Action (New-ScheduledTaskAction -Execute "powershell.exe" -Argument $taskCommand) `
32+
-Force
33+
} catch {
34+
Write-Host "Error: $($_ | Format-List * -Force | Out-String)"
35+
}
36+
37+
Start-Sleep -Seconds 180 # wait for install to trigger and complete
38+
39+
Write-Host "Task: $(Get-ScheduledTaskInfo -TaskName $taskName | Format-List *)"
40+
Write-Host "Package Status: $(Get-WindowsCapability -Online -Name "$sshPackage*" | Format-List *)"
1341
}
1442
}
1543
}
@@ -20,6 +48,10 @@
2048
Set-Service -Name ssh-agent -StartupType Disabled
2149
}
2250

51+
function shouldInstallSshComponents {
52+
Get-OSVersion == "windows2019"
53+
}
54+
2355
function Enable-SSHD
2456
{
2557
# Remove existing OpenSSH firewall rule and recreate with '-Profile Any' option

0 commit comments

Comments
 (0)