Practical PowerShell Command Recipes — Growing the Small Tools You Use Every Day

· · PowerShell, Windows, Command Line, Automation, Business Efficiency, Legacy Asset Reuse

1. What to Grasp First

Once you have learned the basics of PowerShell, the next step is to grow your set of “small, frequently used tools” — that is what makes it practical in real work.

By small tools, we do not mean short aliases. In this article, instead of abbreviations like ls and cat, we use the full command names such as Get-ChildItem, Get-Content, and Select-String.

On that basis, we will make the following kinds of work doable in one line or a few lines:

Count items
Check total size
Remove duplicates
Aggregate by category
Extract only the values you need
Compare two sets of results
See the lines around a log hit
Send results to the clipboard
Save the output while also showing it on screen
Check environment variables and the network

PowerShell is useful even without writing long scripts. Start by growing your set of “frequently used building blocks” so you can gradually combine them in everyday work.

Rather than memorizing commands, what matters is being able to recall “in this situation, that building block applies.”

The code in this article is published on GitHub as a runnable sample set organized theme by theme following the chapter structure (recipe scripts and Pester tests).

powershell-practical-command-recipes - komurasoft-blog-samples (GitHub)

2. The Approach This Time

The premises are these three:

  1. Write commands with their full names
  2. Center the work on read-only commands
  3. Always pair change commands with target verification and -WhatIf

For example, rather than learning the file deletion command straight away, it is safer to first internalize this flow:

Look at the targets
  -> filter by condition
  -> count them
  -> save to CSV if needed
  -> confirm the planned changes
  -> execute

This article focuses on investigation, aggregation, comparison, and output rather than strong operations like deletion and stopping.

3. A Map of the Frequently Used Commands

The main commands we will use this time.

What you want to do Command
Check counts and totals Measure-Object
Clean up duplicates Sort-Object -Unique
Aggregate by category Group-Object
Output only the columns you need Select-Object
Process each element ForEach-Object
Search strings Select-String
Compare two sets of results Compare-Object
Compute hash values Get-FileHash
Use the clipboard Set-Clipboard / Get-Clipboard
Output to both screen and file Tee-Object
Measure processing time Measure-Command
See error details Get-Error
Check network reachability Test-Connection / Test-NetConnection

There is no need to learn all of them at once. We recommend learning them paired with a goal: “to count, Measure-Object,” “to group, Group-Object,” “to compare, Compare-Object.”

4. Counting — Measure-Object

The first frequent operation is counting.

Count the files in the current folder.

Get-ChildItem . -File | Measure-Object

To include subfolders:

Get-ChildItem . -File -Recurse | Measure-Object

The Count in the Measure-Object result is the number of items.

To see the total file size, aggregate Length.

Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

As is, however, this is in bytes and a bit hard for humans to read, so convert it to GB.

$size = Get-ChildItem . -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

This is handy when you want a rough view of the total size of a folder.

5. Checking Maximum and Average Too

Measure-Object can produce not just sums but also maximums and averages.

Get-ChildItem . -File |
  Measure-Object -Property Length -Sum -Average -Maximum -Minimum

This is useful for seeing the spread of file sizes.

You can also sum the cumulative CPU time of processes. The CPU from Get-Process is not a utilization percentage but the number of seconds of CPU time used since the process started.

Get-Process |
  Measure-Object -Property CPU -Sum

Note, however, that this value is cumulative rather than an instantaneous CPU utilization, so it varies with the timing of the run and how long the processes have been up.

It is sufficient for investigative purposes, but for rigorous monitoring you also need dedicated monitoring tools and log design.

6. Extracting Just the Values — Select-Object -ExpandProperty

Select-Object is commonly used to choose columns.

Get-Process |
  Select-Object Name, Id, CPU

This outputs “objects with the columns Name, Id, and CPU.”

When you want just the values, on the other hand, use -ExpandProperty.

Get-Process -Name notepad -ErrorAction SilentlyContinue |
  Select-Object -ExpandProperty Id

The same applies when extracting just file names.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name

When you want to pass a command’s results to another command or a text file, -ExpandProperty is convenient.

For example, save just the list of file names.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\file-names.txt -Encoding UTF8

Select-Object Name and Select-Object -ExpandProperty Name look similar, but the shape of the result differs.

Select-Object Name
  -> a table with a Name column

Select-Object -ExpandProperty Name
  -> the Name values themselves

