Chapter 17. Processes, Services, and Event Logs

by Mar 25, 2012

In your daily work as an administrator, you will probably often deal with applications (processes), services, and event logs so let’s take some of the knowledge you gained from the previous chapters and play with it. The examples and topics covered in this chapter are meant to give you an idea of what you can do. By no means are they a complete list of what you can do. They will provide you with a great starting point, though.

Working with Processes

Every application that is running is represented by a so-called “process”. To view all running processes, use Get-Process cmdlet.

PS> Get-Process

This will list all running processes on the local machine, not just yours. So if other people are logged onto your box, their processes may also show up in that list. However, unless you have local Administrator privileges, you can only access limited properties of processes you did not launch yourself.

That’s why Get-Process throws a number of exceptions when you try and list the executable files of all running processes. Exceptions occur either when there is no executable for a given process (namely System and Idle), or if you do not have permission to see them:

PS> Get-Process -FileVersionInfo

To hide error messages and focus only on the information you are able to retrieve, use the common parameter -ErrorAction SilentlyContinue which is available in every cmdlet – or its short form -ea 0:

PS> Get-Process -FileVersionInfo -ErrorAction SilentlyContinue
PS> Get-Process -FileVersionInfo -ea 0

Process objects returned from Get-Process contain a lot more information that you can see when you pipe the result to Select-Object and have it display all object properties:

PS> Get-Process | Select-Object *

You can then examine the object properties available, and put together your own reports by picking the properties that you need:

PS> Get-Process | Select-Object Name, Description, Company, MainWindowTitle

Name                Description         Company             MainWindowTitle
----                -----------         -------             ---------------
AppleMobileDevic...
conhost             Console Window Host Microsoft Corpor...
csrss
csrss
DataCardMonitor     DataCardMonitor ... Huawei Technolog... DataCardMonitor
Dropbox             Dropbox             Dropbox, Inc.
dwm                 Desktop Window M... Microsoft Corpor...
(...)

When you do that, you’ll notice that there may be blank lines. They occur when a process object has no information for the particular property you selected. For example, the property MainWindowTitle represents the text in the title bar of an application window. So, if a process has no application window, MainWindowTitle is empty.

You can use the standard pipeline cmdlets to take care of that. Use Where-Object to filter out processes that do not meet your requirements. For example, this line will get you only processes that do have an application window:

PS> Get-Process | Where-Object { $_.MainWindowTitle -ne '' } |
>> Select-Object Description, MainWindowTitle, Name, Company
>>

Description         MainWindowTitle     Name                Company
-----------         ---------------     ----                -------
DataCardMonitor ... DataCardMonitor     DataCardMonitor     Huawei Technolog...
Remote Desktop C... storage1 - Remot... mstsc               Microsoft Corpor...
Windows PowerShell  Windows PowerShell  powershell          Microsoft Corpor...
Microsoft Office... eBook_Chap17_V2.... WINWORD             Microsoft Corpor...

Note that you can also retrieve information about processes by using WMI:

PS> Get-WmiObject Win32_Process

WMI will get you even more details about running processes.

Both Get-Process and Get-WmiObject support the parameter -ComputerName, so you can use both to retrieve processes remotely from other machines. However, only Get-WmiObject also supports the parameter -Credential so you can authenticate. Get-Process always uses your current identity, and unless you are Domain Administrator or otherwise have local Administrator privileges at the target machine, you will get an Access Denied error.

Note that even with Get-Process, you can authenticate. Establish an IPC network connection to the target machine, and use this connection for authentication. Here is an example:

PS> net use \someRemoteMachine Password /USER:domainusername

Here are some more examples of using pipeline cmdlets to refine the results returned by Get-Process. Can you decipher what these lines would do?

PS> Get-Process | Where-Object { $_.StartTime -gt (Get-Date).AddMinutes(-180)} 
PS> @(Get-Process notepad -ea 0).Count
PS> Get-Process | Measure-Object -Average -Maximum -Minimum -Property PagedSystemMemorySize

Accessing Process Objects

Each Process object contains methods and properties. As discussed in detail in Chapter 6, many properties may be read as well as modified, and methods can be executed like commands. This allows you to control many fine settings of processes. For example, you can specifically raise or lower the priority of a process. The next statement lowers the priority of all Notepads:

