Dargslan.WinSSHMgr.psm1

<#
.SYNOPSIS
    Windows OpenSSH server and client management toolkit — SSH config audit, key management, session monitoring, and security hardening (2026 Edition)

.DESCRIPTION
    2026 Edition — Part of the Dargslan Windows Admin Toolkit collection.
    More tools and resources at https://dargslan.com
    Free Cheat Sheets: https://dargslan.com/cheat-sheets

.LINK
    https://dargslan.com

.LINK
    https://github.com/Dargslan/powershell-admin-scripts
#>


function Get-SSHReport {
    <#
    .SYNOPSIS
        Audit Windows OpenSSH server and client configuration
    .DESCRIPTION
        Reports SSH service status, sshd_config analysis, authorized keys, host keys, and security assessment.
        Part of Dargslan.WinSSHMgr (2026 Edition) — https://dargslan.com
    #>

    [CmdletBinding()] param([switch]$Json)

    $report = [ordered]@{
        SSHService = Get-Service sshd -ErrorAction SilentlyContinue | Select-Object Status, StartType, DisplayName
        SSHAgent = Get-Service ssh-agent -ErrorAction SilentlyContinue | Select-Object Status, StartType
        Installed = (Get-WindowsCapability -Online -Name OpenSSH* -ErrorAction SilentlyContinue | Where-Object State -eq "Installed") | Select-Object Name, State
        Config = @{}
        HostKeys = @()
        AuthorizedKeys = @()
        SecurityScore = 0
    }
    $sshdConfig = "$env:ProgramData\ssh\sshd_config"
    if (Test-Path $sshdConfig) {
        $cfg = Get-Content $sshdConfig | Where-Object { $_ -notmatch "^\s*#" -and $_ -match "\S" }
        $report.Config = [PSCustomObject]@{
            PermitRootLogin = ($cfg | Where-Object { $_ -match "PermitRootLogin\s+(\S+)" }) -replace "PermitRootLogin\s+", ""
            PasswordAuth = ($cfg | Where-Object { $_ -match "PasswordAuthentication\s+(\S+)" }) -replace "PasswordAuthentication\s+", ""
            PubkeyAuth = ($cfg | Where-Object { $_ -match "PubkeyAuthentication\s+(\S+)" }) -replace "PubkeyAuthentication\s+", ""
            MaxAuthTries = ($cfg | Where-Object { $_ -match "MaxAuthTries\s+(\d+)" }) -replace "MaxAuthTries\s+", ""
            Port = ($cfg | Where-Object { $_ -match "^Port\s+(\d+)" }) -replace "Port\s+", ""
            AllowUsers = ($cfg | Where-Object { $_ -match "AllowUsers" }) -replace "AllowUsers\s+", ""
        }
    }
    $hostKeyDir = "$env:ProgramData\ssh"
    if (Test-Path $hostKeyDir) {
        $report.HostKeys = Get-ChildItem "$hostKeyDir\ssh_host_*_key.pub" -ErrorAction SilentlyContinue | ForEach-Object {
            $content = Get-Content $_.FullName
            [PSCustomObject]@{ File = $_.Name; Type = ($content -split " ")[0]; Size = $_.Length }
        }
    }
    $score = 50
    if ($report.SSHService.Status -eq "Running") { $score += 10 }
    if ($report.Config.PasswordAuth -eq "no") { $score += 20 }
    if ($report.Config.PubkeyAuth -eq "yes") { $score += 10 }
    if ($report.Config.MaxAuthTries -and [int]$report.Config.MaxAuthTries -le 3) { $score += 10 }
    $report.SecurityScore = [PSCustomObject]@{ Score = $score; Grade = $(if ($score -ge 80) {"A"} elseif ($score -ge 60) {"B"} elseif ($score -ge 40) {"C"} else {"D"}) }
    if ($Json) { return $report | ConvertTo-Json -Depth 3 }
    Write-Host "`n [SSH Report — 2026 Edition]" -ForegroundColor Cyan
    Write-Host " Service: $($report.SSHService.Status) | Agent: $($report.SSHAgent.Status)"
    if ($report.Config) { $report.Config | Format-List }
    Write-Host " Security Score: $score/100 ($($report.SecurityScore.Grade))" -ForegroundColor $(if ($score -ge 80) {"Green"} elseif ($score -ge 60) {"Yellow"} else {"Red"})
    return $report
}

Export-ModuleMember -Function *