Skip to the main content.

ScriptRunner Blog

My Top 10 PowerShell Commands for Troubleshooting Windows Problems

Table of Contents

Post Featured Image

Let me start by giving a bit of background about myself as it will help to give context and legitimacy to this post, I hope. I have a background as a software developer, having written my first code in 1980, but in 1995 I became involved with products from a company called Citrix and I’ve been troubleshooting problems with them, or more precisely, mostly with the applications delivered on top of them, ever since.

This used to be a manual affair which is tedious, boring and error prone so being the inherently lazy person I am, I’ve been trying to simplify, accelerate and automate the troubleshooting where possible and practical, by using PowerShell.

This article shares some of my success in this area and I hope will encourage you to be a more efficient trouble-shooter so that you have more time available for fun things (although to me personally, that is quite often more troubleshooting or PowerShell development)!

Below, I present a list of the PowerShell commands for troubleshooting I find the most useful and use most frequently.

Get-CimInstance

WMI, or CIM (pronounced “See Eye Em”) as the PowerShell cmdlets morphed to in version 3.0, is a great yet simple and generic method to get information about all kinds of things from one or more computers.

For instance, you can get detailed information about processes, services, disks, networks, memory, processors, batteries, etc, etc. In addition, some companies, such as Citrix, add their own WMI providers to give access to information that would otherwise need a proprietary API or executable to retrieve.

For example, this command will get operating system details and installation and last boot times (fig. 1):

Get-CimInstance -ClassName win32_operatingsystem -ComputerName grl-dc03,grl-sql01,grl-sql03 | select PSComputerName,caption,version,installdate,LastBootUpTime | Format-Table -AutoSize
fig1-Screenshot-PowerShell-ISE-Get-CimInstance

Fig. 1: The Get-CimInstance Command delivers as output information about operating systems, which are displayed in table form

A lot of my consultancy engagements include health checking of various components. The way I gather a large amount of information about the desktops and servers I am checking, which I can use when I am not on site or have access to the customer systems, is to use a script I wrote that queries almost fifty CIM classes from a list of computers specified on the command line, or via text file. You can download the script for free from my GitHub repository.

The script writes the results to csv files making it easy to compare results from different machines, e.g. to check consistency and help spot anomalies.

Get-WinEvent

There can be incredibly useful information contained in the Windows event log when troubleshooting issues such as slow logon.

But knowing where to look can be problematic since on recent operating systems there are upwards of 300 different active event logs where crucial information could be hiding – not just in the System or Application events logs like in the old days.

Using PowerShell, we can easily search for specific events

  • via id
  • in a certain time range
  • containing specific text or
  • a combination of the above

which is much easier, quicker and scalable than manually running event viewer and trawling through a myriad of events.

For instance, here is an example of using a hash table argument, also known as a dictionary, to retrieve account lockout events in the last twelve hours from a remote domain controller including the computer the lockout was caused from (figure 2 and 3):

Get-WinEvent -ComputerName grl-dc03 -FilterHashtable @{LogName = 'Security';Id = 4740;StartTime = (Get-Date).AddHours( -12) } -ErrorAction SilentlyContinue | Select TimeCreated,@{n='User';e={$_.Properties[0].value}},@{n='From';e={$_.Properties[1].Value}}

Screenshot of PowerShell ISE: The command described in the text delivers as output a table containing account lockout events in the last twelve hours from a remote domain controller including the computer the lockout was caused from

Fig. 2: The Get-WinEvent Command delivers as output information about account lockout events in the last twelve hours from a remote domain controller, which are displayed in table form

Screenshot of the Windows Event properties

Fig. 3: Screenshot of the Windows Event properties

Note in the command how we use the “Properties” array returned by Get-WinEvent to extract specific fields so that we don’t have to parse the full text of the event log entry (figure 4).

Screenshot of the detailed properties of a Windows event.

Fig 4: The Get-WinEvent Command described in the text selects only the first [0] and second [1] field of the EventData set

Again, there’s a script I use almost daily to retrieve all events from all enabled event logs in a given time period, such as a user logon, to look for clues/reasons for errors or slow performance. You can download it from my GitHub repository.

Enter-PSSession

Consider the scenario where users on a specific computer complain about poor performance but when you try to remote to that machine with mstsc or similar, your logon hangs.

Wouldn’t it be nice to have a low-overhead method of remoting to that device for interactive, or automated, troubleshooting like one can do with telnet or ssh to *nix machines (e.g. using the great free tool PuTTY)?