PS> Get-Process notepad | ForEach-Object { $_.PriorityClass = "BelowNormal" }

Launching New Processes (Applications)

Launching applications from PowerShell is pretty straight-forward: simply enter the name of the program you want to run, and press ENTER:

PS> notepad
PS> regedit
PS> ipconfig

This works great, but eventually you’ll run into situations where you cannot seem to launch an application. PowerShell might complain that it would not recognize the application name although you know for sure that it exists.

When this happens, you need to specify the absolute or relative path name to the application file. That can become tricky because in order to escape spaces in path names, you have to quote them, and in order to run quoted text (and not echo it back), you need to prepend it with an ampersand. The ampersand tells PowerShell to treat the text as if it was a command you entered.

So if you wanted to run Internet Explorer from its standard location, this is the line that would do the job:

& 'C:Program FilesInternet Exploreriexplore.exe'

When you run applications from within PowerShell, these are the rules to know:

  • Environment variable $env:path: All folders listed in $env:path are special. Applications stored inside these folders can be launched by name only. You do not need to specify the complete or relative path. That’s the reason why you can simply enter notepad and press ENTER to launch the Windows Editor, or run commands like ping or ipconfig.
  • Escaping Spaces: If the path name contains spaces, the entire path name needs to be quoted. Once you quote a path, though, it becomes a string (text), so when you press ENTER, PowerShell happily echoes the text back to you but won’t start the application. Whenever you quote paths, you need to prepend the string with “&” so PowerShell knows that you want to launch something.
  • Synchronous and asynchronous execution: when you run a console-based application such as ipconfig.exe or netstat.exe, it shares the console with PowerShell so its output is displayed in the PowerShell console. That’s why PowerShell pauses until console-based applications finished. Window-based applications such as notepad.exe or regedit.exe use their own windows for output. Here, PowerShell continues immediately and won’t wait for the application to complete.

Using Start-Process

Whenever you need to launch a new process and want more control, use Start-Process. This cmdlet has a number of benefits over launching applications directly. First of all, it is a bit smarter and knows where a lot of applications are stored. It can for example find iexplore.exe without the need for a path:

PS> Start-Process iexplore.exe

Second, Start-Process supports a number of parameters that allow you to control window size, synchronous or asynchronous execution or even the user context an application is using to run. For example, if you wanted PowerShell to wait for a window-based application so a script could execute applications in a strict order, use -Wait parameter:

PS> Start-Process notepad -Wait

You’ll notice that PowerShell now waits for the Notepad to close again before it accepts new commands.

Start-Process has just one limitation: it cannot return the results of console-based applications back to you. Check this out:

PS> $result = ipconfig

This will store the result of ipconfig in a variable. The same done with Start-Process yields nothing:

PS> $result = Start-Process ipconfig

That’s because Start-Process by default runs every command synchronously, so ipconfig runs in its own new console window which is visible for a split-second if you look carefully. But even if you ask Start-Process to run the command in no new console, results are never returned:

PS> $result = Start-Process ipconfig -NoNewWindow

Instead, they are always output to the console. So if you want to read information from console-based applications, do not use Start-Process.

Stopping Processes

If you must kill a process immediately, use Stop-Process and specify either the process ID, or use the parameter -Name to specify the process name. This would close all instances of the Notepad:

PS> Stop-Process -Name Notepad

Stopping processes this way shouldn’t be done on a regular basis: since the application is immediately terminated, it has no time to save unsaved results (which might result in data loss), and it cannot properly clean up (which might result in orphaned temporary files and inaccurate open DLL counters). Use it only if a process won’t respond otherwise. Use –WhatIf to simulate. Use –Confirm when you want to have each step confirmed.

To close a process nicely, you can close its main window (which is the automation way of closing the application window by a mouse click). Here is a sample that closes all instances of notepad:

PS> Get-Process Notepad -ea 0 | ForEach-Object { $_.CloseMainWindow() }

Managing Services

Services are basically processes, too. They are just executed automatically and in the background and do not necessarily require a user logon. Services provide functionality usually not linked to any individual user.

