diff --git a/Invoke-OpenSSHConfiguration.ps1 b/Invoke-OpenSSHConfiguration.ps1 index 47c0f0b..eb014a9 100644 --- a/Invoke-OpenSSHConfiguration.ps1 +++ b/Invoke-OpenSSHConfiguration.ps1 @@ -91,10 +91,8 @@ [String]$SFTPSubsystemPath, [Parameter(Mandatory=$False)] - [Switch]$EnableService, - - [Parameter(Mandatory=$False)] - [Switch]$StartService, + [ValidateNotNullOrEmpty()] + [Int]$SSHPort = 22, [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] @@ -764,40 +762,79 @@ Switch (Test-ProcessElevationStatus) } #endregion - #region Service Management - Switch ($EnableService.IsPresent -eq $True) + #region Service Management (Automatic) + $SSHDService = Get-Service -Name 'sshd' -ErrorAction SilentlyContinue + + Switch ($Null -ine $SSHDService) { {($_ -eq $True)} { - $WriteLogMessage.Invoke(0, @("Configuring sshd service to start automatically. Please Wait...")) - $Null = Set-Service -Name 'sshd' -StartupType Automatic -ErrorAction SilentlyContinue - $WriteLogMessage.Invoke(0, @("sshd service configured for automatic startup.")) + #region Configure Automatic Startup + Switch ($SSHDService.StartType -ine 'Automatic') + { + {($_ -eq $True)} + { + $WriteLogMessage.Invoke(0, @("Configuring sshd service to start automatically. Please Wait...")) + $Null = Set-Service -Name 'sshd' -StartupType Automatic -ErrorAction SilentlyContinue + $WriteLogMessage.Invoke(0, @("sshd service configured for automatic startup.")) + } + } + #endregion + + #region Start Service + Switch ($SSHDService.Status -ine 'Running') + { + {($_ -eq $True)} + { + $WriteLogMessage.Invoke(0, @("Starting sshd service. Please Wait...")) + $Null = Start-Service -Name 'sshd' -ErrorAction SilentlyContinue + $WriteLogMessage.Invoke(0, @("sshd service started.")) + } + } + #endregion } } + #endregion - Switch ($StartService.IsPresent -eq $True) + #region Windows Firewall Configuration (Automatic) + $FirewallRuleName = 'OpenSSH-Server-In-TCP' + $FirewallProfiles = [System.Enum]::GetValues([Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetSecurity.Profile]) + + ForEach ($FirewallProfile In $FirewallProfiles) { - {($_ -eq $True)} + $ExistingRule = Get-NetFirewallRule -Name "$($FirewallRuleName)-$($FirewallProfile)" -ErrorAction SilentlyContinue + + Switch ($Null -eq $ExistingRule) { - $SSHDService = Get-Service -Name 'sshd' -ErrorAction SilentlyContinue - - Switch ($Null -ine $SSHDService) + {($_ -eq $True)} { - {($_ -eq $True)} - { - Switch ($SSHDService.Status -ine 'Running') - { - {($_ -eq $True)} - { - $WriteLogMessage.Invoke(0, @("Starting sshd service. Please Wait...")) - $Null = Start-Service -Name 'sshd' -ErrorAction SilentlyContinue - $WriteLogMessage.Invoke(0, @("sshd service started.")) - } + $WriteLogMessage.Invoke(0, @("Creating Windows Firewall rule for profile `"$($FirewallProfile)`". Please Wait...")) - Default - { - $WriteLogMessage.Invoke(0, @("sshd service is already running.")) - } + $FirewallRuleParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' + $FirewallRuleParameters.Add('Name', "$($FirewallRuleName)-$($FirewallProfile)") + $FirewallRuleParameters.Add('DisplayName', "OpenSSH SSH Server ($($FirewallProfile))") + $FirewallRuleParameters.Add('Description', "Inbound rule for OpenSSH SSH Server on TCP port $($SSHPort) for $($FirewallProfile) profile") + $FirewallRuleParameters.Add('Enabled', 'True') + $FirewallRuleParameters.Add('Direction', 'Inbound') + $FirewallRuleParameters.Add('Protocol', 'TCP') + $FirewallRuleParameters.Add('LocalPort', $SSHPort) + $FirewallRuleParameters.Add('Profile', $FirewallProfile) + $FirewallRuleParameters.Add('Action', 'Allow') + $FirewallRuleParameters.Add('ErrorAction', 'SilentlyContinue') + + $Null = New-NetFirewallRule @FirewallRuleParameters + $WriteLogMessage.Invoke(0, @("Windows Firewall rule created for profile `"$($FirewallProfile)`".")) + } + + Default + { + Switch (($ExistingRule.Enabled -eq $False) -or ($ExistingRule.LocalPort -ne $SSHPort)) + { + {($_ -eq $True)} + { + $WriteLogMessage.Invoke(0, @("Updating Windows Firewall rule for profile `"$($FirewallProfile)`". Please Wait...")) + $Null = Set-NetFirewallRule -Name "$($FirewallRuleName)-$($FirewallProfile)" -Enabled 'True' -LocalPort $SSHPort -ErrorAction SilentlyContinue + $WriteLogMessage.Invoke(0, @("Windows Firewall rule updated for profile `"$($FirewallProfile)`".")) } } } diff --git a/README.md b/README.md index 568b866..1f47f6c 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,7 @@ cd Invoke-OpenSSHConfiguration | `-CAInclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (include matches) | | `-CAExclusionExpression` | String | Regex to filter CAs by Subject or Thumbprint (exclude matches) | | `-SFTPSubsystemPath` | String | Custom SFTP server path (default: `sftp-server.exe`, configured automatically) | -| `-EnableService` | Switch | Set sshd service to automatic startup | -| `-StartService` | Switch | Start sshd service if not running | +| `-SSHPort` | Int | SSH port number (default: `22`, used for firewall rules) | | `-LogDirectory` | DirectoryInfo | Custom log directory path | | `-ContinueOnError` | Switch | Continue execution on non-fatal errors | @@ -105,8 +104,6 @@ This exports all unexpired Root and Intermediate CA certificates from the Window -EnableCertificateAuthentication ` -EnablePubkeyAuthentication ` -DisablePasswordAuthentication ` - -EnableService ` - -StartService ` -LogDirectory 'C:\Logs\OpenSSH' ``` @@ -115,9 +112,7 @@ This exports all unexpired Root and Intermediate CA certificates from the Window ```powershell .\Invoke-OpenSSHConfiguration.ps1 -Mode Server ` -EnablePubkeyAuthentication ` - -DisablePasswordAuthentication ` - -EnableService ` - -StartService + -DisablePasswordAuthentication ``` ### Selective CA Trust (Regex Filtering) @@ -203,14 +198,12 @@ The toolkit includes reusable functions in `Toolkit\Functions\`: ### Current Gaps (Not Yet Implemented) **Server Configuration** -- Port configuration (change from default 22) - User/group restrictions (AllowUsers, AllowGroups) - SSH banner/MOTD configuration - ListenAddress binding to specific interfaces **Security** - No automatic ACL/permission setting on generated keys -- No Windows Firewall rule creation **Management** - No uninstall/rollback capability @@ -218,7 +211,9 @@ The toolkit includes reusable functions in `Toolkit\Functions\`: ### Features Implemented - ✅ Password authentication control (`-DisablePasswordAuthentication`) -- ✅ Service auto-start (`-EnableService`, `-StartService`) +- ✅ Service auto-start and start (automatic, no switches needed) +- ✅ Windows Firewall rules (automatic per-profile: Domain, Private, Public) +- ✅ Port configuration (`-SSHPort`, default 22) - ✅ Config backup before modification (automatic timestamped backups) - ✅ Config validation (`sshd -t`) before restart with automatic rollback - ✅ CA selection via regex (`-CAInclusionExpression`, `-CAExclusionExpression`)