Using Start-Job
or PowerShell v6+'s &
background operator isn't an option, because terminating the job will also terminate child processes launched from it, which jobs are - both on Windows and on Unix-like platforms.
However, you can achieve nohup
-like behavior via the Start-Process
cmdlet:
On Unix-like platforms, you can combine Start-Process
with nohup
:
The following example launches a background PowerShell instance that stays alive even after you close the launching terminal; it emits a .
every second, and nohup
collects both stdout and stderr output in file nohup.out
in the current directory, appending to such a file if it already exists:
# Runs for 2 minutes and appends both stdout and stderr output to ./nohup.out
Start-Process nohup 'pwsh -nop -c "1..120 | % { write-host . -nonewline; sleep 1 }"'
Caveat: As of PowerShell 7.2, running this command via a SSH connection only works if the connection was initiated via ssh
, not via PowerShell's own SSH-based remoting cmdlets, such as Invoke-Command
and Enter-PSSession
[1].
For instance - assuming that the user's default shell on the target computer is pwsh
(PowerShell), the following command could be used; note that option -t
is needed in order to allocate a pseudo terminal (pty), so that nohup
thinks its stdout is connected to a terminal and therefore sends its output to file .\nohup.out
):
ssh -t <user>@<host> 'Start-Process nohup ''pwsh -nop -c \"1..120 | % { write-host . -nonewline; sleep 1 }\"'''
Note the surprising need for \"
rather than just "
, required to compensate for PowerShell's still-broken argument-passing to external programs as of PowerShell 7.1 - see this answer.
By contrast, if the user's default shell on the target computer is a POSIX-compatible shell such as bash
, use the following (run from PowerShell):
# IMPORTANT: If the target machine runs macOS rather than Linux, use the
# `pwsh`'s *full path*, which is `/usr/local/bin/pwsh` by default.
ssh -t <user>@<host> 'nohup pwsh -nop -c ''1..120 | % { write-host . -nonewline; sleep 1 }'' & whoami >/dev/null'
Note the use of dummy command whoami >/dev/null
after submitting the background job ( &
), which is seemingly required to ensure that nohup
gets enough time to actually launch its target command.
On Windows, where Start-Process
by default creates an independent process in a new console window, you can use -WindowStyle Hidden
to launch that process in a hidden window that will remain alive independently of the launching shell.
# Runs for 2 minutes and appends success output to ./nohup.out
Start-Process -WindowStyle Hidden pwsh '-nop -c "1..120 | % { Add-Content -nonewline nohup.out -Value .; sleep 1 }"'
Caveat: This does not work as-is work remoting:
In a remoting sessio, Start-Process
cannot launch the process in a separate (hidden) window this way, so on exiting the remoting session the launched process is terminated as well.
However, you can create a disconnected session that remains alive on the target computer until it is explicitly deleted (or until the target computer reboots); alternatively, create a regular (connected) session explicitly and keep it as long as needed - though if the calling computer reboots before the task is completed, the task is again terminated (unless you explicitly disconnect the session first).
An example, using Invoke-Command
's -InDisconnectedSession
switch:
# Launch the command remotely, in a disconnected session, and
# return a session-information object:
$disconnSess = Invoke-Command -Computer <host> -InDisconnectedSession {
Start-Process -WindowStyle Hidden pwsh '-nop -c "1..120 | % { Add-Content -nonewline nohup.out -Value .; sleep 1 }"'
}
# ... Let the command finish
# Remove the session again
Remove-PSSession $disconnSess
[1] These cmdlets do not allocate a pseudo terminal (pty), the absence of which causes nohup
to print its output to stdout and stderr rather than to file .\nohup.out
. Additionally, this unexpected, directly printed output can cause the remote PowerShell session to crash.
Start-Job
are killed when the launching shell exits. – Asel