pixel - Fotolia
How to use PowerShell to troubleshoot Windows desktops
When IT uses remote access to troubleshoot a user's desktop, it prevents the user from working. PowerShell, however, allows IT to fix a problem without disturbing the user.
As an IT professional, it is common for you to use remote connection tools such as TeamViewer to connect to end-user devices and troubleshoot issues. This is a fine way to address problems that stop users from performing necessary and time-sensitive tasks.
A remote connection, however, is invasive to end users and typically forces them to stop working to let you investigate the issue. As a result, if end users encounter issues they can continue to work through, it may be preferable for you to connect to a user's device using a Command-line interface (CLI), such as PowerShell, to troubleshoot an issue.
Using a CLI allows users to continue to work while you troubleshoot. If you know how to use PowerShell, you can troubleshoot a Windows desktop either locally or remotely using native cmdlets.
How to use PowerShell remoting
The most common PowerShell commands are Enter-PSSession and Invoke-Command. Both use Windows Remote Management in the background to connect and run commands or scripts.
For instance, to check if chrome.exe is running on a remote machine, you can run:
PS C:\> Invoke-Command -ComputerName TestMachine -ScriptBlock {Get-Process chrome.exe }
View Windows processes
Oftentimes, when troubleshooting client machines, it is necessary to view and kill Windows processes that are running.
For instance, a user may need to kill outlook.exe because the window is not responding. Those who know how to use PowerShell to do this will enter Stop-Process -Force.
PS C:\> Stop-Process -Name outlook.exe -Force
If you must find processes that a particular user is running, you can filter through the UserName property. In this example, you want to find any process running under Dan:
PS C:\> Get-Process -IncludeUserName | Where-Object {$_.UserName -eq 'Dan'}
Handles |
WS(K) |
CPU(s) |
Id |
UserName |
Process Name |
481 |
79696 |
230.53 |
9728 |
Dan |
Adobe CEF Helper |
384 |
21696 |
.67 |
25888 |
Dan |
Adobe CEF Helper |
64 |
2928 |
.16 |
1672 |
Dan |
CC Library |
64 |
2812 |
.22 |
13992 |
Dan |
CCXProcess |
299 |
76184 |
5.84 |
336 |
Dan |
Chrome |
345 |
113572 |
31.08 |
772 |
Dan |
Chrome |
395 |
162504 |
42.19 |
3508 |
Dan |
Chrome |
333 |
150896 |
58.61 |
3532 |
Dan |
Chrome |
Test network port availability
Imagine a client machine has an issue connecting to a specific web application on port 8080. One easy method to find out if that machine can connect to that port is to use the cmdlet Test-NetConnection. This cmdlet tests the connection against specific ports to see if they are listening on remote endpoints.
PS C:\> Test-NetConnection -ComputerName testserver -Port 8080
WARNING: TCP connect to (172.16.52.11 : 8080) failed
ComputerName: testserver
RemoteAddress: 172.16.52.11
RemotePort: 8080
InterfaceAlias: Ethernet
SourceAddress: 172.16.48.10
PingSucceeded: True
PingReplyDetails (RTT): 0 ms
TcpTestSucceeded: False
The test failed on port 8080 for the hostname testserver. This cmdlet also performs a ping test to see if the Internet Control Message Protocol can reach the port. This helps ensure the machine is accessible on the network.
Work with software installations
When you use the Windows graphical user interface, you can view installed applications with the Add and Remove programs function. In PowerShell, you can do this with the Get-Package command.
To view any software installed containing the name Adobe, run this command on machines running PowerShell Version 5 or above:
PS C:\> Get-Package -name *Adobe*
Name |
Version |
Source |
Provider name |
Adobe CS6 64-bit |
1.2.0 |
C:\Program Files (x86)\Adobe\... |
Msi |
In addition, you can uninstall software with the Uninstall-Package command.
PS C:\> Get-Package -Name 'adobe air' | Uninstall-Package
Name |
Version |
Adobe AIR |
31.0.0.96 |
How to use PowerShell to search events
The Windows event log allows you to see the events logged on a given system. In PowerShell, the Get-WinEvent cmdlet is the best way to do this. Even better, with a CLI, you can search for what you want easier and faster than you would using Windows Event Viewer.
In the following example, you are trying to find any errors in the application log for events in the last hour for Group Policy Services. To do this, you can use a hash table with the logname -- application -- providername -- Group Policy Services -- and the start time. You only want to see the time the event was created and the message in it, so you use the Select-Object cmdlet.
PS C:\> Get-WinEvent -FilterHashtable @{Logname="Application"; ProviderName="Group Policy Services"; StartTime=(Get-Date).AddHours(-2)} | Select-Object -Property ti
mecreated,message | Format-List
TimeCreated : 12/4/2018 2:36:07 PM
Message: The computer 'test' preference item in the test {69F49340-0D18-434D-A112-F82A688D1E42}' Group Policy Object did not apply because it failed with error code '0x80070424. The specified service does not exist as an installed service.' This error was suppressed.
Performance counters
When it comes to troubleshooting performance issues in Windows, counters have long been the method for getting the data you need to fix an issue. If you know how to use PowerShell, you can not only view what counters are available, but you can also start them with the cmdlet Get-Counter.
To view all the possible counters on a local system, run:
PS C:\> Get-Counter -ListSet * | Select-Object Countersetname | Sort-Object -Property Countersetname
One interesting counter is User Input Delay per Process, which provides the number of milliseconds a system takes to respond to a user interacting with an application.
PS C:\> $Counter = Get-Counter -ListSet 'User Input Delay per Process'
PS C:\> $Counter.Counter
\User Input Delay per Process(*)\Max Input Delay
If you run Get-Counter against that count sample, you can see all of the processes running in your local machine.
PS C:\> Get-Counter -Counter '\User Input Delay per Process(*)\Max Input Delay' -MaxSamples 5
Timestamp |
Counter Samples |
12/5/2018 7:37:20 AM |
\\TestMachine\user input delay per process(0:6980 <outlook.exe>)\max input delay: 0 |
|
\\TestMachine\user input delay per process(0:2992 <networklicenseserver.exe>)\max input delay : 0 |
|
\\TestMachine\user input delay per process(0:3992 <svchost.exe>)\max input delay : 0 |
Now you can find the counter sample -- process name -- to use for your counter. In this example, you use outlook.exe and a PowerShell object to make viewing the samples easier:
PS C:\> Get-Counter -Counter '\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay' -MaxSamples 100 | ForEach {
>> $_.CounterSamples | ForEach {
>> [pscustomobject]@{
>> TimeStamp = $_.TimeStamp
>> Path = $_.Path
>> Value = $_.CookedValue
>> }
>> }
>> }
Time Stamp |
Path |
Value |
12/5/2018 7:40:10 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
0 |
12/5/2018 7:40:11 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
0 |
12/5/2018 7:40:12 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
0 |
12/5/2018 7:40:13 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
0 |
12/5/2018 7:40:14 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
0 |
12/5/2018 7:40:15 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
16 |
12/5/2018 7:40:16 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
16 |
12/5/2018 7:40:17 AM |
\\TestMachine\user input delay per process(1:14156 <outlook.exe>)\max input delay |
31 |