Idera nSoftware Compellent

Chapter 17. Processes, Services, Event Logs

In your daily work as an administrator, you often have to deal with programs (processes), services, and innumerable entries in event logs so this is a good opportunity to put into practice the basic knowledge you gained from the first 12 chapters. The examples and topics covered in this chapter are meant to give you an idea of the full range of options.

In the course of your reading, you will no doubt rack your brains occasionally and find yourself flipping back pages to the introductory chapters. What's really astonishing are the many and diverse options you have in using the PowerShell pipeline (as discussed in Chapter 5) and associated formatting cmdlets to wring out every last bit of data from pipeline objects. What was just dry theory in Chapter 5 will now become very interesting in the following.

Topics Covered:

Processes

Processes are basically running programs as most routine tasks can be mastered using the cmdlets Get-Process and Stop-Process. In addition, processes can also be controlled directly by the objects and methods of the .NET framework.

Starting Processes

Starting processes is inherent in the console. You can launch any executable program in a directory named in the PATH environment variable simply by typing its name:

notepad
regedit
explorer .

But note how PowerShell loses control over Windows applications. After applications start, they are left to their own devices since PowerShell can't directly access these processes once they've started. Direct control of a process is only possible if you start the process using the Start() .NET method, which enables you to check whether a process still responds or is terminated. You can also force a process to stop running:

$process = [System.Diagnostics.Process]::Start("notepad")
$process.Responding
True
$process.HasExited
False
$process.Kill()

You can even use WaitForExit() to get PowerShell to wait until the process exits, which comes in handy inside PowerShell scripts when you want to make sure that a process has completed its task before you go on to the next step:

$process = [System.Diagnostics.Process]::Start("notepad")
$process.WaitForExit()

Monitoring Processes

Get-Process retrieves all running processes. What applies here applies in general to PowerShell: the cmdlet retrieves Process objects as result, not text. Text will appear only if you output the result of Get-Process to the console:

# Output all processes beginning with "P":
Get-Process p*
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
377 8 21224 13344 167 1,84 7144 powershell
184 7 10328 9528 85 2,28 5652 PSDrt

Each Process object contains more information than is displayed in the console. To view all properties, send the result to a formatting cmdlet like Format-List and append with an asterisk:

Get-Process powershell | Format-List *
__NounName : Process
Name : powershell
Handles : 377
VM : 175292416
WS : 13664256
PM : 21733376
NPM : 8268
Path : C:\WINDOWS\system32\WindowsPowerShell\
v1.0\powershell.exe
Company : Microsoft Corporation
CPU : 1,8408118
FileVersion : 6.0.6000.16386 (winmain(wmbla).070112-1312)
ProductVersion : 6.0.6000.16386
Description : PowerShell.EXE
Product : Microsoft® Windows® PowerShell
Id : 7144
PriorityClass : Normal
HandleCount : 377
WorkingSet : 13664256
PagedMemorySize : 21733376
PrivateMemorySize : 21733376
VirtualMemorySize : 175292416
TotalProcessorTime : 00:00:01.8408118
BasePriority : 8
ExitCode :
HasExited : False
ExitTime :
Handle : 1648
MachineName : .
MainWindowHandle : 1774772
MainWindowTitle : Windows PowerShell
MainModule : System.Diagnostics.ProcessModule
(powershell.exe)
MaxWorkingSet : 1413120
MinWorkingSet : 204800
Modules : {powershell.exe, ntdll.dll, kernel32.dll,
ADVAPI32.dll...}
NonpagedSystemMemorySize : 8268
NonpagedSystemMemorySize64 : 8268
PagedMemorySize64 : 21733376
PagedSystemMemorySize : 137688
PagedSystemMemorySize64 : 137688
PeakPagedMemorySize : 43565056
PeakPagedMemorySize64 : 43565056
PeakWorkingSet : 32870400
PeakWorkingSet64 : 32870400
PeakVirtualMemorySize : 195878912
PeakVirtualMemorySize64 : 195878912
PriorityBoostEnabled : True
PrivateMemorySize64 : 21733376
PrivilegedProcessorTime : 00:00:00.5928038
ProcessName : powershell
ProcessorAffinity : 3
Responding : True
SessionId : 1
StartInfo : System.Diagnostics.ProcessStartInfo
StartTime : 16.10.2007 13:32:55
SynchronizingObject :
Threads : {6584, 6816, 7032, 6412}
UserProcessorTime : 00:00:01.2480080
VirtualMemorySize64 : 175292416
EnableRaisingEvents : False
StandardInput :
StandardOutput :
StandardError :
WorkingSet64 : 13664256
Site :
Container :

