The Invoke-CommandAs module allows you to execute PowerShell commands remotely as the SYSTEM account. In this article, I will show how Invoke-CommandAs works and some of the behind-the-scenes code it uses.

One of the great features of PowerShell is the ability to run commands and scripts remotely on machines. I often find myself either entering an interactive session with Enter-PSSession or using Invoke-Command on multiple machines at once. I am an old PSExec user, and although I do not find much use for it anymore now that PowerShell can do so many things PSExec does (and better), to me it still has had one benefit.

This would be the ability to run remote commands as the SYSTEM account by specifying the ‑s parameter like this:

PSExec.exe –s \\machine whoami

I have searched in the past for solutions that let me do this in PowerShell, but recently one module has made it possible: Invoke-CommandAs. This module aims to address this very problem in PowerShell, and it does so wonderfully. Its creator is Marc Kellerman, whom I met at PowerShell Summit this year.

How it works

For Windows 8/2012+ systems, the command uses the ScheduledTasks module to register and run script blocks on remote systems. For Windows 7/2008, it creates a scheduled task COM object and invokes the code this way since the ScheduledJobs module is not available on these versions of Windows.

This serves two critical functions. For one, it provides a way to solve the PowerShell double-hop problem by running the code "locally" under a scheduled task. In addition, it creates and runs the task under the SYSTEM account, which can be preferable for things such as installing software.

PowerShell remotely as SYSTEM

To show that the remote commands are actually running under the SYSTEM account, I can do a simple test using the whoami command. Note that I specify ‑AsSystem as a parameter, which is not a parameter you can use in Invoke-Command.

whoami under the SYSTEM account

whoami under the SYSTEM account

Next, we will do something a bit more interesting. Let's use Invoke-CommandAs to install a Chocolatey package remotely as SYSTEM.

C:\> Invoke-CommandAs -ComputerName TestMachine -ScriptBlock { choco install curl  y   no-progress } -AsSystem -RunElevated
Chocolatey v0.10.11
Installing the following packages:
curl
By installing you accept licenses for the packages.

curl v7.62.0
curl package files install completed. Performing other installation steps.
Extracting 64-bit C:\ProgramData\chocolatey\lib\curl\tools\curl-7.62.0-win64-mingw.zip to C:\ProgramData\chocolatey\lib\curl\tools...
C:\ProgramData\chocolatey\lib\curl\tools
 ShimGen has successfully created a shim for curl.exe
 The install of curl was successful.
  Software installed to 'C:\ProgramData\chocolatey\lib\curl\tools'

Chocolatey installed 1/1 packages.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

As you can see, it works like a charm, returning me the same output I would see if I ran this command locally.

Solving the double-hop issue

There are various ways to get around the PowerShell double-hop issues, which occur when you attempt to access a Server Message Block (SMB) share from a remote session. Invoke-CommandAs does this within the cmdlet. Not only this, but you can also run the scriptblock as a completely different user and pass your local credential object to the remote computer with the ‑As parameter.

Subscribe to 4sysops newsletter!

PS C:\> $Credential = Get-Credential
PS C:\> Invoke-CommandAs -ComputerName TestMachine -ScriptBlock {Get-Item \\Server\Test} -As $Credential

    Directory:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d--hs               12/5/2018   2:58 PM   Test

Wrap-up

One of the characteristics I enjoy most about the PowerShell community is the number of quality modules created. Chances are if you are looking for a module for a specific circumstance, it is in the PowerShell Gallery. Invoke-CommandAs does exactly that by solving not only running remote commands as SYSTEM but solving the double-hop issue as well.

avataravataravataravatar
10 Comments
  1. Marc R Kellerman 5 years ago

    Thanks for the shoutout!

    avatar
  2. Nice Article Dan!

    I have to download Mark’s module and kick the tires; it looks super useful!

  3. Great article Dan. Thanks for sharing.

  4. James Mathias 5 years ago

    If Invoke-CommandAs is not available, where can I get this module?

    Thanks…

    James

  5. Amazing!

  6. Peter 3 years ago

    What would be the syntax if you wanted to run a separate powershell script as the logged in user?

    Something like this…

    Invoke-CommandAs -FilePath C:\Scripts\PowershellScript.ps1 -ComputerName WIN10 -Interactive

    But it's looking for argument for that parameter.

    avatar
    • Peter 3 years ago

       I'm trying to run a script that the user interacts with. It seems like no matter what parameters I use, the script does not run interactively with the logged on user. I tried this…

      $LoggedInUser = Invoke-Command -ScriptBlock {Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -expand UserName} -ComputerName WIN10
      
      Invoke-CommandAs -ScriptBlock {notepad.exe} -ComputerName PICAWK0351NEC01 -AsInteractive $LoggedInUser
      

      …but notepad still ran as me and not the logged in user.

      avatar
      • Leos Marek (Rank 4) 3 years ago

        Have you tried the command on the first line? 🙂 It does not return a property named UserName from remote system. Even when I try the command locally, the UserName is empty.

      • Leos Marek (Rank 4) 3 years ago

        Furthermore – executing something under user context does not mean that the user will get a GUI of that process… 

Leave a reply

Your email address will not be published. Required fields are marked *

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account