If you want CSV output, keeping it as a column is better; if you want to feed it into further string processing, the bare values are easier to handle.

7. Removing Duplicates — Sort-Object -Unique

Say you want a list of just the file extensions.

Get-ChildItem . -File |
  Select-Object -ExpandProperty Extension |
  Sort-Object -Unique

Running this shows only the deduplicated extensions, such as .txt, .log, and .csv.

You can also see just the distinct process names.

Get-Process |
  Select-Object -ExpandProperty ProcessName |
  Sort-Object -Unique

An example of extracting just the list of department names from a user list CSV:

Import-Csv .\users.csv |
  Select-Object -ExpandProperty Department |
  Sort-Object -Unique

When “the list is cluttered with lots of identical values,” remembering Sort-Object -Unique first is handy.

8. Aggregating by Category — Group-Object

When you want not just deduplication but “how many of each,” use Group-Object.

Count files per extension.

Get-ChildItem . -File |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

Adding -NoElement omits the contents of each group, making the counts easier to read.

Count by service status.

Get-Service |
  Group-Object -Property Status -NoElement

Count by event log level.

Get-WinEvent -LogName System -MaxEvents 500 |
  Group-Object -Property LevelDisplayName -NoElement

Group-Object is well suited to grasping the big picture at the start of an investigation.

Which extensions are most common
Which service statuses are most common
Which error levels are most common
Which department has the most data

Use it when you want to see the distribution before drilling into details.

9. Creating the Columns You Need — Adding Computed Columns

File size is available via Length, but the unit is bytes. Looking at byte counts every time is painful, so it is convenient to create columns converted to MB or KB.

Get-ChildItem . -File |
  Select-Object Name, @{Name="SizeKB"; Expression={ [math]::Round($_.Length / 1KB, 1) }}, LastWriteTime

An example that includes subfolders and lists the largest files first:

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}, LastWriteTime

@{Name="..."; Expression={ ... }} is the syntax for creating a computed column. It looks a little long at first, but it is used constantly in real work.

For example, you can display process memory usage in MB.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

For reports, a column like SizeMB is far more readable than the raw Length.

10. Viewing Newest, Oldest, and Largest First

In PowerShell, sorting is done with Sort-Object.

See the most recently modified files.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime -Descending |
  Select-Object -First 10 Name, LastWriteTime

See the oldest files.

Get-ChildItem . -File |
  Sort-Object -Property LastWriteTime |
  Select-Object -First 10 Name, LastWriteTime

See the largest files.

Get-ChildItem . -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 10 FullName, Length

These three come up all the time.

Newest first -> LastWriteTime -Descending
Oldest first -> LastWriteTime
Largest first -> Length -Descending

They are frequent companions in log investigation, cleaning out unneeded files, and disk space investigation.

11. Use the Format Commands Only at the End, for Display

To make things easier to read on screen, use Format-Table and Format-List.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Format-Table -AutoSize

For viewing the details of a single item, Format-List is handy.

Get-Process -Id $PID |
  Format-List *

But Format-Table and Format-List are “for display.”

It is safer not to use them before outputting to CSV or before processing with subsequent commands.

# Avoid
Get-Process |
  Format-Table Name, Id |
  Export-Csv .\process.csv -NoTypeInformation

For CSV output, choose the columns with Select-Object.

# Correct
Get-Process |
  Select-Object Name, Id |
  Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8

When in doubt, think of it like this:

Only viewing on screen -> Format-Table / Format-List
Using it later         -> Select-Object

12. Making Log Searches a Bit More Convenient — Select-String

For string searching, use Select-String.

Select-String -Path .\logs\*.log -Pattern "ERROR"

Multiple patterns can be specified.

Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN", "FATAL"

To see the surrounding lines, use -Context.

Select-String -Path .\logs\*.log -Pattern "ERROR" -Context 2

This also displays the two lines before and after each matching line, which is helpful when you want to see the context around an error.

To search for a literal string, use -SimpleMatch.

Select-String -Path .\logs\*.log -Pattern "[ERROR]" -SimpleMatch