Filtering and Clearly Displaying Processes

As described in Chapter 5, you can use pipeline filters to work on lists of processes. If you were only interested in processes that have been running for less than three hours, you could find them like this:

Get-Process | Where-Object { $_.StartTime -gt `
(Get-Date).AddMinutes(-180) } | Format-Table
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
671 75 50944 41392 316 13,96 4408 devenv
571 29 60180 40824 213 71,09 8076 iexplore
51 3 1248 5468 56 0,19 5932 notepad
411 17 69892 54936 291 27,42 7224 PowerShellPlus.vshost
110 3 3072 5320 54 0,06 1508 SearchFilterHost
303 6 5136 8668 69 0,09 7096 SearchProtocolHost
844 35 50480 107004 381 141,02 6460 WINWORD

If you want start times displayed, append the property you seek to Format-Table. As shown in Chapter 5, the next statement adds a new Minutes column that calculates the elapsed time in minutes since a program began running:

Get-Process | Where-Object { $_.StartTime -gt (Get-Date).AddMinutes(-180) } |
Format-Table Name, Id, StartTime, @{expression={ [int](New-TimeSpan `
$_.StartTime (get-date) ).TotalMinutes }; label="Minutes" } -autosize
Name Id StartTime Minutes
---- -- --------- -------
devenv 4408 10.16.2007 16:06:42 129
iexplore 8076 10.16.2007 16:15:48 119
notepad 5932 10.16.2007 17:35:16 40
PowerShellPlus.vshost 7224 10.16.2007 16:32:26 103
SearchFilterHost 4584 10.16.2007 18:14:21 1
SearchProtocolHost 7884 10.16.2007 18:14:21 1
taskeng 2864 10.16.2007 18:11:55 3
WINWORD 6460 10.16.2007 17:29:01 46

Use the option described in Chapter 5: with Format-Table or Format-List to output calculated columns. This allows you to select from current properties of a Process object, as well as properties of child objects, and you can also obtain or calculate entirely new data.

In the following example, Get-Process returns for each process not only its name but also the directory from which the process was started, as well as a description of the process. The start directory is a property of a child object in MainModule. The static .NET method GetVersionInfo() will obtain a description of the process if it is given the path of the process. That can be found in the Path property:

