Search code examples
amazon-web-servicespowershellssm

SSM send-command with Powershell does not complete until background job finishes


I am using SSM send-command to start a Tomcat process on a Windows EC2 instance.

for example:

aws ssm send-command --instance-id i-xxxx --document-name "AWS-RunPowerShellScript"
   --parameters 'commands=["startup.bat"]'

This does indeed start Tomcat but I noticed that SSM command invocation itself is stuck in progress until I eventually shut Tomcat down, at which point it immediately succeeds.

My hunch is that something about the way SSM runs Powershell blocks on any spawned child processes (start java ... in the case of Tomcat). I don't think this is unique to Tomcat or even Java, though.

Is there a way I can get Powershell to exit, leaving the child processes running in the background?


Solution

  • If you want to start an independent process in PowerShell - one that stays alive even after the creating process terminates - use the Start-Process cmdlet:

    Start-Process aws -ArgumentList @'
    send-command --instance-id i-xxxx --document-name AWS-RunPowerShellScript --parameters commands=["startup.bat"]
    '@
    

    Note the use of a (literal) here-string (@'<newline>...<newline>'@) to make embedding quotes easier; see the bottom section of this answer for information about PowerShell string literals.

    While -ArgumentList can accept an array of arguments, the way these are translated into a command line is broken as of PowerShell 7.0 (and will likely not get fixed due to backward compatibility concerns; see this GitHub issue).

    Therefore, it is best to use a single argument with embedded quoting.

    Note that you should only use double quotes (") as argument delimiters when calling external programs (such as aws in this case).[1]


    [1] With direct invocation of an external program, you're free to use either quoting style, because PowerShell, when it rebuilds the command line behind the scenes, uses only " to quote arguments (if needed at all). In the case of Start-Process, the -ArgumentList value is passed through to a .NET API (System.Diagnostics.ProcessStartInfo), where no such translation is performed.