Cmdlet Description
Get-Service Lists services
New-Service Registers a service
Restart-Service Stops a service and then restarts it. For example, to allow modifications of settings to take effect
Resume-Service Resumes a stopped service
Set-Service Modifies settings of a service
Start-Service Starts a service
Stop-Service Stops a service
Suspend-Service Suspends a service

Table 17.1: Cmdlets for managing services

Examining Services

Use Get-Service to list all services and check their basic status.

PS> Get-Service

You can also check an individual service and find out whether it is running or not:

PS> Get-Service Spooler

Starting, Stopping, Suspending, and Resuming Services

To start, stop, temporarily suspend, or restart a service, use the corresponding cmdlets. You can also use Get-Service to select the services first, and then pipe them to one of the other cmdlets. Just note that you may need local administrator privileges to change service properties.

PS> Stop-Service Spooler

If a service has dependent services, it cannot be stopped unless you also specify -Force.

PS> Stop-Service Spooler -Force

Note that you can use WMI to find out more information about services, and also manage services on remote machines:

PS> Get-WmiObject Win32_Service -ComputerName Storage1 -Credential Administrator

Since WMI includes more information that Get-Service, you could filter for all services set to start automatically that are not running. By examining the service ExitCode property, you’d find services that did initialization tasks and finished ok (exit code is 0) or that crashed (exit code other than 0):

PS> Get-WmiObject Win32_Service -Filter 'StartMode="Auto" and Started=False' |
>> Select-Object DisplayName, ExitCode
>>

DisplayName                                  ExitCode
-----------                                  --------
Microsoft .NET Framework NGEN v4.0.30319_X86        0
Microsoft .NET Framework NGEN v4.0.30319_X64        0
Google Update Service (gupdate)                     0
Net Driver HPZ12                                    0
Pml Driver HPZ12                                    0
Software Protection                                 0
Windows Image Acquisition (WIA)                     0

Reading and Writing Event Logs

Event logs are the central place where applications as well as the operating system log all kinds of information grouped into the categories Information, Warning, and Error. PowerShell can read and write these log files. To find out which log files exist on your machine, use Get-EventLog with the parameter -List:

PS> Get-EventLog -List

To list the content of one of the listed event logs, use -LogName instead. This lists all events from the System event log:

PS> Get-EventLog -LogName System

Dumping all events is not a good idea, though, because this is just too much information. In order to filter the information and focus on what you want to know, take a look at the column headers. If you want to filter by the content of a specific column, look for a parameter that matches the column name.

This line gets you the latest 20 errors from the System event log:

PS> Get-EventLog -LogName System -EntryType Error -Newest 20

And this line gets you all error and warning entries that have the keyword “Time” in its message:

PS> Get-EventLog -LogName System -EntryType Error, Warning -Message *Time* |
>> Select-Object TimeWritten, Message

Writing Entries to the Event Log

To write your own entries to one of the event logs, you first need to register an event source (which acts like your “sender” address). To register an event source, you need local administrator privileges. Make sure you open PowerShell with full administrator rights and use this line to add a new event source called “PowerShellScript” to the Application log:

PS> New-EventLog -LogName Application -Source PowerShellScript

Note that an event source must be unique and may not exist already in any other event log. To remove an event source, use Remove-EventLog with the same parameters as above, but be extremely careful. This cmdlet can wipe out entire event logs.

Once you have registered your event source, you are ready to log things to an event log. Logging (writing) event entries no longer necessarily requires administrative privileges. Since we added the event source to the Application log, anyone can now use it to log events. You could for example use this line inside of your logon scripts to log status information:

PS> Write-EventLog -LogName Application -Source PowerShellScript -EntryType Information `
>> -EventId 123 -Message 'This is my first own event log entry'

You can now use Get-EventLog to read back your entries:

PS> Get-EventLog -LogName Application -Source PowerShellScript

   Index Time          EntryType   Source                 InstanceID Message
   ----- ----          ---------   ------                 ---------- -------
  163833 Nov 14 10:47  Information PowerShellScript              123 This is...

Or you can open the system dialog to view your new event entry that way:

PS> Show-EventLog

And of course you can remove your event source if this was just a test and you want to get rid of it again (but you do need administrator privileges again, just like when you created the event source):

PS> Remove-EventLog -Source PowerShellScript