tl;dr
// Make PowerShell not only launch Calculator, but also
// determine and output its PID, as described in the next section.
out, _ :=
exec.Command(
`powershell.exe`,
`-NoProfile`,
`-Command`,
`Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID`,
).Output()
// Parse stdout output, which contains the PID, into an int
var pid int
fmt.Sscanf(string(out), "%d\n", &pid)
In principle, you can pass -PassThru
to PowerShell's Start-Process
(start
) cmd, which returns a process-info object that has an .Id
property containing the launched process' PID, and output the latter.
Unfortunately, with UWP / AppX applications specifically, such as Calculator, this does not work, which is a problem that exists in the underlying .NET APIs, up to at least .NET 6.0 - see GitHub issue #10996.
You can try the following workaround:
Launch the AppX application with Start-Process
, which indirectly creates a process whose name is Calculator
(Windows 10) / CalculatorApp
(Windows 11).
- You can identify this name yourself if you run
(Get-Process *calc*).Name
after launching Calculator. Get-Process *calc* | Select-Object Name, Path
would show the executable path too, but note that this executable should be considered an implementation detail and can not be invoked directly.
Return the ID of that Calculator
/ CalculatorApp
process. The fact that Calculator only ever creates one such process in a given user session actually makes identifying that process easy.
Note that this means that the PID of a preexisting Calculator process may be returned, which, however, is the correct one, because the transient process launched by Start-Process
simply delegates creation of a new Calculator window to an existing process.
If you wanted to identify the newly created window, more work would be required: You'd have to enumerate the process' windows and identify the one with the highest z-order.
PowerShell code (note: in Windows 11, replace Calculator
with CalculatorApp
):
# Launch Calculator - which may reuse an existing instance and
# merely create a new *window* - and report the PID.
Start-Process -ErrorAction Stop calculator:
(Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID
Note that I've used the URL scheme calculator:
as a simpler way to launch Calculator.
Note:
- The
Where-Object SessionId -eq (Get-Process -ID $PID).SessionId
guards against mistakenly considering potential Calculator
processes created by other users in their own sessions (Get-Process
returns all processes running on the local machine, across all user sessions). Filtering by .SessionID
, i.e. by the active user session (window station), prevents this problem.
As a PowerShell CLI call:
powershell.exe -NoProfile -Command "Start-Process -ErrorAction Stop calculator: ; (Get-Process Calculator | Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID"