Private/SSHScriptBuilder.ps1

function SSHScriptBuilder {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$True)]
        [string]$RemoteHostNameOrIP,

        [Parameter(
            Mandatory=$True,
            ParameterSetName='Local'
        )]
        [ValidatePattern("\\")] # Must be in format <RemoteHostName>\<User>
        [string]$LocalUserName,

        [Parameter(
            Mandatory=$True,
            ParameterSetName='Domain'    
        )]
        [ValidatePattern("\\")] # Must be in format <DomainShortName>\<User>
        [string]$DomainUserName,

        [Parameter(
            Mandatory=$False,
            ParameterSetName='Local'    
        )]
        [string]$LocalPassword,

        [Parameter(
            Mandatory=$False,
            ParameterSetName='Domain'
        )]
        [string]$DomainPassword,

        [Parameter(Mandatory=$False)]
        [string]$KeyFilePath,

        [Parameter(Mandatory=$False)]
        [System.Collections.ArrayList]$SSHScriptArray, # NOTE: $SSHScriptArray will ALWAYS be run BEFORE $ElevatedSSHScriptArray

        [Parameter(Mandatory=$False)]
        [System.Collections.ArrayList]$ElevatedSSHScriptArray, # NOTE: $SSHScriptArray will ALWAYS be run BEFORE $ElevatedSSHScriptArray

        [Parameter(Mandatory=$False)]
        [string]$ScriptCompleteFlag, # This should be a regex string

        [Parameter(Mandatory=$False)]
        [int]$PotentialAdditionalPwdPrompts,

        [Parameter(Mandatory=$False)]
        [int]$PwdPromptTimeoutMin = 10,

        [Parameter(Mandatory=$False)]
        [int]$PwdPromptDelaySeconds,

        [Parameter(Mandatory=$False)]
        [float]$WindowsWaitTimeMin = 2,

        [Parameter(Mandatory=$False)]
        [switch]$WindowsTarget
    )

    if ($LocalUserName) {
        $FullUserName = $($LocalUserName -split "\\")[-1]
    }
    if ($DomainUserName) {
        $DomainNameShort = $($DomainUserName -split "\\")[0]
        $FullUserName = $($DomainUserName -split "\\")[-1]
    }

    $HostNameValue = $RHostIP = @(
        $RemoteHostNetworkInfo.IPAddressList | Where-Object {$_ -notmatch "^169"}
    )[0]

    # This is what we're going for:
    # ssh -t pdadmin@192.168.2.10 "echo 'ConnectionSuccessful'"
    [System.Collections.ArrayList]$SSHCmdStringArray = @(
        'ssh'
        '-t'
    )
    if ($KeyFilePath) {
        $null = $SSHCmdStringArray.Add("-i")
        $null = $SSHCmdStringArray.Add('"' + $KeyFilePath + '"')
    }
    if ($LocalUserName) {
        $null = $SSHCmdStringArray.Add("$FullUserName@$HostNameValue")
    }
    if ($DomainUserName) {
        $null = $SSHCmdStringArray.Add("$FullUserName@$DomainNameShort@$HostNameValue")
    }
    
    if ($SSHScriptArray) {
        [System.Collections.ArrayList][array]$AwaitScriptArray = @($SSHScriptArray) | foreach {
            $FinalLine = $_ -replace [regex]::Escape('\'),'\\'
            $FinalLine = $FinalLine -replace [regex]::Escape('$'),'\`$'
            $FinalLine = $FinalLine -replace [regex]::Escape('"'),'\`"\`"'
            if ($FinalLine -match 'sed.*subsystemline') {
                $FinalLine = $FinalLine -replace [regex]::Escape('\`"\`"'),'\\\`"'
            }
            $FinalLine
        }
        #$AwaitScriptArray.Insert($($AwaitScriptArray.Count-1),"echo $ScriptCompleteFlag")
        #$null = $AwaitScriptArray.Add("echo $ScriptCompleteFlag")
        $FinalAwaitScript = $AwaitScriptArray -join "; "
        
        [System.Collections.ArrayList][array]$ExpectScriptArray = @($SSHScriptArray) | foreach {
            $FinalLine = $_ -replace [regex]::Escape('\'),'\\\'
            $FinalLine = $FinalLine -replace [regex]::Escape('$'),'\\\$'
            $FinalLine = $FinalLine -replace [regex]::Escape('"'),'\\\"'
            #$FinalLine = $FinalLine -replace [regex]::Escape('\n'),'\\\n"'
            $FinalLine = $FinalLine -replace [regex]::Escape('['),'\['
            $FinalLine = $FinalLine -replace [regex]::Escape(']'),'\]'
            $FinalLine
        }
        #$null = $ExpectScriptArray.Add("echo $ScriptCompleteFlag")
        # No need for $FinalExpectScript, because we loop through the $ExpectScriptArray to send each command one at a time
    }

    if ($ElevatedSSHScriptArray) {
        [System.Collections.ArrayList][array]$ElevatedAwaitScriptArray = @($ElevatedSSHScriptArray) | foreach {
            $FinalLine = $_ -replace [regex]::Escape('\'),'\\'
            $FinalLine = $FinalLine -replace [regex]::Escape('$'),'\`$'
            $FinalLine = $FinalLine -replace [regex]::Escape('"'),'\`"\`"'
            if ($FinalLine -match 'sed.*subsystemline') {
                $FinalLine = $FinalLine -replace [regex]::Escape('\`"\`"'),'\\\`"'
            }
            $FinalLine
        }
        #$ElevatedAwaitScriptArray.Insert($($ElevatedAwaitScriptArray.Count-1),"echo $ScriptCompleteFlag")
        #$null = $ElevatedAwaitScriptArray.Add("echo $ScriptCompleteFlag")
        $FinalElevatedAwaitScript = $ElevatedAwaitScriptArray -join "; "
        
        [System.Collections.ArrayList][array]$ElevatedExpectScriptArray = @($ElevatedSSHScriptArray) | foreach {
            $FinalLine = $_ -replace [regex]::Escape('\'),'\\\'
            $FinalLine = $FinalLine -replace [regex]::Escape('$'),'\\\$'
            $FinalLine = $FinalLine -replace [regex]::Escape('"'),'\\\"'
            #$FinalLine = $FinalLine -replace [regex]::Escape('\n'),'\\\n"'
            $FinalLine = $FinalLine -replace [regex]::Escape('['),'\['
            $FinalLine = $FinalLine -replace [regex]::Escape(']'),'\]'
            $FinalLine
        }
        #$null = $ExpectScriptArray.Add("echo $ScriptCompleteFlag")
        # No need for $FinalElevatedExpectScript, because we loop through the $ExpectScriptArray to send each command one at a time
    }

    if (!$PSVersionTable.Platform -or $PSVersionTable.Platform -eq "Win32NT") {
        if (!$WindowsTarget) {
            if ($SSHScriptArray -and !$ElevatedSSHScriptArray) {
                $SSHCmdString = $($SSHCmdStringArray -join " ") + ' ' + '"bash -c \`"' + $FinalAwaitScript + '\`""'
            }
            if (!$SSHScriptArray -and $ElevatedSSHScriptArray) {
                $SSHCmdString = $($SSHCmdStringArray -join " ") + ' ' + '"sudo bash -c \`"' + $FinalElevatedAwaitScript + '\`""'
            }
            if ($SSHScriptArray -and $ElevatedSSHScriptArray) {
                $SSHCmdString = $($SSHCmdStringArray -join " ") + ' ' + '"bash -c \`"' + $FinalAwaitScript + '\`"; ' +
                'sudo bash -c \`"' + $FinalElevatedAwaitScript + '\`""'
            }
        }
        else {
            $SSHCmdString = $($SSHCmdStringArray -join " ") + ' ' +  '"' + $FinalAwaitScript + '"'
        }

        Write-Host "`$SSHCmdString is:`n $SSHCmdString"

        #region >> Await Attempt Number 1 of 2
        
        $PSAwaitProcess = $null
        $null = Start-AwaitSession
        Start-Sleep -Seconds 1
        $null = Send-AwaitCommand '$host.ui.RawUI.WindowTitle = "PSAwaitSession"'
        $PSAwaitProcess = $($(Get-Process | Where-Object {$_.Name -eq "powershell"}) | Sort-Object -Property StartTime -Descending)[0]
        Start-Sleep -Seconds 1
        $null = Send-AwaitCommand "`$env:Path = '$env:Path'"
        Start-Sleep -Seconds 1
        $null = Send-AwaitCommand -Command $([scriptblock]::Create($SSHCmdString))
        Start-Sleep -Seconds 5

        # This will either not prompt at all, prompt to accept the RemoteHost's RSA Host Key, or prompt for a password
        $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

        [System.Collections.ArrayList]$CheckForExpectedResponses = @()
        $null = $CheckForExpectedResponses.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
        $Counter = 0
        while (![bool]$($($CheckForExpectedResponses -split "`n") -match [regex]::Escape("Are you sure you want to continue connecting (yes/no)?")) -and
        ![bool]$($($CheckForExpectedResponses -split "`n") -match "assword.*:") -and 
        ![bool]$($($CheckForExpectedResponses -split "`n") -match $ScriptCompleteFlag) -and $Counter -le 30
        ) {
            $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
            $null = $CheckForExpectedResponses.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
            if ($CheckResponsesOutput -match "must be greater than zero" -or @($CheckResponsesOutput)[-1] -notmatch "[a-zA-Z]") {
                break
            }
            Start-Sleep -Seconds 1
            $Counter++
        }
        if ($Counter -eq 31) {
            Write-Verbose "SSH via '$($SSHCmdStringArray -join " ")' timed out!"

            if ($PSAwaitProcess.Id) {
                try {
                    $null = Stop-AwaitSession
                }
                catch {
                    if ($PSAwaitProcess.Id -eq $PID) {
                        Write-Error "The PSAwaitSession never spawned! Halting!"
                        $global:FunctionResult = "1"
                        return
                    }
                    else {
                        if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                            Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                        }
                        $Counter = 0
                        while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                            Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                            Start-Sleep -Seconds 1
                            $Counter++
                        }
                    }
                }
                $PSAwaitProcess = $null
            }
        }

        #endregion >> Await Attempt 1 of 2

        $CheckResponsesOutput = $CheckForExpectedResponses | foreach {$_ -split "`n"}
            
        #region >> Await Attempt 2 of 2
        
        # If $CheckResponsesOutput contains the string "must be greater than zero", then something broke with the Await Module.
        # Most of the time, just trying again resolves any issues
        if ($CheckResponsesOutput -match "must be greater than zero" -or @($CheckResponsesOutput)[-1] -notmatch "[a-zA-Z]" -or
        $CheckResponsesOutput -match "background process reported an error") {
            if ($PSAwaitProcess.Id) {
                try {
                    $null = Stop-AwaitSession
                }
                catch {
                    if ($PSAwaitProcess.Id -eq $PID) {
                        Write-Error "The PSAwaitSession never spawned! Halting!"
                        $global:FunctionResult = "1"
                        return
                    }
                    else {
                        if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                            Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                        }
                        $Counter = 0
                        while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                            Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                            Start-Sleep -Seconds 1
                            $Counter++
                        }
                    }
                }
            }

            $PSAwaitProcess = $null
            $null = Start-AwaitSession
            Start-Sleep -Seconds 1
            $null = Send-AwaitCommand '$host.ui.RawUI.WindowTitle = "PSAwaitSession"'
            $PSAwaitProcess = $($(Get-Process | Where-Object {$_.Name -eq "powershell"}) | Sort-Object -Property StartTime -Descending)[0]
            Start-Sleep -Seconds 1
            $null = Send-AwaitCommand "`$env:Path = '$env:Path'"
            Start-Sleep -Seconds 1
            $null = Send-AwaitCommand -Command $([scriptblock]::Create($SSHCmdString))
            Start-Sleep -Seconds 5

            # This will either not prompt at all, prompt to accept the RemoteHost's RSA Host Key, or prompt for a password
            $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

            [System.Collections.ArrayList]$CheckForExpectedResponses = @()
            $null = $CheckForExpectedResponses.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
            $Counter = 0
            while (![bool]$($SuccessOrAcceptHostKeyOrPwdPrompt -match [regex]::Escape("Are you sure you want to continue connecting (yes/no)?")) -and
            ![bool]$($SuccessOrAcceptHostKeyOrPwdPrompt -match "assword.*:") -and 
            ![bool]$($SuccessOrAcceptHostKeyOrPwdPrompt -match $ScriptCompleteFlag) -and $Counter -le 30
            ) {
                $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                $null = $CheckForExpectedResponses.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                Start-Sleep -Seconds 1
                $Counter++
            }
            if ($Counter -eq 31) {
                Write-Error "SSH via '$($SSHCmdStringArray -join " ")' timed out!"
                $global:FunctionResult = "1"

                #$CheckForExpectedResponses

                if ($PSAwaitProcess.Id) {
                    try {
                        $null = Stop-AwaitSession
                    }
                    catch {
                        if ($PSAwaitProcess.Id -eq $PID) {
                            Write-Error "The PSAwaitSession never spawned! Halting!"
                            $global:FunctionResult = "1"
                            return
                        }
                        else {
                            if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                            }
                            $Counter = 0
                            while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                Start-Sleep -Seconds 1
                                $Counter++
                            }
                        }
                    }
                }

                return
            }
        }

        #endregion >> Await Attempt 2 of 2

        $CheckResponsesOutput = $CheckForExpectedResponses | foreach {$_ -split "`n"}

        # At this point, if we don't have the expected output, we need to fail
        if ($CheckResponsesOutput -match "must be greater than zero" -or @($CheckResponsesOutput)[-1] -notmatch "[a-zA-Z]" -or
        $CheckResponsesOutput -match "background process reported an error") {
            if ($CheckResponsesOutput -match "must be greater than zero" -or @($CheckResponsesOutput)[-1] -notmatch "[a-zA-Z]") {
                Write-Error "Something went wrong with the PowerShell Await Module! Halting!"
            }
            if ($CheckResponsesOutput -match "background process reported an error") {
                Write-Error "Please check your credentials! Halting!"
            }
            $global:FunctionResult = "1"

            if ($PSAwaitProcess.Id) {
                try {
                    $null = Stop-AwaitSession
                }
                catch {
                    if ($PSAwaitProcess.Id -eq $PID) {
                        Write-Error "The PSAwaitSession never spawned! Halting!"
                        $global:FunctionResult = "1"
                        return
                    }
                    else {
                        if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                            Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                        }
                        $Counter = 0
                        while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                            Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                            Start-Sleep -Seconds 1
                            $Counter++
                        }
                    }
                }
            }

            return
        }

        # Now we should either have a prompt to accept the host key, a prompt for a password, or it already worked...

        if ($CheckResponsesOutput -match [regex]::Escape("Are you sure you want to continue connecting (yes/no)?")) {
            $null = Send-AwaitCommand "yes"
            Start-Sleep -Seconds 3
            
            # This will either not prompt at all or prompt for a password
            $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

            [System.Collections.ArrayList]$CheckExpectedSendYesOutput = @()
            $null = $CheckExpectedSendYesOutput.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
            $Counter = 0
            while (![bool]$($($CheckExpectedSendYesOutput -split "`n") -match "assword.*:") -and 
            ![bool]$($($CheckExpectedSendYesOutput -split "`n") -match $ScriptCompleteFlag) -and $Counter -le 30
            ) {
                $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                $null = $CheckExpectedSendYesOutput.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                Start-Sleep -Seconds 1
                $Counter++
            }
            if ($Counter -eq 31) {
                Write-Error "Sending 'yes' to accept the ssh host key timed out!"
                $global:FunctionResult = "1"
                
                if ($PSAwaitProcess.Id) {
                    try {
                        $null = Stop-AwaitSession
                    }
                    catch {
                        if ($PSAwaitProcess.Id -eq $PID) {
                            Write-Error "The PSAwaitSession never spawned! Halting!"
                            $global:FunctionResult = "1"
                            return
                        }
                        else {
                            if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                            }
                            $Counter = 0
                            while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                Start-Sleep -Seconds 1
                                $Counter++
                            }
                        }
                    }
                }

                return
            }

            $CheckSendYesOutput = $CheckExpectedSendYesOutput | foreach {$_ -split "`n"}
            
            # This will handle EITHER the ssh login password prompt OR the sudo prompt (neither of which are guaranteed to happen)
            if ($CheckSendYesOutput -match "assword.*:") {
                if ($LocalPassword) {
                    $null = Send-AwaitCommand $LocalPassword
                }
                if ($DomainPassword) {
                    $null = Send-AwaitCommand $DomainPassword
                }
                Start-Sleep -Seconds 3

                if ($PwdPromptDelaySeconds) {
                    Start-Sleep -Seconds $PwdPromptDelaySeconds
                }

                $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

                if (!$SSHOutputPrep) {
                    [System.Collections.ArrayList]$script:SSHOutputPrep = @()
                    if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                        $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                    }
                }
                $Counter = 0
                $PwdPromptTimeoutSeconds = $PwdPromptTimeoutMin*60
                $CounterLimit = $PwdPromptTimeoutSeconds/10
                while (![bool]$($($SSHOutputPrep -split "`n") -match "assword.*:") -and 
                ![bool]$($($SSHOutputPrep -split "`n") -match $ScriptCompleteFlag) -and $Counter -le $CounterLimit) {
                    $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                    if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                        $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                    }
                    Start-Sleep -Seconds 10
                    $Counter++
                }
                if ($Counter -eq $($CounterLimit+1)) {
                    Write-Verbose "Sending the user's password timed out!"

                    #$SSHOutputPrep

                    if ($PSAwaitProcess.Id) {
                        try {
                            $null = Stop-AwaitSession
                        }
                        catch {
                            if ($PSAwaitProcess.Id -eq $PID) {
                                Write-Error "The PSAwaitSession never spawned! Halting!"
                                $global:FunctionResult = "1"
                                return
                            }
                            else {
                                if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                    Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                                }
                                $Counter = 0
                                while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                    Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                    Start-Sleep -Seconds 1
                                    $Counter++
                                }
                            }
                        }
                    }
                }
                
                # This will handle EITHER the sudo prompt or another generic password prompt (neither of which are guaranteed to happen)
                if ($SuccessOrAcceptHostKeyOrPwdPrompt -match "assword.*:" -or @($($SSHOutputPrep -split "`n"))[-1] -match "assword.*:") {
                    if ($LocalPassword) {
                        $null = Send-AwaitCommand $LocalPassword
                    }
                    if ($DomainPassword) {
                        $null = Send-AwaitCommand $DomainPassword
                    }
                    Start-Sleep -Seconds 3

                    if ($PwdPromptDelaySeconds) {
                        Start-Sleep -Seconds $PwdPromptDelaySeconds
                    }
    
                    $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

                    if (!$SSHOutputPrep) {
                        [System.Collections.ArrayList]$script:SSHOutputPrep = @()
                        if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                            $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                        }
                    }
                    $Counter = 0
                    $PwdPromptTimeoutSeconds = $PwdPromptTimeoutMin*60
                    $CounterLimit = $PwdPromptTimeoutSeconds/10
                    while (![bool]$($($SSHOutputPrep -split "`n") -match "assword.*:") -and 
                    ![bool]$($($SSHOutputPrep -split "`n") -match $ScriptCompleteFlag) -and $Counter -le $CounterLimit) {
                        $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                        if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                            $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                        }
                        Start-Sleep -Seconds 10
                        $Counter++
                    }
                    if ($Counter -eq $($CounterLimit+1)) {
                        Write-Verbose "Sending the user's password timed out!"

                        #$SSHOutputPrep

                        if ($PSAwaitProcess.Id) {
                            try {
                                $null = Stop-AwaitSession
                            }
                            catch {
                                if ($PSAwaitProcess.Id -eq $PID) {
                                    Write-Error "The PSAwaitSession never spawned! Halting!"
                                    $global:FunctionResult = "1"
                                    return
                                }
                                else {
                                    if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                        Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                                    }
                                    $Counter = 0
                                    while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                        Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                        Start-Sleep -Seconds 1
                                        $Counter++
                                    }
                                }
                            }
                        }
                    }

                    # We need this extra if block for MacOS because there is one more Password prompt
                    if ($SuccessOrAcceptHostKeyOrPwdPrompt -match "assword.*:" -or @($($SSHOutputPrep -split "`n"))[-1] -match "assword.*:") {
                        if ($LocalPassword) {
                            $null = Send-AwaitCommand $LocalPassword
                        }
                        if ($DomainPassword) {
                            $null = Send-AwaitCommand $DomainPassword
                        }
                        Start-Sleep -Seconds 3

                        if ($PwdPromptDelaySeconds) {
                            Start-Sleep -Seconds $PwdPromptDelaySeconds
                        }
        
                        $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
        
                        if (!$SSHOutputPrep) {
                            [System.Collections.ArrayList]$script:SSHOutputPrep = @()
                            if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                                $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                            }
                        }
                        $Counter = 0
                        $PwdPromptTimeoutSeconds = $PwdPromptTimeoutMin*60
                        $CounterLimit = $PwdPromptTimeoutSeconds/10
                        while (![bool]$($($SSHOutputPrep -split "`n") -match "assword.*:") -and 
                        ![bool]$($($SSHOutputPrep -split "`n") -match $ScriptCompleteFlag) -and $Counter -le $CounterLimit) {
                            $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                            if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                                $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                            }
                            Start-Sleep -Seconds 10
                            $Counter++
                        }
                        if ($Counter -eq $($CounterLimit+1)) {
                            Write-Verbose "Sending the user's password timed out!"
        
                            #$SSHOutputPrep
        
                            if ($PSAwaitProcess.Id) {
                                try {
                                    $null = Stop-AwaitSession
                                }
                                catch {
                                    if ($PSAwaitProcess.Id -eq $PID) {
                                        Write-Error "The PSAwaitSession never spawned! Halting!"
                                        $global:FunctionResult = "1"
                                        return
                                    }
                                    else {
                                        if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                            Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                                        }
                                        $Counter = 0
                                        while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                            Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                            Start-Sleep -Seconds 1
                                            $Counter++
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else {
                $SSHOutputPrep = $($CheckSendYesOutput | Out-String) -split "`n"
            }
        }
        elseif ($CheckResponsesOutput -match "assword.*:") {
            if ($LocalPassword) {
                $null = Send-AwaitCommand $LocalPassword
            }
            if ($DomainPassword) {
                $null = Send-AwaitCommand $DomainPassword
            }
            Start-Sleep -Seconds 3

            if ($PwdPromptDelaySeconds) {
                Start-Sleep -Seconds $PwdPromptDelaySeconds
            }

            $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

            if (!$SSHOutputPrep) {
                [System.Collections.ArrayList]$script:SSHOutputPrep = @()
                if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                    $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                }
            }
            $Counter = 0
            $PwdPromptTimeoutSeconds = $PwdPromptTimeoutMin*60
            $CounterLimit = $PwdPromptTimeoutSeconds/10
            while (![bool]$($($SSHOutputPrep -split "`n") -match "assword.*:") -and 
            ![bool]$($($SSHOutputPrep -split "`n") -match $ScriptCompleteFlag) -and $Counter -le $CounterLimit) {
                $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                    $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                }
                Start-Sleep -Seconds 10
                $Counter++
            }
            if ($Counter -eq $($CounterLimit+1)) {
                Write-Verbose "Sending the user's password timed out!"

                #$SSHOutputPrep

                if ($PSAwaitProcess.Id) {
                    try {
                        $null = Stop-AwaitSession
                    }
                    catch {
                        if ($PSAwaitProcess.Id -eq $PID) {
                            Write-Error "The PSAwaitSession never spawned! Halting!"
                            $global:FunctionResult = "1"
                            return
                        }
                        else {
                            if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                            }
                            $Counter = 0
                            while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                Start-Sleep -Seconds 1
                                $Counter++
                            }
                        }
                    }
                }
            }

            #Write-Host "`$SuccessOrAcceptHostKeyOrPwdPrompt is:`n$SuccessOrAcceptHostKeyOrPwdPrompt" -ForegroundColor Yellow
            #Write-Host "`$SSHOutputPrep is:`n$SSHOutputPrep" -ForegroundColor Yellow

            #$SuccessOrAcceptHostKeyOrPwdPrompt | Export-CliXml "$HOME\SuccessOrAcceptHostKeyOrPwdPrompt.xml"
            #$SSHOutputPrep | Export-CliXml "$HOME\SSHOutputPrep.xml"
            
            # This will handle EITHER the sudo prompt or another generic password prompt (neither of which are guaranteed to happen)
            if ($SuccessOrAcceptHostKeyOrPwdPrompt -match "assword.*:" -or @($($SSHOutputPrep -split "`n"))[-1] -match "assword.*:") {
                if ($LocalPassword) {
                    $null = Send-AwaitCommand $LocalPassword
                }
                if ($DomainPassword) {
                    $null = Send-AwaitCommand $DomainPassword
                }
                Start-Sleep -Seconds 3

                if ($PwdPromptDelaySeconds) {
                    Start-Sleep -Seconds $PwdPromptDelaySeconds
                }

                $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse

                if (!$SSHOutputPrep) {
                    [System.Collections.ArrayList]$script:SSHOutputPrep = @()
                    if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                        $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                    }
                }
                $Counter = 0
                $PwdPromptTimeoutSeconds = $PwdPromptTimeoutMin*60
                $CounterLimit = $PwdPromptTimeoutSeconds/10
                while (![bool]$($($SSHOutputPrep -split "`n") -match "assword.*:") -and 
                ![bool]$($($SSHOutputPrep -split "`n") -match $ScriptCompleteFlag) -and $Counter -le $CounterLimit) {
                    $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                    if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                        $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                    }
                    Start-Sleep -Seconds 10
                    $Counter++
                }
                if ($Counter -eq $($CounterLimit+1)) {
                    Write-Verbose "Sending the user's password timed out!"

                    #$SSHOutputPrep

                    if ($PSAwaitProcess.Id) {
                        try {
                            $null = Stop-AwaitSession
                        }
                        catch {
                            if ($PSAwaitProcess.Id -eq $PID) {
                                Write-Error "The PSAwaitSession never spawned! Halting!"
                                $global:FunctionResult = "1"
                                return
                            }
                            else {
                                if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                    Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                                }
                                $Counter = 0
                                while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                    Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                    Start-Sleep -Seconds 1
                                    $Counter++
                                }
                            }
                        }
                    }
                }

                #Write-Host "`$SuccessOrAcceptHostKeyOrPwdPrompt is:`n$SuccessOrAcceptHostKeyOrPwdPrompt" -ForegroundColor Yellow
                #Write-Host "`$SSHOutputPrep is:`n$SSHOutputPrep" -ForegroundColor Yellow

                #$SuccessOrAcceptHostKeyOrPwdPrompt | Export-CliXml "$HOME\SuccessOrAcceptHostKeyOrPwdPrompt2.xml"
                #$SSHOutputPrep | Export-CliXml "$HOME\SSHOutputPrep2.xml"

                # We need this extra if block for MacOS because there is one moe Password prompt
                if ($SuccessOrAcceptHostKeyOrPwdPrompt -match "assword.*:" -or @($($SSHOutputPrep -split "`n"))[-1] -match "assword.*:") {
                    if ($LocalPassword) {
                        $null = Send-AwaitCommand $LocalPassword
                    }
                    if ($DomainPassword) {
                        $null = Send-AwaitCommand $DomainPassword
                    }
                    Start-Sleep -Seconds 3

                    if ($PwdPromptDelaySeconds) {
                        Start-Sleep -Seconds $PwdPromptDelaySeconds
                    }
    
                    $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
    
                    if (!$SSHOutputPrep) {
                        [System.Collections.ArrayList]$script:SSHOutputPrep = @()
                        if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                            $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                        }
                    }
                    $Counter = 0
                    $PwdPromptTimeoutSeconds = $PwdPromptTimeoutMin*60
                    $CounterLimit = $PwdPromptTimeoutSeconds/10
                    while (![bool]$($($SSHOutputPrep -split "`n") -match "assword.*:") -and 
                    ![bool]$($($SSHOutputPrep -split "`n") -match $ScriptCompleteFlag) -and $Counter -le $CounterLimit) {
                        $SuccessOrAcceptHostKeyOrPwdPrompt = Receive-AwaitResponse
                        if (![System.String]::IsNullOrWhiteSpace($SuccessOrAcceptHostKeyOrPwdPrompt)) {
                            $null = $SSHOutputPrep.Add($SuccessOrAcceptHostKeyOrPwdPrompt)
                        }
                        Start-Sleep -Seconds 10
                        $Counter++
                    }
                    if ($Counter -eq $($CounterLimit+1)) {
                        Write-Verbose "Sending the user's password timed out!"
    
                        #$SSHOutputPrep
    
                        if ($PSAwaitProcess.Id) {
                            try {
                                $null = Stop-AwaitSession
                            }
                            catch {
                                if ($PSAwaitProcess.Id -eq $PID) {
                                    Write-Error "The PSAwaitSession never spawned! Halting!"
                                    $global:FunctionResult = "1"
                                    return
                                }
                                else {
                                    if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                                        Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                                    }
                                    $Counter = 0
                                    while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                                        Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                                        Start-Sleep -Seconds 1
                                        $Counter++
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            $SSHOutputPrep = $($CheckResponsesOutput | Out-String) -split "`n"
        }

        Write-Host "Waiting for up to $WindowsWaitTimeMin minutes for operation to finish..."
        Start-Sleep -Seconds $($WindowsWaitTimeMin*60)

        if ($PSAwaitProcess.Id) {
            try {
                $null = Stop-AwaitSession
            }
            catch {
                if ($PSAwaitProcess.Id -eq $PID) {
                    Write-Error "The PSAwaitSession never spawned! Halting!"
                    $global:FunctionResult = "1"
                    return
                }
                else {
                    if ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue)) {
                        Stop-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue
                    }
                    $Counter = 0
                    while ([bool]$(Get-Process -Id $PSAwaitProcess.Id -ErrorAction SilentlyContinue) -and $Counter -le 15) {
                        Write-Verbose "Waiting for Await Module Process Id $($PSAwaitProcess.Id) to end..."
                        Start-Sleep -Seconds 1
                        $Counter++
                    }
                }
            }
        }

        if (!$SSHOutputPrep) {
            $TentativeResult = "ManualVerificationRequired"
        }
        elseif (![bool]$($SSHOutputPrep -match $ScriptCompleteFlag)) {
            $TentativeResult = "ReviewAllOutput"
        }
        else {
            $TentativeResult = "Success"
        }

        $FinalOutput = [pscustomobject]@{
            TentativeResult         = $TentativeResult
            AllOutput               = $SSHOutputPrep
        }
    }

    if ($PSVersionTable.Platform -eq "Unix") {
        if ($DomainPassword -or $LocalPassword) {
            $FinalPassword = if ($DomainPassword) {$DomainPassword} else {$LocalPassword}
        }
        else {
            $FinalPassword = 'null'
        }
        #$FinalPassword = $FinalPassword -replace [regex]::Escape('$'),'\\\$' -replace [regex]::Escape('"'),'\\\"'

        if ($SSHScriptArray -and $ElevatedSSHScriptArray) {
            $ScriptA = $ExpectScriptArray | foreach {
                if ($_ -match "brew cask reinstall powershell") {
                    $SendLine = $_ -replace ' && echo powershellInstallComplete',''
                    $ExpectPwdPrompt = @(
                        "send -- \`"$SendLine\r\`""
                        'expect {'
                        ' -re \".*assword.*:\" {'
                        ' send -- \"\$password\r\"'
                        ' exp_continue'
                        ' }'
                        ' -re \"was successfully installed!\" {'
                        ' send -- \"echo powershellInstallComplete\r\"'
                        ' expect \"*\"'
                        ' }'
                        '}'
                    )
                    $ExpectPwdPrompt -join "`n"
                }
                elseif ($_ -match "powershellInstallComplete") {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'powershellInstallComplete')
                }
                elseif ($_ -match 'pwshConfigComplete') {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'pwshConfigComplete')
                }
                else {
                    'send -- \"' + $_ + '\r\"' + "`n" + 'expect -re \"$prompt\"'
                }
            }

            $ScriptB = $ElevatedExpectScriptArray | foreach {
                if ($_ -match "powershellInstallComplete") {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'powershellInstallComplete')
                }
                elseif ($_ -match 'pwshConfigComplete') {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'pwshConfigComplete')
                }
                else {
                    'send -- \"' + $_ + '\r\"' + "`n" + 'expect -re \"$prompt\"'
                }
            }
        }
        if (!$SSHScriptArray -and $ElevatedSSHScriptArray) {
            $ScriptB = $ElevatedExpectScriptArray | foreach {
                if ($_ -match "powershellInstallComplete") {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'powershellInstallComplete')
                }
                elseif ($_ -match 'pwshConfigComplete') {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'pwshConfigComplete')
                }
                else {
                    'send -- \"' + $_ + '\r\"' + "`n" + 'expect -re \"$prompt\"'
                }
            }
        }
        if ($SSHScriptArray -and !$ElevatedSSHScriptArray) {
            $ScriptA = $ExpectScriptArray | foreach {
                if ($_ -match "brew cask reinstall powershell") {
                    $SendLine = $_ -replace ' && echo powershellInstallComplete',''
                    $ExpectPwdPrompt = @(
                        "send -- \`"$SendLine\r\`""
                        'expect {'
                        ' -re \".*assword.*:\" {'
                        ' send -- \"\$password\r\"'
                        ' exp_continue'
                        ' }'
                        ' -re \"was successfully installed!\" {'
                        ' send -- \"echo powershellInstallComplete\r\"'
                        ' expect \"*\"'
                        ' }'
                        '}'
                    )
                    $ExpectPwdPrompt -join "`n"
                }
                elseif ($_ -match "powershellInstallComplete") {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'powershellInstallComplete')
                }
                elseif ($_ -match 'pwshConfigComplete') {
                    'send -- \"' + $_ + '\r\"' + "`n" + $('expect \"*{0}*\"' -f 'pwshConfigComplete')
                }
                else {
                    'send -- \"' + $_ + '\r\"' + "`n" + 'expect -re \"$prompt\"'
                }
            }
        }

        [System.Collections.ArrayList]$ExpectScriptPrep = @(
            'expect - << EOF'
            'set timeout 120'
            "set password $FinalPassword"
            'set prompt \"(>|:|#|\\\\\\$)\\\\s+\\$\"'
            "spawn $($SSHCmdStringArray -join " ")"
            'match_max 100000'
            'expect {'
            ' \"*(yes/no)?*\" {'
            ' send -- \"yes\r\"'
            ' exp_continue'
            ' }'
            ' -re \".*assword.*:\" {'
            ' send -- \"\$password\r\"'
            ' exp_continue'
            ' }'
            ' -re \"\$prompt\" {'
            ' send -- \"echo LoggedIn\r\"'
            ' expect \"*\"'
            ' }'
            '}'
        )
        if ($ScriptA) {
            $ScriptA | foreach {
                $null = $ExpectScriptPrep.Add($_)
            }
        }
        if ($ScriptB) {
            $null = $ExpectScriptPrep.Add('send -- \"sudo su\r\"')
            $null = $ExpectScriptPrep.Add('expect {')
            $null = $ExpectScriptPrep.Add(' -re \".*assword.*:\" {')
            $null = $ExpectScriptPrep.Add(' send -- \"\$password\r\"')
            $null = $ExpectScriptPrep.Add(' exp_continue')
            $null = $ExpectScriptPrep.Add(' }')
            $null = $ExpectScriptPrep.Add(' -re \"\$prompt\" {')
            $null = $ExpectScriptPrep.Add(' send -- \"echo StartSudoersUpdate\r\"')
            $null = $ExpectScriptPrep.Add(' expect \"StartSudoersUpdate\"')
            $null = $ExpectScriptPrep.Add(' }')
            $null = $ExpectScriptPrep.Add('}')
            $ScriptB | foreach {
                $null = $ExpectScriptPrep.Add($_)
            }
            $null = $ExpectScriptPrep.Add('send -- \"exit\r\"')
            $null = $ExpectScriptPrep.Add('expect -re \"\$prompt\"')
            $null = $ExpectScriptPrep.Add('send -- \"exit\r\"')
            $null = $ExpectScriptPrep.Add('expect eof')
            $null = $ExpectScriptPrep.Add('EOF')
        }
        else {
            $null = $ExpectScriptPrep.Add('send -- \"exit\r\"')
            $null = $ExpectScriptPrep.Add('expect eof')
            $null = $ExpectScriptPrep.Add('EOF')
        }
        $ExpectScript = $ExpectScriptPrep -join "`n"

        #Write-Host "`$ExpectScript is:`n$ExpectScript"
        #$ExpectScript | Export-CliXml "$HOME/ExpectScript2.xml"
        
        # The below $ExpectOutput is an array of strings
        $ExpectOutput = bash -c "$ExpectScript"

        # NOTE: The below -replace regex string removes garbage escape sequences like: [116;1H
        #$SSHOutputPrep = $ExpectOutput -replace "\e\[(\d+;)*(\d+)?[ABCDHJKfmsu]",""
        $SSHOutputPrep = $ExpectOutput

        if (!$SSHOutputPrep) {
            $TentativeResult = "ManualVerificationRequired"
        }
        elseif (![bool]$($SSHOutputPrep -match $ScriptCompleteFlag)) {
            $TentativeResult = "ReviewAllOutput"
        }
        else {
            $TentativeResult = "Success"
        }

        $FinalOutput = [pscustomobject]@{
            TentativeResult         = $TentativeResult
            AllOutput               = $SSHOutputPrep
        }
    }

    $FinalOutput
}