# Get-SSHArtifacts.ps1 # Collects SSH session artifacts, known hosts, and configuration param( [switch]$ShowKeys ) Write-Host "=== SSH Artifacts ===" -ForegroundColor Cyan # Check common SSH directory locations $sshPaths = @( "$env:USERPROFILE\.ssh", "$env:PROGRAMDATA\ssh" ) $foundArtifacts = $false foreach ($sshPath in $sshPaths) { if (Test-Path $sshPath) { $foundArtifacts = $true Write-Host "`n--- SSH Directory: $sshPath ---" -ForegroundColor Yellow # Known hosts $knownHostsPath = Join-Path $sshPath "known_hosts" if (Test-Path $knownHostsPath) { Write-Host "`nKnown Hosts:" -ForegroundColor Green try { $knownHosts = Get-Content $knownHostsPath -ErrorAction SilentlyContinue $hostCounts = @{} foreach ($line in $knownHosts) { if ($line -and -not $line.StartsWith("#")) { # Extract hostname/IP (first field before space or comma) $parts = $line -split '\s+', 2 if ($parts[0]) { # Handle hashed hosts and comma-separated hosts $hostname = $parts[0] -split ',' | Select-Object -First 1 if ($hostCounts.ContainsKey($hostname)) { $hostCounts[$hostname]++ } else { $hostCounts[$hostname] = 1 } } } } if ($hostCounts.Count -gt 0) { $count = 0 foreach ($hostname in ($hostCounts.Keys | Sort-Object)) { $count++ $appearances = $hostCounts[$hostname] $plural = if ($appearances -eq 1) { "entry" } else { "entries" } Write-Host " $count. $hostname ($appearances $plural)" -ForegroundColor Cyan } } else { Write-Host " No hosts found" -ForegroundColor Gray } } catch { Write-Host " Error reading known_hosts: $_" -ForegroundColor Red } } # SSH Config $configPath = Join-Path $sshPath "config" if (Test-Path $configPath) { Write-Host "`nSSH Config:" -ForegroundColor Green try { $config = Get-Content $configPath -ErrorAction SilentlyContinue $currentHost = $null foreach ($line in $config) { $trimmed = $line.Trim() if ($trimmed -match '^Host\s+(.+)') { $currentHost = $matches[1] Write-Host " Host: $currentHost" -ForegroundColor Yellow } elseif ($currentHost -and $trimmed -match '^HostName\s+(.+)') { Write-Host " Hostname: $($matches[1])" -ForegroundColor Cyan } elseif ($currentHost -and $trimmed -match '^User\s+(.+)') { Write-Host " User: $($matches[1])" -ForegroundColor Cyan } elseif ($currentHost -and $trimmed -match '^Port\s+(.+)') { Write-Host " Port: $($matches[1])" -ForegroundColor Cyan } elseif ($currentHost -and $trimmed -match '^IdentityFile\s+(.+)') { Write-Host " IdentityFile: $($matches[1])" -ForegroundColor Cyan } } } catch { Write-Host " Error reading config: $_" -ForegroundColor Red } } # SSH Keys Write-Host "`nSSH Keys:" -ForegroundColor Green $keyFiles = Get-ChildItem -Path $sshPath -Filter "id_*" -ErrorAction SilentlyContinue if ($keyFiles) { foreach ($keyFile in $keyFiles) { $isPrivate = $keyFile.Name -notmatch '\.pub$' $keyType = if ($isPrivate) { "Private" } else { "Public" } Write-Host " [$keyType] $($keyFile.Name)" -ForegroundColor $(if ($isPrivate) { "Red" } else { "Green" }) Write-Host " Path: $($keyFile.FullName)" -ForegroundColor Gray Write-Host " Modified: $($keyFile.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray # Show public key content if requested if ($ShowKeys -and -not $isPrivate) { try { $content = Get-Content $keyFile.FullName -ErrorAction SilentlyContinue if ($content) { Write-Host " Content: $content" -ForegroundColor Cyan } } catch { Write-Host " Error reading key: $_" -ForegroundColor Red } } } } else { Write-Host " No SSH keys found" -ForegroundColor Gray } # Authorized keys $authorizedKeysPath = Join-Path $sshPath "authorized_keys" if (Test-Path $authorizedKeysPath) { Write-Host "`nAuthorized Keys:" -ForegroundColor Green try { $authKeys = Get-Content $authorizedKeysPath -ErrorAction SilentlyContinue $count = 0 foreach ($line in $authKeys) { if ($line -and -not $line.StartsWith("#")) { $count++ # Extract key type and comment if ($line -match '^(ssh-\S+)\s+\S+\s*(.*)$') { $keyType = $matches[1] $comment = $matches[2] Write-Host " $count. $keyType $(if ($comment) { "($comment)" })" -ForegroundColor Cyan } } } if ($count -eq 0) { Write-Host " No authorized keys found" -ForegroundColor Gray } } catch { Write-Host " Error reading authorized_keys: $_" -ForegroundColor Red } } # List all other files in .ssh directory Write-Host "`nOther Files:" -ForegroundColor Green $otherFiles = Get-ChildItem -Path $sshPath -File -ErrorAction SilentlyContinue | Where-Object { $_.Name -notin @('known_hosts', 'config', 'authorized_keys') -and $_.Name -notmatch '^id_' } if ($otherFiles) { foreach ($file in $otherFiles) { Write-Host " $($file.Name) - Modified: $($file.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan } } else { Write-Host " No other files" -ForegroundColor Gray } } } # Check for PuTTY sessions (Windows alternative to OpenSSH) Write-Host "`n--- PuTTY Sessions ---" -ForegroundColor Yellow try { $puttyPath = "HKCU:\Software\SimonTatham\PuTTY\Sessions" if (Test-Path $puttyPath) { $sessions = Get-ChildItem -Path $puttyPath -ErrorAction SilentlyContinue if ($sessions) { foreach ($session in $sessions) { $sessionName = [System.Web.HttpUtility]::UrlDecode($session.PSChildName) $props = Get-ItemProperty -Path $session.PSPath -ErrorAction SilentlyContinue Write-Host "`nSession: $sessionName" -ForegroundColor Green if ($props.HostName) { Write-Host " Hostname: $($props.HostName)" -ForegroundColor Cyan } if ($props.UserName) { Write-Host " Username: $($props.UserName)" -ForegroundColor Cyan } if ($props.PortNumber) { Write-Host " Port: $($props.PortNumber)" -ForegroundColor Cyan } if ($props.Protocol) { Write-Host " Protocol: $($props.Protocol)" -ForegroundColor Cyan } } } else { Write-Host "No PuTTY sessions found" -ForegroundColor Gray } } else { Write-Host "PuTTY not installed or no sessions configured" -ForegroundColor Gray } } catch { Write-Host "Error reading PuTTY registry: $_" -ForegroundColor Red } # Check for Windows OpenSSH Server logs Write-Host "`n--- OpenSSH Server Logs ---" -ForegroundColor Yellow $sshServerLog = "$env:ProgramData\ssh\logs\sshd.log" if (Test-Path $sshServerLog) { Write-Host "Server log found: $sshServerLog" -ForegroundColor Green try { $recentLogs = Get-Content $sshServerLog -Tail 20 -ErrorAction SilentlyContinue Write-Host "`nRecent log entries (last 20 lines):" -ForegroundColor Cyan $recentLogs | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } } catch { Write-Host "Error reading log: $_" -ForegroundColor Red } } else { Write-Host "No OpenSSH server logs found" -ForegroundColor Gray } if (-not $foundArtifacts) { Write-Host "`nNo SSH artifacts found" -ForegroundColor Gray Write-Host "SSH might not be configured on this system" -ForegroundColor Gray } Write-Host "`nNote: Use -ShowKeys to display public key contents" -ForegroundColor Cyan Write-Host "Private keys are never displayed for security reasons" -ForegroundColor Cyan