I have a windows Powershell script that includes the following line...
$script:parent = (Get-Process -Id (Get-CimInstance Win32_Process -Filter "ProcessID = $pid").ParentProcessId).Name
The line appears twice in the same script. The first time it gets executed it always works fine and returns either svchost
, explorer
or powershell
(meaning that the script was either started by task scheduler, a shortcut on the desktop, or another powershell script).
The second time it's executed, it mostly works fine (and returns the same result) but occasionally returns the following...
Get-Process : Cannot find a process with the process identifier 17216.
At C:\blah\blah\testscript.ps1:2675 char:23
+ ... t:parent = (Get-Process -Id (Get-CimInstance Win32_Process -Filter "P ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (17216:Int32) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenId,Microsoft.PowerShell.Commands.GetProcessCommand
Why is it failing the 2nd time?
(BTW - I'm asking this out of curiosity only, there's a simple fix - only execute the command the one time!)
UPDATE - @mklement0 answer is correct. I hadn't spotted a critical fact, the second execution of 'who's the parent' only ever fails if the parent was a powershell
script. The script runs 24*7 and is designed that in the event of a critical failure it will re-start another copy of itself and then exit. Since this only occurs once or twice a month I had forgotten about this feature
As iRon states in a comment on the question, your symptom implies that the parent process no longer exists at the time the 2nd call is made.
This can indeed happen, for instance, if you call a PowerShell script via powershell.exe
, the Windows PowerShell CLI, using an asynchronous call via Start-Process
, i.e. a call that does not use the -Wait
switch.
Building on your own example Start-Process
call, the following script demonstrates this scenario:
Save the code to a *.ps1
file and invoke it from a PowerShell session launched via the Windows (GUI) shell, such as via the Start Menu or the taskbar.
The script will re-invoke itself, asynchronously, in a new console window, via a powershell.exe
child process.
The original invocation will exit the original PowerShell session (and therefore close its window) after about 1 second.
In the new window, you'll see that the first attempt to get the parent process succeeds, but the second will fail, because by that time the parent process no longer exists.
# Script block for later use to determine the parent process' name.
$sbGetParentProcessName = {
(Get-Process -Id (Get-CimInstance Win32_Process -Filter "ProcessID = $pid").ParentProcessId).Name
}
$parent = & $sbGetParentProcessName
"1st attempt: parent process name is: $parent"
# If this script was invoked from the Windows (GUI) shell (Start Menu, taskbar, desktop, ...),
# or from a scheduled task or a service, re-invoke it, then exit after 1 sec.
if ($parent -in 'explorer', 'svchost') {
Write-Verbose "Re-invoking this script asynchronously..."
Start-Process -FilePath "$PSHOME\powershell.exe" -ArgumentList '-NoExit', '-File', """$PSCommandPath"""
Write-Verbose -Verbose 'Exiting after 1 sec...'
Start-Sleep 1
[Environment]::Exit(0)
}
# Getting here means that the script is being re-invoked.
# Sleeping for 2 seconds ensures that the parent process no longer exists.
Write-Verbose -Verbose 'Sleeping 2 seconds...'
Start-Sleep 2
# This attempt now predictably fails.
# Note: The error message will print *first*.
"2nd attempt: parent process name is: $(& $sbGetParentProcessName)"