The -Pattern of Select-String is normally treated as a regular expression. When you want to search for symbols like [ or . literally, adding -SimpleMatch keeps things clear.

For case-sensitive searching:

Select-String -Path .\logs\*.log -Pattern "Error" -CaseSensitive

Search results can also be kept in a CSV.

Select-String -Path .\logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

13. Replacing Strings

To replace part of a string, use -replace.

"server01.example.com" -replace "\.example\.com$", ""

When replacing the contents of a file, it is safer not to overwrite the original right away. Output to a separate file first.

(Get-Content .\appsettings.json -Raw) -replace "localhost", "db01" |
  Set-Content .\appsettings.preview.json -Encoding UTF8

Review it, and apply it to the original file only if needed.

With configuration files and bulk replacements, too many matches lead to accidents. It is safer to check the targets with Select-String first and then replace.

Select-String -Path .\appsettings.json -Pattern "localhost" -SimpleMatch

14. Comparing Two Sets of Results — Compare-Object

Compare-Object is the command for seeing the differences between two lists.

For example, compare file name listings before and after a change.

Compare-Object `
  -ReferenceObject (Get-Content .\before.txt) `
  -DifferenceObject (Get-Content .\after.txt)

The meanings of SideIndicator are as follows.

Shown Meaning
<= Exists only on the left side, i.e., in ReferenceObject
=> Exists only on the right side, i.e., in DifferenceObject
== Exists in both. Shown when -IncludeEqual is specified

An example of saving and comparing the file name listings of folders:

Get-ChildItem .\before -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before-list.txt -Encoding UTF8

Get-ChildItem .\after -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after-list.txt -Encoding UTF8

Compare-Object `
  -ReferenceObject (Get-Content .\before-list.txt) `
  -DifferenceObject (Get-Content .\after-list.txt)

You can also look at changes in the service list.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-before.csv -NoTypeInformation -Encoding UTF8

After the change, export again.

Get-Service |
  Select-Object Name, Status |
  Export-Csv .\services-after.csv -NoTypeInformation -Encoding UTF8

Compare.

Compare-Object `
  -ReferenceObject (Import-Csv .\services-before.csv) `
  -DifferenceObject (Import-Csv .\services-after.csv) `
  -Property Name, Status

Keeping before/after diffs of your work makes investigation and reporting easier.

15. Checking File Hashes — Get-FileHash

When you want to confirm that a downloaded file or a distributed file is identical, use hash values.

Get-FileHash .\installer.exe -Algorithm SHA256

To check all files in a folder at once:

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 }

These can also be kept in a CSV.

Get-ChildItem .\downloads -File |
  ForEach-Object { Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256 } |
  Select-Object Path, Hash |
  Export-Csv .\hashes.csv -NoTypeInformation -Encoding UTF8

Files that look identical by name alone can differ in content. For distributed artifacts, backups, and migrations, keeping hash values makes verification much easier.

16. Sending to the Clipboard — Set-Clipboard

When you want to paste command results into email or chat, sending them to the clipboard is convenient.

Get-Service |
  Select-Object Name, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

To view the contents of the clipboard:

Get-Clipboard

To make it tab-delimited for pasting into Excel, set the delimiter of ConvertTo-Csv to a tab.

Get-Process |
  Select-Object Name, Id, CPU |
  ConvertTo-Csv -NoTypeInformation -Delimiter "`t" |
  Set-Clipboard

If you just want to share results temporarily, this is easier than creating a file each time. But if you want to keep it as an audit trail, save it to a file with Export-Csv.

17. Showing on Screen While Saving to a File — Tee-Object

When you want to view results on screen while also saving them to a file, use Tee-Object.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Tee-Object -FilePath .\top-process.txt

Tee-Object sends the pipeline results in two directions.

Show on screen
Save to a file as well

It suits “watch while recording” during an investigation. If you want to open the data in Excel later, however, Export-Csv is easier to work with.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, WorkingSet |
  Export-Csv .\top-process.csv -NoTypeInformation -Encoding UTF8

Think of it as Tee-Object for the screen and Export-Csv for keeping tabular data, and it stays clear.

18. Keeping a Work Log — Start-Transcript

To record a sequence of operations, use Start-Transcript.

Start-Transcript -Path .\work-log.txt

The commands you run after this, and the screen output, are recorded.

End it.

Stop-Transcript

In investigative work, you will later want to check things like:

Which commands were run
Which folder the work happened in
What the results were
Whether errors occurred

Using Start-Transcript acts as insurance for the times you forget to take working notes. Be careful, however, when the work puts information on screen that must not be recorded, such as passwords or tokens.

19. Reading a CSV and Viewing by Condition

CSV comes up constantly in business data.

For example, suppose you have the following users.csv.

Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true

Read it.

Import-Csv .\users.csv

See only the people whose department is Sales.

Import-Csv .\users.csv |
  Where-Object { $_.Department -eq "Sales" }

Output only the enabled users to a separate CSV.

Import-Csv .\users.csv |
  Where-Object { $_.Enabled -eq "true" } |
  Export-Csv .\enabled-users.csv -NoTypeInformation -Encoding UTF8

CSV values are usually treated as strings, so when comparing true / false or numbers, consider type conversion as needed.

For example, to see only rows with a score of 80 or higher:

Import-Csv .\scores.csv |
  Where-Object { [int]$_.Score -ge 80 }

20. Viewing JSON Configuration Values

JSON is commonly used in configuration files and Web APIs.

$config = Get-Content .\settings.json -Raw | ConvertFrom-Json
$config

You can also look at just a specific value.

$config.Database.Host

An example of changing a value and saving to a separate file:

$config.Database.Host = "db01"
$config |
  ConvertTo-Json -Depth 10 |
  Set-Content .\settings.updated.json -Encoding UTF8

When working with JSON, Get-Content -Raw is the common choice. With -Raw, the whole file is read as a single string, which is clearer when handling multi-line JSON.

21. Viewing Environment Variables

Environment variables come up often for application settings and path checks.

View the list.

Get-ChildItem Env:

View the current user name.

$env:USERNAME

View the temp folder.

$env:TEMP

Split PATH for readability.

$env:PATH -split ";"

Set an environment variable for the current PowerShell session only.

$env:APP_MODE = "Development"

This setting is effective only inside the PowerShell session currently open.

To persist it as a user environment variable, do this:

[Environment]::SetEnvironmentVariable("APP_MODE", "Development", "User")

This is an operation that changes the environment, so on corporate PCs and production servers, confirm the scope of impact before doing it.

22. Checking Your Profile

PowerShell has a profile that is loaded at startup.

Check its location.

$PROFILE

Check whether it exists.

Test-Path $PROFILE

To create it:

New-Item -ItemType File -Path $PROFILE -Force

Open it in Notepad.

notepad $PROFILE

Putting frequently used settings and functions in your profile is convenient. However, writing too much complex processing there slows PowerShell startup and makes things hard to reproduce in other environments, so at first we recommend limiting it to frequently used paths and display settings.

23. Viewing Processes

In process investigation, the first move is usually to look at the largest memory consumers.

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

Filter by a specific name.

Get-Process -Name notepad -ErrorAction SilentlyContinue

When stopping a process, do not run it straight away — confirm with -WhatIf.

Stop-Process -Name notepad -WhatIf

If everything looks right, execute.

Stop-Process -Name notepad

In production environments, stopping a process can affect business operations. Before stopping, confirm the target, the users, and the recovery method.

24. Viewing Services

View the service list.

Get-Service

To see only stopped services:

Get-Service |
  Where-Object { $_.Status -eq "Stopped" }

Find services that are set to automatic start but are not running.

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

When restarting a service, confirm the target first as well.

Get-Service -Name "Spooler"

Rehearse.

Restart-Service -Name "Spooler" -WhatIf

Service operations have a large impact, so confirm the maintenance window and recovery procedure before executing.

25. Viewing Event Logs

In Windows investigation, looking at event logs comes up frequently.

View the most recent 100 entries in the System log.

Get-WinEvent -LogName System -MaxEvents 100 |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

Narrow to just errors and warnings.

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message

See only the errors from the last 24 hours.

$start = (Get-Date).AddHours(-24)

Get-WinEvent -FilterHashtable @{ LogName = "System"; StartTime = $start } |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message

To keep investigation results in a CSV:

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -in @("Error", "Warning") } |
  Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message |
  Export-Csv .\system-events.csv -NoTypeInformation -Encoding UTF8

