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 |
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