ps/Modules/Cole.PowerShell.Developer/Public/Get-SSHConfigEntries.ps1

120 lines
4.5 KiB
PowerShell
Raw Normal View History

2023-05-30 22:51:22 -07:00
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
}