I have a ps1 script which runs some set of apps. All are run with the commands like:
$this.apps.Add($(Start-Process "$($global:openTrackDir)\opentrack.exe" `
-WorkingDirectory "$($global:openTrackDir)" -Verb RunAs -PassThru)
Add
is used because I need reference to those apps to close them later.
Problem is opentrack generates in console some debug messages:
DEBUG [C:\repos\opentrack\api/plugin-support.hpp:106]: library "kinect-face" failed: "Cannot load library C:\\Program Files\\opentrack\\modules\\\\opentrack-tracker-kinect-face.dll: Can't
I would like to get rid of those messages but I don't know how to do this.
I found page https://powershell.one/code/9.html and those solutions seems to be something I look for, but when I try to apply something there is no effect.
How to remove not wanted messages from console effectively (if it is possible).
In order to silence the output from your elevated process, you need to call via a shell and use its redirections (you cannot use -RedirectStandardOutput
/ -RedirectStandardError
, because it cannot be combined with -Verb RunAs
).
Start-Process
call in an effort to target the launched process' streams: the launched processes output streams are not output by this cmdlet; it produces no output by default, and with -PassThru
it outputs a .NET object (of type System.Diagnostics.Process
) with information about the newly launched process.While you could use powershell.exe
, cmd.exe
is more lightweight;
the following silences both the stdout and stderr streams:
$this.apps.Add(
(Start-Process -Verb RunAs -PassThru `
-FilePath cmd.exe -Args "/c cd /d `"$global:openTrackDir`" && `"$global:openTrackDir\opentrack.exe`" >NUL 2>&1"
)
)
Note that I've omitted -WorkingDirectory "$global:openTrackDir"
and have instead included a cd
command as part of the shell command to pass to cmd.exe
, because the -WorkingDirectory
argument would be ignored in combination with -Verb RunAs
.[1]
Limitations:
Because of the use of cmd.exe
as an intermediary, -PassThru
returns information about the cmd.exe
process, not the ultimately launched opentrack.exe
process.
While you can obtain a process-information object about the latter as follows, if your script runs in a non-elevated process, you won't be able to kill that process with, e.g., Stop-Process
, because it wasn't directly launched by Start-Process
:[2]
$indirectlyLaunchedProcess =
(Get-CimInstance Win32_Process -Filter "ParentProcessId = $($this.apps[$i])") |
Where-Object Name -ne conhost.exe
Attempting $indirectlyLaunchedProcess | Stop-Process
will result in an Access Denied
error - unless your script is also running in an elevated session.
If your script is running in an elevated session, you'll need to kill both the cmd.exe
intermediary and your opentrack.exe
process:
Stop-Process -Id $indirectlyLaunchedProcess.ProcessId, $this.apps[$i].Id
The Where-Object
command filters out the helper conhost.exe
child process that is implicitly created for any process that allocates a console window.
[1] -WorkingDirectory
would be honored by .NET applications in general, such as pwsh.exe
, the PowerShell (Core) 7 CLI, but, curiously, not by powershell.exe
, the Windows PowerShell CLI, which in this context behaves like a native application such as cmd.exe
- see this answer for details.
[2] Note that killing the directly launched elevated process works even when running in a non-elevated session, but only if the process-information object - obtained via Start-Process
's -PassThru
switch - is passed to Stop-Process
. That is, $this.apps[$i] | Stop-Process
and Stop-Process $this.apps[$i]
both work, but Stop-Process -Id $this.apps[$i].Id
does not.
However, killing only the cmd.exe
intermediary isn't sufficient, because the child process launched from it lives on.