Invoking remote sudo commands in the PowerShell sessions

First, PowerShell Core have to be installed on every target Linux machine and added to its /etc/ssh/sshd_config:

Subsystem       powershell /usr/bin/pwsh -sshs -NoLogo -NoProfile

Probably, in a script you have the remote session to that target box started like:

$s = New-PSSession -HostName $deployHostname -UserName $login -KeyFilePath $keyfile

If you have to execute a sudo command in that session, you could do like:

Invoke-Command -Session $s {
    Invoke-Expression "sudo ..."
}

Imagine you put your script into CI / CD pipeline and want to see its output in a log. In case of failure of a command invoked like shown above, probably, you'll be frustrated with the error output like this:

NotSpecified: (:String) [], RemoteException
script returned exit code 1

Such useless output originate from the fact that fail happens in a remote session. You can't cope with that by just adding a conversion of an output error to exception with -ErrorAction Stop parameter for Invoke-Expression, because the output of the invoked shell command is not a PowerShell error output.

But throwing exceptions is the right way of passing errors. So, the working solution includes writing output to a file and throwing its content with the exception this way:

Invoke-Command -Session $s {
    $errFile = "/tmp/$($(New-Guid).Guid).err"
    Invoke-Expression "sudo ... 2>${errFile}" -ErrorAction Stop
    $err = Get-Content $errFile -ErrorAction SilentlyContinue
    Remove-Item $errFile -ErrorAction SilentlyContinue
    If (-Not $null -eq $err)
    {
        throw $err
    }
}

Perfect, but has too many lines of code for just copying and pasting it all over the script. So, let's introduce a function:

function Invoke-SudoCommand {
<#
.SYNOPSIS
Invokes sudo command in a remote session to Linux
#>
    param (
        [Parameter(Mandatory=$true)]
        [PSSession]
        $Session,

        [Parameter(Mandatory=$true)]
        [String]
        $Command
    )
    Invoke-Command -Session $Session {
        $errFile = "/tmp/$($(New-Guid).Guid).err"
        Invoke-Expression "sudo ${using:Command} 2>${errFile}" -ErrorAction Stop
        $err = Get-Content $errFile -ErrorAction SilentlyContinue
        Remove-Item $errFile -ErrorAction SilentlyContinue
        If (-Not $null -eq $err)
        {
            throw $err
        }
    }
}

Using this function you can invoke sudo commands with a single line of code:

Invoke-SudoCommand -Session $s -Command "..."

Script variables can also be used:

Invoke-SudoCommand -Session $s -Command "rm -rf ${targetFolder}"
Invoke-SudoCommand -Session $s -Command "unzip ${zipName} -d ${targetFolder}"

PowerShell allows you to wrap things in a pretty neat way, isn't it?

Guessing can you use this function inside of a 1st level remote session to execute the sudo commands in the nested remote sessions? Sure, export a function to the remote session and invoke it there. Look in this repository for the implementation and usage of Export-FunctionRemote.