Event logs easily grow large, so it is important to narrow the range with -MaxEvents or a time window.

26. Checking the Network

For reachability checks, use Test-Connection.

Test-Connection example.com -Count 4

To check TCP port reachability on Windows, Test-NetConnection is convenient.

Test-NetConnection example.com -Port 443

To check DNS resolution:

Resolve-DnsName example.com

In network investigation, isolate the problem like this:

Can the name be resolved
Can the IP be reached
Is the target port open
Is there interference from a proxy or firewall

Rather than judging everything with PowerShell alone, it works well as the entry point of the isolation process.

27. Looking at Web Results

For fetching web pages, use Invoke-WebRequest.

Invoke-WebRequest https://example.com |
  Select-Object StatusCode, StatusDescription

For handling JSON API results, Invoke-RestMethod is convenient.

Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell |
  Select-Object full_name, stargazers_count, forks_count

API results can usually be handled as PowerShell objects from the start, which makes them easy to combine with Select-Object and Where-Object.

When investigating internal APIs too, start with read-only GET requests.

When handling credentials or tokens, be careful about screen display and what gets recorded in the transcript.

28. Measuring Execution Time — Measure-Command

When you want to know how long processing takes, use Measure-Command.

Measure-Command {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

The result includes TotalSeconds and TotalMilliseconds.

$result = Measure-Command {
  Get-ChildItem . -File -Recurse | Measure-Object
}

$result.TotalSeconds

When you want to speed up a script, measuring time rather than going by feel is important. However, results vary with file counts, disk state, and network state, so do not judge from a single run — check several times.

29. Running Slow Work in the Background — Start-Job

To run a time-consuming investigation as a separate job, use Start-Job.

$job = Start-Job -ScriptBlock {
  Get-ChildItem C:\Windows -File -Recurse -ErrorAction SilentlyContinue |
    Measure-Object
}

View the job status.

Get-Job

Receive the results.

Receive-Job $job

Remove jobs that are no longer needed.

Remove-Job $job

Start-Job is convenient, but there is no need to use it heavily from the start. Run things normally first, and turn only the slow processing into jobs — that keeps things clear.

30. Using Command History

To see previously executed commands, use Get-History.

Get-History

Make just the command lines easy to read.

Get-History |
  Select-Object Id, CommandLine

Re-run a specific history entry.

Invoke-History 12

History is convenient, but it can also re-run dangerous commands. When re-running change commands like Remove-Item or Stop-Process from history, check the content before executing.

31. Viewing Error Details — Get-Error

In PowerShell 7, Get-Error is available for looking at recent errors in detail.

Get-Error

To see only the most recent error message:

$Error[0].Exception.Message

When an error occurs, don’t just look at the red text on screen — check the following:

Which command failed
Which path or target it failed on
Whether it is a permissions problem
Whether the file does not exist
Whether it is a network or lock problem

To keep investigation results, combine with Start-Transcript and Export-Csv.

32. Frequently Used Comparison Operators

Comparison operators come up constantly with Where-Object.

Operator Meaning Example
-eq Equal $_.Status -eq "Running"
-ne Not equal $_.Status -ne "Running"
-gt Greater than $_.Length -gt 10MB
-ge Greater than or equal $_.Length -ge 10MB
-lt Less than $_.Length -lt 10MB
-le Less than or equal $_.Length -le 10MB
-like Wildcard match $_.Name -like "*.log"
-match Regular expression match $_.Name -match "^app"
-in The value is in a list $_.Status -in @("Running", "Paused")
-contains The list contains the value @("a", "b") -contains "a"

Examples:

Get-ChildItem . -File |
  Where-Object { $_.Length -gt 10MB }
Get-Service |
  Where-Object { $_.Status -in @("Running", "Paused") }
Get-ChildItem . -File |
  Where-Object { $_.Name -match "\.log$" }

At first, -eq, -ne, -gt, -lt, and -like alone are enough. Once you are comfortable, -match and -in make conditions easier to write.

33. Small Practical Recipes

From here, these are examples in a form you can use directly in real work.

See file counts per extension

Get-ChildItem C:\Work -File -Recurse |
  Group-Object -Property Extension -NoElement |
  Sort-Object -Property Count -Descending

Use this when you want a rough grasp of a folder’s contents.

See the top 20 largest files

Get-ChildItem C:\Work -File -Recurse |
  Sort-Object -Property Length -Descending |
  Select-Object -First 20 FullName, @{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }}

