Public/Install-GceWindowsSsh.ps1
|
function Install-GceWindowsSsh { #Requires -Version 5.0 #Requires -RunAsAdministrator <# .SYNOPSIS Installs and configures SSH server on Windows VM in Google Cloud with PowerShell as the default shell. .DESCRIPTION This function: 1. Installs Google Compute Engine Windows components (if not already installed) 2. Installs Google Compute Engine SSH server (if not already installed) 3. Configures SSH to use PowerShell as the default shell 4. Configures SSH authentication settings 5. Restarts the SSH service Requires Administrator privileges and PowerShell 7+ (pwsh.exe) to be installed. .PARAMETER PowerShellPath Optional path to PowerShell 7+ executable. Defaults to "C:\Program Files\PowerShell\7\pwsh.exe". If not found at the specified path, the function will search for pwsh.exe in PATH. .PARAMETER SkipInstallCheck Skip checking and installing Google Compute Engine packages. Use this if packages are already installed. .EXAMPLE Install-GceWindowsSsh Installs and configures SSH server with default settings. .EXAMPLE Install-GceWindowsSsh -PowerShellPath "C:\Program Files\PowerShell\8\pwsh.exe" Installs and configures SSH server using a specific PowerShell path. .EXAMPLE Install-GceWindowsSsh -SkipInstallCheck Configures SSH server without checking for or installing GCE packages. .NOTES Requires Administrator privileges Requires PowerShell 7+ (pwsh.exe) to be installed Requires googet package manager (typically available on GCE Windows images) #> [CmdletBinding()] param( [Parameter(Mandatory=$false)] [string]$PowerShellPath = "C:\Program Files\PowerShell\7\pwsh.exe", [Parameter(Mandatory=$false)] [switch]$SkipInstallCheck ) $ErrorActionPreference = 'Stop' Write-Host "=== Installing and Configuring SSH Server on Windows VM ===" -ForegroundColor Cyan Write-Host "" # Function to check if a package is installed function Test-GoogetPackageInstalled { param([string]$PackageName) try { $installed = googet installed 2>&1 | Select-String -Pattern $PackageName return ($null -ne $installed) } catch { return $false } } # Function to check if PowerShell 7+ is installed function Test-PowerShellInstalled { param([string]$Path) if (Test-Path $Path) { return $true } # Try to find pwsh.exe in PATH try { $pwsh = Get-Command pwsh.exe -ErrorAction SilentlyContinue if ($pwsh) { $script:PowerShellPath = $pwsh.Source return $true } } catch { return $false } return $false } # Step 1: Check and install Google Compute Engine Windows components Write-Host "[1/6] Checking Google Compute Engine Windows components..." -ForegroundColor Yellow if (-not $SkipInstallCheck) { if (-not (Test-GoogetPackageInstalled -PackageName "google-compute-engine-windows")) { Write-Host " Installing google-compute-engine-windows..." -ForegroundColor Gray googet -noconfirm=true install google-compute-engine-windows if ($LASTEXITCODE -ne 0) { throw "Failed to install google-compute-engine-windows" } Write-Host " ✓ Installed google-compute-engine-windows" -ForegroundColor Green } else { Write-Host " ✓ google-compute-engine-windows is already installed" -ForegroundColor Green } } else { Write-Host " Skipping install check (SkipInstallCheck specified)" -ForegroundColor Gray } # Step 2: Check and install Google Compute Engine SSH Write-Host "[2/6] Checking Google Compute Engine SSH..." -ForegroundColor Yellow if (-not $SkipInstallCheck) { if (-not (Test-GoogetPackageInstalled -PackageName "google-compute-engine-ssh")) { Write-Host " Installing google-compute-engine-ssh..." -ForegroundColor Gray googet -noconfirm=true install google-compute-engine-ssh if ($LASTEXITCODE -ne 0) { throw "Failed to install google-compute-engine-ssh" } Write-Host " ✓ Installed google-compute-engine-ssh" -ForegroundColor Green } else { Write-Host " ✓ google-compute-engine-ssh is already installed" -ForegroundColor Green } } else { Write-Host " Skipping install check (SkipInstallCheck specified)" -ForegroundColor Gray } # Step 3: Verify PowerShell 7+ is installed Write-Host "[3/6] Verifying PowerShell 7+ installation..." -ForegroundColor Yellow if (-not (Test-PowerShellInstalled -Path $PowerShellPath)) { throw "PowerShell 7+ (pwsh.exe) not found at $PowerShellPath or in PATH. Please install PowerShell 7+ first." } $PowerShellPath = (Get-Command pwsh.exe -ErrorAction Stop).Source Write-Host " ✓ Found PowerShell at: $PowerShellPath" -ForegroundColor Green # Step 4: Configure SSH DefaultShell registry entry Write-Host "[4/6] Configuring SSH DefaultShell registry entry..." -ForegroundColor Yellow $regPath = "HKLM:\SOFTWARE\OpenSSH" if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null Write-Host " Created registry path: $regPath" -ForegroundColor Gray } try { $currentValue = Get-ItemProperty -Path $regPath -Name DefaultShell -ErrorAction SilentlyContinue if ($currentValue -and $currentValue.DefaultShell -eq $PowerShellPath) { Write-Host " ✓ DefaultShell already set correctly" -ForegroundColor Green } else { New-ItemProperty -Path $regPath -Name DefaultShell -Value $PowerShellPath -PropertyType String -Force | Out-Null Write-Host " ✓ Set DefaultShell to: $PowerShellPath" -ForegroundColor Green } } catch { throw "Failed to set DefaultShell registry value: $_" } # Step 5: Configure sshd_config file Write-Host "[5/6] Configuring sshd_config..." -ForegroundColor Yellow $sshdConfigPath = "C:\ProgramData\ssh\sshd_config" if (-not (Test-Path $sshdConfigPath)) { throw "sshd_config file not found at $sshdConfigPath. SSH may not be properly installed." } # Backup the original config $backupPath = "$sshdConfigPath.backup.$(Get-Date -Format 'yyyyMMddHHmmss')" Copy-Item $sshdConfigPath $backupPath -Force Write-Host " Created backup: $backupPath" -ForegroundColor Gray # Prepare the settings we need to add/update $settingsToAdd = @{ 'PasswordAuthentication' = 'yes' 'PubkeyAuthentication' = 'yes' } # Process each setting $lines = Get-Content $sshdConfigPath $newLines = @() $settingsFound = @{} foreach ($line in $lines) { $trimmedLine = $line.Trim() # Check if this line is a setting we care about $matched = $false foreach ($key in $settingsToAdd.Keys) { if ($trimmedLine -match "^$key\s+") { $matched = $true $settingsFound[$key] = $true # Replace with our value $newLines += "$key $($settingsToAdd[$key])" Write-Host " Updated: $key = $($settingsToAdd[$key])" -ForegroundColor Gray break } } if (-not $matched) { $newLines += $line } } # Add any settings that weren't found foreach ($key in $settingsToAdd.Keys) { if (-not $settingsFound[$key]) { $newLines += "$key $($settingsToAdd[$key])" Write-Host " Added: $key = $($settingsToAdd[$key])" -ForegroundColor Gray } } # Write the updated config $newLines | Set-Content $sshdConfigPath -Encoding UTF8 Write-Host " ✓ Updated sshd_config" -ForegroundColor Green # Step 6: Restart SSH service Write-Host "" Write-Host "[6/6] Restarting SSH service..." -ForegroundColor Yellow try { $sshdService = Get-Service sshd -ErrorAction Stop if ($sshdService.Status -eq 'Running') { Restart-Service sshd -Force Write-Host " ✓ SSH service restarted successfully" -ForegroundColor Green } else { Start-Service sshd Write-Host " ✓ SSH service started successfully" -ForegroundColor Green } # Verify service is running Start-Sleep -Seconds 2 $sshdService = Get-Service sshd if ($sshdService.Status -eq 'Running') { Write-Host " ✓ SSH service is running" -ForegroundColor Green } else { Write-Warning " SSH service is not running. Status: $($sshdService.Status)" } } catch { Write-Error "Failed to restart SSH service: $_" Write-Host " You may need to manually restart the service or check the configuration." -ForegroundColor Yellow throw } Write-Host "" Write-Host "=== Configuration Complete ===" -ForegroundColor Green Write-Host "" Write-Host "Summary:" -ForegroundColor Cyan Write-Host " - SSH server configured with PowerShell as default shell" -ForegroundColor White Write-Host " - PasswordAuthentication: Enabled" -ForegroundColor White Write-Host " - PubkeyAuthentication: Enabled" -ForegroundColor White Write-Host "" Write-Host "You can now connect via SSH using:" -ForegroundColor Cyan Write-Host " ssh username@vm-ip-address" -ForegroundColor White Write-Host "" } |