function Get-SSHConfigEntries { <# .SYNOPSIS This function is used to get the specified user's SSH config entries as a hashtable for ease of parsing .PARAMETER Username [string] The user to get the ssh config for .PARAMETER Path [string] The path to the config file to read in #> [CmdletBinding(DefaultParameterSetName = 'Username')] [OutputType([object[]])] param ( [Parameter(ParameterSetName = 'Username')] [string]$Username = (Get-CurrentUsername), [Parameter(ParameterSetName = 'Path', Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Path ) $logLead = (Get-LogLeadName) if ($PSCmdlet.ParameterSetName -eq 'Username') { $magicPathRoot = '~\.ssh' $magicPath = (Join-Path -Path $magicPathRoot -ChildPath 'config') if (!(Test-Path -Path $magicPathRoot) -or !(Test-Path -Path $magicPath)) { Write-Warning "$logLead : No SSH config file found for current user" return $null } else { $Path = $magicPath } } if (!(Test-Path -Path $Path)) { Write-Warning "$logLead : No SSH config file found at [$Path]" return $null } $lines = (Get-Content -Path $Path) <# Format of SSH client config file ssh_config The ssh_config client configuration file has the following format. Both the global /etc/ssh/ssh_config and per-user ~/ssh/config have the same format. Empty lines and lines starting with '#' are comments. Each line begins with a keyword, followed by argument(s). Configuration options may be separated by whitespace or optional whitespace and exactly one =. Arguments may be enclosed in double quotes (") in order to specify arguments that contain spaces. #> $currentObject = @{ Comments = @(); } $return = @() foreach ($line in $lines) { $rawLine = $line $line = $line.Trim() if ([string]::IsNullOrWhiteSpace($line)) { if (($currentObject.Comments.Count -gt 0) -or ($null -ne $currentObject.Host)) { # We have either an object or a random block of comments. # Assume it's a "previous record" and put it on the $return, then gen up a new object and keep going $return += $currentObject $currentObject = @{ Comments = @(); } } continue } $value = '' $commentStartingIndex = $line.IndexOf('#') $comment = '' if ($commentStartingIndex -gt -1) { $comment = $line.Substring($commentStartingIndex + 1).Trim() $line = $line.Substring(0, $commentStartingIndex).Trim() } if ([string]::IsNullOrWhiteSpace($line)) { $currentObject.Comments += $comment continue } $quotedIdentifierStartingIndex = $line.IndexOf('"') $quotedIdentifierEndingIndex = $line.LastIndexOf('"') if (($quotedIdentifierStartingIndex -gt -1) -and ($quotedIdentifierEndingIndex -gt $quotedIdentifierStartingIndex)) { # There is a value on the line that starts and ends with a quote mark, so we should escape that into a variable for now $value = $line.Substring($quotedIdentifierStartingIndex + 1, $quotedIdentifierEndingIndex - $quotedIdentifierStartingIndex - 1) $line = $line.Substring(0, $quotedIdentifierStartingIndex).Trim() } if ([string]::IsNullOrWhiteSpace($value)) { $firstSpaceIndex = $line.Trim().IndexOf(' ') if ($firstSpaceIndex -gt -1) { $value = $line.Trim().Substring($firstSpaceIndex + 1) $line = $line.Trim().Substring(0, $firstSpaceIndex) } } if ([string]::IsNullOrWhiteSpace($line)) { Write-Host "$logLead : Somehow we have ended up with an empty key name for [$rawLine] with a value [$value] and potential comment [$comment]" } else { Write-Verbose "$logLead : We have ended up with a key name for [$line] with a value [$value] and potential comment [$comment]" $currentObject.$line = $value if (![string]::IsNullOrWhiteSpace($comment)) { $currentObject.$line | Add-Member -NotePropertyName 'Comment' -NotePropertyValue $comment } } } if (($currentObject.Comments.Count -gt 0) -or ($null -ne $currentObject.Host)) { # We ended with something that hasn't been appended to the return value yet. $return += $currentObject } return $return }