Commonly used in disk space investigation.

See files modified in the last 24 hours

$since = (Get-Date).AddHours(-24)

Get-ChildItem C:\Work -File -Recurse |
  Where-Object { $_.LastWriteTime -ge $since } |
  Select-Object FullName, Length, LastWriteTime

Useful after an incident for seeing which files were modified.

Turn log lines containing ERROR into a CSV

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" |
  Select-Object Path, LineNumber, Line |
  Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8

Makes investigation results easier to share.

See 2 lines before and after each ERROR

Select-String -Path C:\App\Logs\*.log -Pattern "ERROR" -Context 2

Use this when you want the context around the cause.

See the processes using the most memory

Get-Process |
  Sort-Object -Property WorkingSet -Descending |
  Select-Object -First 10 Name, Id, @{Name="MemoryMB"; Expression={ [math]::Round($_.WorkingSet / 1MB, 1) }}

See services set to automatic start but stopped

Get-Service |
  Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } |
  Select-Object Name, DisplayName, Status, StartType

Turn System log errors into a CSV

Get-WinEvent -LogName System -MaxEvents 500 |
  Where-Object { $_.LevelDisplayName -eq "Error" } |
  Select-Object TimeCreated, ProviderName, Id, Message |
  Export-Csv .\system-errors.csv -NoTypeInformation -Encoding UTF8