Entering the PowerShell Command  Enter-PSSession gives a command line interface onto the remote computer, that is if PowerShell remoting is enabled via GPO or manually via “winrm quickconfig” or Enable-PSRemoting -Force.

This allows troubleshooting and remediation such as looking for the highest consumers of CPU or memory via Get-Process (alias ps) and terminating them if that is appropriate via Stop-Process (alias kill).

Test-NetConnection

How do you test if a specific web server is up and running? Ping? No! Ping merely tests if ICMP replies are enabled, and indirectly tests name resolution if not using an IP address – it does not confirm whether there is a process listening on a specific port on the remote machine and firewalls allow the connection.

In pre-PowerShell days I would use telnet.exe for this port testing but now PowerShell provides the Test-NetConnection command (alias tnc) which allows checking of a specific port on a machine (and route tracing too), as shown in figure 5:

Test-NetConnection -ComputerName grl-dc03 -Port 443 -InformationLevel Quiet
Screenshot of PowerShell ISE: The command Test-NetConnection delivers as output information about the internet connection

Fig. 5: Test-NetConnection can be used to query information about a specific port on a machine

In addition, because it returns a PowerShell object or a Boolean, it is easy to incorporate into scripts without having to parse command output from the likes of ping.exe which we used to have to do in the bad old days.

 

Get-ADUser

This is the odd one out in this list because it is not available by default: One has to have the ActiveDirectory PowerShell module installed although that is very simple via the “Add-WindowsFeature RSAT-AD-PowerShell” command (run elevated).

Many vendors have PowerShell modules to allow you to interface and automate their technology – I use ones from VMware and Citrix daily for instance.

Get-ADUser and associated cmdlets, such as Get-ADGroupMember, allow us to check, and change, AD information and is particularly useful for querying large numbers of objects and producing a report (see Export-CSV later).

Here is an example of counting how many accounts have a home drive set to “H:” which we might need if we are performing some maintenance – we could change the home drive just as easily (figure 6):

Get-ADUser -Filter "HomeDrive -eq 'H:'" | Measure-Object
Screenshot of PowerShell ISE: The command descrived in the text delivers as output the number of users whose homedrive equals

Fig. 6: Get-ADUser can be used to easily retrieve information about users in Active Directory

I also find it very useful when on customer systems, and they haven’t given me access to AD Users and Computers, but I need to check properties for a user such as group membership.

 

Get-Process

Frequently we need to check that critical processes are running or investigate processes that we don’t recognize. Whilst Task Manager and SysInternals Process Explorer are useful tools, we can check, and fix, a lot of issues with the Get-Process (alias ps) cmdlet.

Here is an example that shows all processes that are running from folders that have “Citrix” in the name, sorted on ascending start times of that process, which allows us to determine if the process started at boot, user logon, etc. (figure 7):

Get-process | Where Path -match 'Citrix' | Select Name,Id,StartTime,Path | Sort StartTime | Format-Table -AutoSize
Screenshot of PowerShell ISE: The command described in the text delivers as output all processes whose path contains CITRIX

Fig. 7: Get-Process can be used to filter for processes that contain “Citrix” in their name and to display specific information about them

Here is a similar command which looks for “VMware” in the company name in the version resources of the .exe files of all running processes (figure 8 and 9):

Get-Process | Get-itemProperty -EA Silent | Select -ExpandProperty VersionInfo | Where CompanyName -match 'VMware' | Select FileVersion,ProductName,FileName
Screenshot of PowerShell ISE: The command described in the text delivers as output information about all processes whose company name contains VMware

Fig. 8: Get-Process can be used to filter for processes that contain ‘VMware’ in their company name and to display specific information about them

Screenshot of vmtoolsd.exe properties.

Fig. 9: The company name can usually be found in the property details of an .exe file in the entry “Copyright”

 

Get-ChildItem

Chances are that you have actually been using this command without even realizing, especially if you are coming from a command prompt, if you have been using “dir” in a PowerShell prompt, as that is an alias for Get-ChildItem.

As the name suggests, Get-ChildItem gives us information about the child items, and their children and so on if we specify -recurse, of a parent where the parent could be a local or remote file system folder, a registry key, a certificate store, etc (hint: run Get-PSDrive to see what PowerShell drives are available).

Here is an example that shows details in the given folder and children, including any hidden ones which the -force enables, for any file that exceeds 100MB in size, sorted in descending size order.