Get-Process | Format-Table Name, @{ex={ $_.MainModule.FileName };
la="StartDirectory"}, @{ex={([system.diagnostics.fileversioninfo]::`
GetVersionInfo($_.Path)).FileDescription}; la="Description"} -wrap
Name StartDirectory Description
---- ----------- ------------
agrsmsvc C:\Windows\system32\ Agere Soft Modem Call
agrsmsvc.exe Progress Service
AppSvc32 C:\Program Files\Common Symantec Application
Files\Symantec Shared\App Core Service
Core\AppSvc32.exe
Ati2evxx C:\Windows\system32\ ATI External Event
Ati2evxx.exe Utility EXE Module
ATSwpNav C:\Program Files\Finger ATSwpNav Application
print Sensor\ATSwpNav
.exe
BatteryMiser5 C:\Program Files\LG Battery Miser
Software\Battery Miser\
BatteryMiser5.exe
ccApp C:\Program Files\Common Symantec User Session
Files\Symantec Shared\
ccApp.exe
(...)

Counting Processes

Processes can be counted rather easily because the result of Get-Process is (nearly) always an array, which comes with the Count property. Get-Process won't necessarily return the result as an array; only if the result is a single process or no process at all. That's why you should always first convert the result into an array before you determine the number of array elements:

# Determine the number of notepads:
@(Get-Process notepad).Count
1

Another sort of "measurement" is carried out by Measure-Object. It makes a statistical evaluation of a particular object property. For example, if you wanted to know what the minimum, maximum, and average values of the PagedSystemMemorySize property are, proceed as follows:

Get-Process | Measure-Object -Average -Maximum `
-Minimum -Property PagedSystemMemorySize
Count : 112
Average : 86227,2857142857
Sum :
Maximum : 369472
Minimum : 0
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:

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

Stopping Processes

You can use Stop-Process to stop running processes, but that can be risky because PowerShell makes it so very easy to do. The following statement closes all opened Notepads and does so without asking for confirmation—even when the Notepads contain unsaved text:

Stop-Process -name Notepad

However, a small safety measure is integrated that forces you to specify the -name parameter. The standard parameter that you can use even without a parameter name is for Stop-Process the process ID.

Use the -whatif option for Stop-Process to check in advance what the command would do. Use -confirm when you want to have each step confirmed to avoid risks.

Services

Services are special programs, which are executed unsupervised and require no interactive logon session. Services provide functions usually not linked to any individual user. You should use the following PowerShell cmdlets to manage services:

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

Listing Services

Get-Service works like Get-Process and Get-ChildItem: it returns service objects that meet your criterion. All services will be listed if you don't specify any criterion. Use Where-Object in the pipeline if you want to filter the result:

# List all services beginning with "A":
Get-Service a*


# Only running services beginning with "A":
Get-Service a* | Where-Object { $_.status -eq 'Running' }
Status Name DisplayName
------ ---- -----------
Running AeLookupSvc Application Experience Lookup
Running AgereModemAudio Agere Modem Call Progress Audio
Running Appinfo Application information
Running Ati External Ev... Ati External Event Utility
Running AudioEndpointBu... Windows Audio Endpoint Builder
Running Audiosrv Windows Audio

Starting, Stopping, Suspending, Resuming Services

To start, stop, temporarily suspend, or restart a service, all you have to do is to clearly identify the service. Get-Service will retrieve the service for you, which you can then pass on to one of the other cmdlets listed in Table 17.1.

Most services perform important tasks. Be cautious when you stop or start services. Pick out a harmless service, and if you're not sure whether a service is harmless, it's wiser not to experiment.

For example, the following statement stops the service called Parental Controls on Windows Vista. Of course, this will only work if you have administrator rights (and the service has to be running as well):

Get-Service | Where-Object { $_.DisplayName -eq `
'Parental Controls' } | Stop-Service
Stop-Service : Service "Parental Controls (WPCSvc)"
cannot be stopped due to the following error: Cannot
stop WPCSvc service on computer '.'.
At line:1 char:79
+ Get-Service | Where-Object { $_.DisplayName -eq
'Parental Controls' } | Stop-Service <<<<

Use the DisplayName property if you want to identify a service by its language-localized name. Be absolutely sure that the service name is enclosed in single and not double quotation marks, because some service names include the "$" character. If the character is in text wrapped in double quotation marks, PowerShell will automatically recognize it as identifying a variable and remove it. Start it if you want to track the consequences of your Windows services snap-in modifications:

services.msc

But don't forget to refresh your display because it lags behind and will not display your current changes.

Figure 17.1: Use the services snap-in to check your modifications

Event Log

Windows makes records of all malfunctions, warnings, and other information in its event logs. You can use the Get-Eventlog cmdlet to access log entries. That's a prudent thing to do because event logs are jam-packed with information, and PowerShell is absolutely the right tool to extract the important information they contain.

Use the -list parameter to find out what event logs are on your system. The Entries column should already give you a rough idea of how much information is being collected in some of your event logs:

Get-EventLog -List
Max(K) Retain OverflowAction Entries Name
------ ------ -------------- ------- ----
512 7 OverwriteOlder 659 ACEEventLog
20,480 0 OverwriteAsNeeded 21,032 Application
15,168 0 OverwriteAsNeeded 0 DFS Replication
20,480 0 OverwriteAsNeeded 0 Microsoft-Windows-
Forwarding/Operational
512 7 OverwriteOlder 0 Internet Explorer
512 7 OverwriteOlder 0 Key Management Service
8,192 0 OverwriteAsNeeded 0 Media Center
16,384 0 OverwriteAsNeeded 8 Microsoft Office
Diagnostics
16,384 0 OverwriteAsNeeded 524 Microsoft Office
Sessions
20,480 0 OverwriteAsNeeded 61,829 System
15,360 0 OverwriteAsNeeded 18,465 Windows PowerShell

If you wanted to get a display of all the entries in the System log, you would no doubt agree that there's just too much information to be helpful:

Get-EventLog System
Index Time Type Source EventID Message
----- ---- ---- ------ ------- -------
...81 Oct 16 19:02 Info Service ... 7036 The description for...
...80 Oct 16 18:59 Info Service ... 7036 The description for...
...79 Oct 16 18:59 Info Tcpip 4201 Network adapter "wi...
...78 Oct 16 18:59 Info Tcpip 4201 Network adapter "wi...
...77 Oct 16 18:59 Info Dhcp 1103 Network address was...
...76 Oct 16 18:59 Info BROWSER 8033 Search service has ...
...75 Oct 16 18:45 Info Service ... 7036 The description for...
...74 Oct 16 18:29 Info Service ... 7036 The description for...
...73 Oct 16 18:29 Info Tcpip 4201 Network adapter "wi...

That's why you should use the PowerShell filters. Use Where-Object to pass the information retrieved by Get-Eventlog through the pipeline while allowing only those entries through that meet your criteria. The next statement reads only those events from the PowerShell event log that match the type, "Information", and have today's date. To do so, PowerShell compares the contents of the TimeWrittenproperty with today's date. Since only the date, and not the time, are supposed to be compared, PowerShell compares the result of Date(), a method of the DateTime type that sets the time to zero.

Get-Eventlog "Windows PowerShell" |
Where-Object {$_.EntryType -eq "Information"} |
Where-Object {($_.TimeWritten).Date -eq (Get-Date).Date}
Index Time Type Source EventID Message
----- ---- ---- ------ ------- -------
60339 Oct 16 16:32 Info PowerShell 400 Engine state is cha...
60338 Oct 16 16:32 Info PowerShell 600 Provider "Certifica...
60337 Oct 16 16:32 Info PowerShell 600 Provider "Variable"...
60336 Oct 16 16:32 Info PowerShell 600 Provider "Registry"...
60335 Oct 16 16:32 Info PowerShell 600 Provider "Function"...
60334 Oct 16 16:32 Info PowerShell 600 Provider "FileSyste...
60333 Oct 16 16:32 Info PowerShell 600 Provider "Environme...
60332 Oct 16 16:32 Info PowerShell 600 Provider "Alias" is...
60331 Oct 16 16:27 Info PowerShell 400 Engine state is cha...
60330 Oct 16 16:27 Info PowerShell 600 Provider "Certifica...
60329 Oct 16 16:27 Info PowerShell 600 Provider "Variable"...
(...)

Access to the event logs is easy, but it's a more difficult matter to find your way around the information in the logs and to create the right filters to extract the right information. However, once you have mastered that, you can process information in Excel by using Export-Csv:

Get-Eventlog "System" |
Where-Object {$_.EntryType -eq "Warning"} |
Where-Object {($_.TimeWritten).Date -eq (Get-Date).Date} |
Select-Object EventID, Message |
Export-Csv report2.csv

.\report2.csv

Figure 17.2: Picking out PowerShell events and exporting them to Excel

For PowerShell, filtering event logs takes place mostly on the client side, so access is slow and ineffective. In the case of huge event logs, all their results have to pass through the PowerShell pipeline. The Windows Management Instrumentation (WMI) service, which you will use in another chapter, is better at managing event logs since it filters events on the server side.

Writing Entries to the Event Log

PowerShell officially supports only the reading of events. However, since you can always resort to the methods of the .NET framework, making your own entries is no problem:

[Diagnostics.EventLog]::WriteEntry("Application","PS Script started","Warning")

The Event Viewer shows you that it was successful:

eventvwr.msc

Figure 17.3: Events you make may look a little strange

What happened here is that the event you made was properly written, but because you aren't known as an event log source, the event display is hard to understand.


Posted Apr 10 2009, 08:00 AM by ps1

Comments

Chapter 17. Processes, Services, Event Logs - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com wrote Chapter 17. Processes, Services, Event Logs - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com
on 04-10-2009 5:45 PM

Pingback from  Chapter 17. Processes, Services, Event Logs - Master-PowerShell | With Dr. Tobias Weltner - PowerShell.com

Copyright 2010 PowerShell.com. All rights reserved.