Send command results to the clipboard

Get-Service |
  Select-Object Name, DisplayName, Status |
  ConvertTo-Csv -NoTypeInformation |
  Set-Clipboard

Convenient for pasting into email or chat.

Compare file listings before and after work

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\before.txt -Encoding UTF8

Take it again after the work.

Get-ChildItem C:\Work -File |
  Select-Object -ExpandProperty Name |
  Set-Content .\after.txt -Encoding UTF8

Compare.

Compare-Object (Get-Content .\before.txt) (Get-Content .\after.txt)

See a folder’s total size in GB

$size = Get-ChildItem C:\Work -File -Recurse |
  Measure-Object -Property Length -Sum

[math]::Round($size.Sum / 1GB, 2)

34. Cautions When Combining with Change Commands

Most of what we have covered is read-only, and with those alone you can experiment fairly freely. These, on the other hand, are change commands.

Operation Command
Copy Copy-Item
Move Move-Item
Delete Remove-Item
Rename Rename-Item
Stop a process Stop-Process
Restart a service Restart-Service
Persist an environment variable [Environment]::SetEnvironmentVariable()

Use change commands in this order:

1. Look at the targets with Get-* commands
2. Filter with Where-Object
3. Review the target list with Select-Object
4. Count them with Measure-Object
5. Keep a record with Export-Csv if needed
6. Rehearse with -WhatIf where available
7. Execute

For example, deleting old .tmp files.

First, look at the targets.

$limit = (Get-Date).AddDays(-30)

$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
  Where-Object { $_.LastWriteTime -lt $limit }

$targets |
  Select-Object FullName, Length, LastWriteTime

Count them.

$targets | Measure-Object

Keep them in a CSV.

$targets |
  Select-Object FullName, Length, LastWriteTime |
  Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8

Confirm what would be deleted.

$targets | Remove-Item -WhatIf

If everything looks right, execute.

$targets | Remove-Item

Just sticking to this flow reduces accidents substantially.

35. How to Remember Them

Trying to memorize commands individually is hard, so it is easier to remember them by goal.

Goal Command to recall
Count Measure-Object
Sum Measure-Object -Sum
View by category Group-Object
Remove duplicates Sort-Object -Unique
Get just the values Select-Object -ExpandProperty
Shape the columns Select-Object
View largest first Sort-Object -Descending
Search for strings Select-String
See the surrounding lines Select-String -Context
Compare two things Compare-Object
Keep an audit trail Export-Csv / Start-Transcript
Output to screen and file Tee-Object
Send to the clipboard Set-Clipboard
Measure time Measure-Command
See error details Get-Error

36. Conclusion

PowerShell is powerful once you can write scripts. In real work, however, what you use most is, perhaps surprisingly, combinations of small commands.

Count
Sort
Group
Compare
Search
Extract
Save
Send to the clipboard
Keep a work log

Being able to do just these makes daily work considerably easier. There is no need to aim for difficult automation from the start. First become able to see the situation accurately with read-only commands, and on top of that, use change commands like Copy-Item, Move-Item, Remove-Item, and Restart-Service only when needed.

The trick to using PowerShell safely is this order:

Look -> Count -> Shape -> Record -> Rehearse -> Execute

Internalize this pattern, and PowerShell stops being “a black screen where you type commands” and becomes a practical tool supporting your daily investigation, organization, and reporting.

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

These topic pages place the article in a broader service and decision context.

This article connects naturally to the following service pages.

Author Profile

Profile page for the article author.

Go Komura

Representative of KomuraSoft LLC

Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.

Back to the Blog