Get-ChildItem -Force -Recurse -File | Where Length -gt 100MB | Sort Length -Descending | Select fullname, CreationTime, @{n='Size (MB)'; e={[math]::Round($_.Length / 1MB , 2)}}}
Screenshot of PowerShell ISE: Retrieving details in a given folder and children for any file that exceeds 100MB in size, sorted in descending size order.

Fig. 10: Retrieving details in a given folder and children for any file that exceeds 100MB in size, sorted in descending size order with the Get-ChildItem command

 

Get-Help

This one is slightly different to the others I have presented thus far in that it doesn’t directly assist troubleshooting but what it does give us is detailed help such as usage, parameters and examples for cmdlets, covering both built in modules and ones you subsequently install.

This, coupled with Get-Command to see what commands are provided with a specific module or are concerned with networks, drives, etc, allows unfamiliar commands to be used quickly without having to resort to one’s favorite web search engine.

I usually use it with -ShowWindow to show the help in a separate text window and -Online is useful to go to a web page with the latest information which sometimes also has extra information and links to related items.

Remember that you can tab through the available arguments or use ctrl space to show them all and that script authors like myself will add the required comments to our scripts so that Get-Help works with them as well.

 

Out-GridView

This cmdlet in Windows PowerShell allows object data output by PowerShell cmdlets, functions or scripts to be easily presented in an onscreen grid view which is then sortable and filterable without requiring any software, other than PowerShell (and .NET) to be installed.

Selected items can even be returned by it for further use in scripts, e.g. to choose an item from a list, or just sent to the clipboard (via the -passthru argument).

Here is a one-liner I use frequently to get today’s IIS log file into a grid view, so I can look for errors, slow response times, etc. :

Get-Content -Path "C:\inetpub\logs\logfiles\w3svc3\$(Get-Date -Format 'u_exyyMMdd.lo\g')"|Where-Object { $_ -match '^(\d|#Fields)' } | ForEach-Object { $_ -replace '^#Fields: ' } |ConvertFrom-Csv -Delimiter ' '|Where-Object cs-uri-stem -NotMatch 'monitor.aspx$' |Select-Object -Property *,@{name='Duration';expression={([int]$_.'time-taken')}} |Out-GridView
Screenshot of PowerShell ISE: formatting a IIS log in a grid view with Out-GridView

Fig. 11: The Out-GridView command lets you format the data you queried with PowerShell in a clear grid

And figure 12 shows the one line I had selected when I clicked the “OK” button in the grid view which was put into the clipboard by Set-Clipboard (alias scb) so it can be pasted into my troubleshooting/healthcheck notes (what do you mean, you still use pen and paper!).

Screenshot PowerShell ISE: Output of the command mentioned before

Fig. 12: Output of the before mentioned command.

 

Export-CSV

Last but not least, Export-CSV is a built-in cmdlet that allows us to write any PowerShell objects, such as the output from cmdlets previously presented like Get-Process, to a correctly formatted CSV file so that they can be examined, filtered, sorted, etc in Microsoft Excel, Google Sheets or even brought back into PowerShell via Import-CSV for further processing.

\\tsclient\c\temp\allprocesses.$env:COMPUTERNAME.csv

Screenshot: Exporting data retrieved with PowerShell into a .csv file

Fig. 13: Exporting data retrieved with PowerShell into a .csv file

Note the use of -NoTypeInformation which prevents a line of property types being output to the csv which confuses Excel although is easily deleted. You can also use -Append to append new objects to an existing csv file although the columns should match between old and new.

I use Export-Csv a lot for “poor man’s reporting” where PowerShell scripts running via regular scheduled tasks collate data from various sources, produce CSV files and email them to “interested” parties via Send-MailMessage (which requires access to an SMTP mail server).

Lastly, if you are using a Dutch locale, you probably want to use -delimiter ‘;’ since they use semicolons in their Comma Separated Values files – a fact that took me a while to figure out when working for a Dutch based company!

Conclusion

Well that’s all for now folks. Please note: there is no order to this – very arbitrary – list in the same way there wouldn’t be an order to tools in your workman’s toolbox – if you need to undo a screw then you are unlikely to pull a hammer out as your first choice (unless you are Jeremy Clarkson of course).

Happy troubleshooting!

Related links

 

Related posts

3 min read

ScriptRunner now available in the Microsoft Azure Marketplace

6 min read

Managing Microsoft Exchange with PowerShell

2 min read

VMUG Webcast: Mastering VMware Management with PowerCLI

About the author: