User Guide for the Process-Created Watcher Script
Introduction
When troubleshooting situations such as a slow or failing logon or a user failing to perform some task, it can be useful to know what processes were launched, when they were launched and what command line arguments were used.
Traditionally, people have used a number of different methods to glean this information:
- Using SysInternals Process Monitor, although this can be difficult to remote to single-user operating systems like Windows 10 and can massively slow down operations because of its own large resource requirements.
- Enabling process creation and termination auditing events, and then piecing together the activity by analysis of these events which are written to the security event log.
Presented here is a different approach that gets Windows Management Instrumentation (WMI) notifications for new process creations via the WqlEventQuery class available in the .NET Framework. The benefits of this approach include:
- Low overhead/resource usage
- No prerequisites, such as enabling process creation and command line auditing
- Easily remoted
- No elevation required (scenario dependent)
The script can show not only what is run, almost as soon as it happens, but also has features to allow it to perform actions when specific processes, optionally matching specific command lines, are run. These actions are asynchronous, so are not suited to some needs, but can be useful to take process dumps or kill the original process and re-launch another one with a different command line or even run a completely different executable.
Process Creation Monitoring
Local Logon Monitoring
The most common use case for this script is likely seeing what processes are created, by what and with what command lines, during a user logon or potentially a logoff, if that is problematic. There are two ways we can run the script to monitor logons:
- Use a separate administrator session when on a multi-user operating system such as Server 2016 or 2019, e.g., when using Parallels® Remote Application Server (RAS), Citrix Virtual Apps and Desktops or VMware Horizon.
- Use the built-in remoting capabilities of the script. This itself has two different methods that use either standard Windows Remoting (winrm), which is more efficient here, or by just remoting specific calls, which doesn’t require winrm to have been configured and working.
The remoting behaviour is controlled by the -nowinrm parameter. Specify this if winrm does not work when -computer has been used to specify a non-local machine.
To monitor a new session on a multi-user OS, we run something like this in an elevated PowerShell prompt in a session on that server, eg., via mstsc or console:
& 'C:\Scripts\Process created watcher.ps1' -newSessionsOnly -outputCsv logon.csv -afterLogon -overwrite -includeUsers 'system|billybob' | Out-GridView
We are instructing the script to only report processes for sessions created after the script starts and only where the username for new processes is either “system” or “billybob” (the user launching the new session). We get an onscreen grid view in real-time, as shown below, but it also records the same information to the file logon.csv in the folder where the script is run from.
Note: In the above screenshot, we have the SecondsAfterLogon column. AfterLogon was specified so the script queries LSASS for the exact logon time (which can vary considerably from the time reported by “query user” (quser.exe) which comes from the WTS API – 10 seconds in the example here). This shows how long after the logon time that each process was started.
Remote Logon Monitoring
If the system requiring monitoring is not a multi-user OS, e.g., Windows 10, we cannot establish a full, interactive administrator session to monitor new sessions. We can use the script from another machine that has rights to access the remote machine, which is typically allowed when running elevated as a domain administrator or with equivalent privileges.
Here is an example of running in an elevated PowerShell prompt on a Server 2016 machine that’s watching for a logon on a Windows 10 machine:
& 'C:\Scripts\Process created watcher.ps1' -newSessionsOnly -afterLogon -computer GLFLXX02 | Out-GridView
It results in output like this, on the Server 2016 machine where the script is running:
In-Session Monitoring
Sometimes we may need to troubleshoot why something seemingly incorrect is happening in an existing user’s session, such as a viewer application not launching when an attachment is opened in an email program or similar. In this scenario, the simplest way to run the script is from within a non-elevated PowerShell session within the user’s session. We can run the script as follows:
& 'C:\Scripts\Process created watcher.ps1'
This will output details of all new processes created similar to this:
We could use the -outputcsv parameter or pipe it through Out-GridView (ogv) as in the previous example.
Taking Actions on a Process Start
An additional feature of this script is the ability to take actions when one or more specific processes are launched. Bear in mind that the actions are asynchronous, meaning that the process notifications this script receives will be processed after the newly created process runs, so it may already have finished or delivered its payload by the time the script receives the notification and takes any configured action.
The actions available, via the -action parameter, comprise:
Action | Purpose |
Launch | Launch a new process, leaving the triggering one to also run |
LaunchInstead | Kill the triggering process and launch a new one |
Relaunch | Kill the triggering process and launch it again (with different parameters) |
Kill | Kill the triggering process |
KillParent | Kill the triggering process’s parent process |
In addition, there are the following command line parameters that can be used:
Parameter | Purpose |
-actionDelaySeconds | Delay in seconds, or part thereof, from when process is launched to when action is performed |
-matchParameters | Only perform the action if the parameters to the process match this regex |
-newProcess | The new process to launch, including path if required |
-newParameters | Parameters to pass to the new process |
The -newParameters parameter can take the following pseudo-environment variables which will be expanded before the action is performed:
Variable | Replacement |
%cmdline% | Command line passed to the original process |
%pid% | Process id of the process on which the action has been triggered |
%processname% | Name of the process on which the action has been triggered (not including the path) |
%username% | User name of the account owning the process on which the action has been triggered |
Real environment variables will also be expanded, if they are available. For example, the following connects remotely to the computer GLW10MCS01. When explorer.exe is launched in any new session, it will also launch the procdump.exe utility, 30 seconds after the start of explorer.exe, with the command line specified. This includes the process id (pid) of explorer via the %pid% pseudo-environment variable.
& '.\Process created watcher.ps1' -newSessionsOnly -computer GLW10MCS01 -includeProcesses explorer.exe -action Launch -actionDelaySeconds 30 -newProcess 'C:\Program Files\sysinternals\procdump.exe' -newParameters '-accepteula -ma %pid% c:\temp\dumps' -confirm:$false
Notes:
- The window title property is only available when the script is running in the user’s own session, locally.
- When the -newSessionsOnly or -afterLogon parameters are used, the script needs to have access to the script WTSAPI.ps1, which uses the Microsoft WTS APIs to query session information, in the same folder as this script. This is available on GitHub and if the -download parameter is specified, the script will attempt to download it.
- The default remoting mechanism used, in order to get more detailed process information, is Windows Remoting (winrm). However, if this is not configured (run winrm quickconfig or Enable-PSRemoting elevated on the remote machine) or not working to a machine, the -nowinrm parameter can be specified. This will remote the Get-Process cmdlet directly, which should only require the remote registry service to be running on the remote machine although it is not as efficient as Windows Remoting. Even without -nowinrm, the script will fall back to using Get-Process, but the failure to establish a winrm session can take upwards of 30 seconds.
- Do not pipe the output into Format-Table -Autosize since the autosize parameter reads all input in order to figure out the best column sizes so live output will be blocked until the script exits or is terminated (by default it does not exit of its own accord). Instead, either pipe through Out-Gridview or get as wide a PowerShell window as possible and use the -width parameter to specify the column width of the window. Alternatively, if no live output is required, e.g., the data is being recorded to file via the -outputCSV parameter, pipe to Out-Null.
- In Parallels RAS 18, administrators have a complete overview of user session details to pinpoint anomalies faster. With advanced session details, administrators can view metrics such as logon duration and logon duration breakdown, incoming and outgoing data within a session, bandwidth availability and usage, network latency, user connection flow, and the number of reconnects and disconnect reasons. For example, logon duration and logon duration breakdown consist of the following:
Logon duration Time taken to log on, excluding the time waiting on UI Logon duration breakdown 1. Connection time 2. Authentication duration 3. Host preparation (includes load-balancing algorithm) 4. User-profile load time 5. RAS policies lookup 6. Group Policy processing 7. Desktop loading 8. Other
Bio – Guy Leech
I first wrote software in 1980 as a teenager and then for 6 years from 1988 after graduating from the University of Manchester with a Computer Science degree. In 1995 I became involved with Citrix and have moved in the EUC sphere ever since with a number of stints at Citrix partners in the UK and a long tenure at AppSense (now Ivanti) after coming up with the idea, and writing from scratch, a security product in 1998 that became AppSense Application Manager (now Ivanti Application Control).
In 2009 and 2010 I was awarded the VMware vExpert title (the first 2 years of the program) and again in 2020, the Citrix Technology Advocate honour in 2019 and both Citrix Technology Professional and Microsoft MVP in 2020.
Currently, I am a self-employed consultant providing a mixture of services to end customers, Citrix partners and software vendors, specialising in troubleshooting and software development.