Search code examples
powershellcommand-line-interfacestart-job

-s when using Start-Job in powershell


I am trying to call a Start-Job in powershell. When I do, it spawns a background powershell with the following arguments:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Version 5.0 -s -NoLogo -NoProfile -EncodedCommand [encoded command I want to run in base64]

However, the powershell command never seems to complete, whatever the command I send it.

I tried spawning a powershell instance like this:

powershell.exe -s

And this also seems to create an instance that seems frozen, not executing or doing anything. Looking online, I cannot seem to find any reference to the -s argument.

Does anybody know what it's for or how to get rid of it so that my start-jobs work properly?

Edit: It's possible that -s is the shorthand for -sta, but my command does not freeze using -sta, but it does using -s.

Edit2: I have since found out that -s is a shorthand for -ServerMode, apparently a Legacy Powershell 2.0 option. I have no idea why that is added when using Start-Job.

Edit3: The command I use is:

$deploymentsJobs += Start-Job -InitializationScript { SomeSmallFunction } (AnotherFunction) -ArgumentList  $arg1, $arg2, $arg3}

Solution

  • tl;dr:

    • The -s option is an expected part of the command line used to launch a background job via a new PowerShell process - it puts the new process in server mode, which is required to communicate with the calling process for background job management.

      • It is not a legacy option, but it isn't documented either, because it is only meant to be used internally by PowerShell.
    • Given that everything you describe is as expected, the problem is likely with the specific commands you run via -InitializationScript and in the main script block (the implied -ScriptBlock argument).


    As you've discovered, a Start-Job call spawns a powershell -s -NoLogo -NoProfile call behind the scenes (discoverable via Task Manager).
    That is, a new PowerShell process is created to run the commands in the background.

    An -EncodedCommand parameter with a Base64-encoded command string is only present if you invoked Start-Process with the -Initialization parameter - the main script block (the (implied) -ScriptBlock argument) is not passed via the command line (see below).

    -s is used PowerShell-internally - always - to invoke background jobs, and -s, as you've also discovered, is an alias for the -servermode switch. (Given that only -STA is documented, one would expect -s to be short for -STA, but it is not).
    -s / -servermode is an implementation detail, used only by PowerShell itself, which is why it isn't documented.

    This location in the PowerShell Core source code on GitHub shows you how the command line for the background process is constructed.

    Server mode is the mode the background process must be in in order to communicate with the calling process via its standard streams (stdin, stdout, stderr): That is, the command to execute in the background is sent to the background process through its stdin stream, and the background process reports its output via its stdout and stderr streams.[1]

    Note that XML-based serialization / deserialization happens during this inter-process communication, using the same infrastructure as PowerShell remoting - see this answer for more information.


    [1] Ohad Schneider points out that it is possible to accidentally disrupt this communication if the main script block contains commands such as Start-Process -NoNewWindow with a console program that directly write to the background process' stdout stream - see this answer.