PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely
· Updated: · Go Komura · PowerShell, Windows, Command Line, Automation, Legacy Asset Reuse
Revision history (1 updates, last updated Sep 1, 2026)
A log of the changes made to this article. Where a pre-update version was archived, it stays readable at a permanent DOI link.
- Retranslated as a full translation of the Japanese original. The previous English version was an abridgement that carried only part of the source, so sections, tables, Mermaid diagrams, figure captions and FAQ entries were missing. All of them have been restored to match the Japanese original, and the technical claims are the same as in the Japanese version. Read the version before this update (DOI: 10.5281/zenodo.21614641)
- First published
Cite this article(DOI: 10.5281/zenodo.21614640)
This article is archived on Zenodo. Below are both the DOI that always resolves to the latest version and the DOI pinned to the version you are reading.
Go Komura (2026). PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely. KomuraSoft LLC. https://doi.org/10.5281/zenodo.21614640 https://comcomponent.com/en/blog/2026/05/29/powershell-command-basics/
- DOI (latest version)
- 10.5281/zenodo.21614640
- DOI (this version)
- 10.5281/zenodo.22220493
1. What to Grasp First
PowerShell is a command environment you can use for checking Windows settings, organizing files, investigating logs, processing CSVs, operating services, and automating routine work.
That said, there is no need to write complex scripts from day one. Just learn the following flow first, and you will already be quite effective in real work.
Find -> Look -> Filter -> Sort -> Output -> Change only if needed
The fundamentals of PowerShell are not about memorizing long commands. What matters are these three things:
- Being able to look up commands with
Get-CommandandGet-Help - Being able to pass results to the next command with the
|pipeline - Checking the impact with
-WhatIfand-Confirmbefore deleting, stopping, or changing anything
PowerShell runs investigation and changes on the same screen. That is convenient, but deletions and stops execute just as instantly, so the habit of starting from read-only checks is essential.
The code that appears in this article is published on GitHub as a complete sample set, including a collection of theme-by-theme scripts that follow the chapter structure (arranged so you can practice safely in a workspace created in a temporary folder) and Pester tests.
powershell-command-basics - komurasoft-blog-samples (GitHub)
How to Read This Article
This article has 26 chapters. You do not have to read it straight through. Starting from the chapter that matches your goal will keep you oriented.
| Goal | Chapters to read |
|---|---|
| You are about to touch PowerShell for the first time | Chapters 1-8 (the mental model, how to look things up, the pipeline, file operations) and chapter 24 (the order to learn commands in) |
| You want to investigate logs or settings | Chapter 9 (text), chapter 12 (processes and services), chapter 13 (event logs), chapter 21 (an investigation sample) |
| You want to process CSV or JSON | Chapters 10, 11, and 15 |
| You want to package the work into a script | Chapters 14, 16, 17, and 18 |
| You want to delete or move things safely | Chapters 19, 22, and 25 |
| You just want to look a command up | Chapter 20 (the list of basic commands) and chapter 23 (common stumbling blocks) |
The learning order itself is collected in chapter 24, “The Order to Learn Commands In.” When you first sit down at a prompt, keep only stage 1 from chapter 24 (Get-Command, Get-Help, Get-Member, Get-Location, Set-Location, Get-ChildItem, Get-Content, Select-String) next to you and follow along with the article. Once you understand those eight, you can look up the rest when you actually need them.
How This Article Divides Up with the Practical Recipes
There is one more PowerShell article on this site. The two have different jobs, so use them as follows.
| Article | What it covers | When to read it |
|---|---|---|
| This article (the basics) | The operating model: how to find commands, how to think about the pipeline, the order that makes change commands safe | Read this one first |
| Practical PowerShell Command Recipes | Building blocks organized by goal: counts and totals (Measure-Object), grouping by category (Group-Object), comparing two sets (Compare-Object), recording a work log (Start-Transcript), and so on |
Read it when a specific “I want to do this” comes up in real work |
CSV, processes, services, event logs, and the caveats around Format-* appear in both. This article explains why you write things in that shape; the recipes article gives you the part to reach for in a given situation.
In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (20 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle
2. The Difference Between PowerShell and the Command Prompt
PowerShell looks similar to the traditional Command Prompt (cmd.exe), but the underlying model is different.
| Aspect | Command Prompt | PowerShell |
|---|---|---|
| Primary output | Strings | Objects |
| Command names | dir, copy, and so on |
Get-ChildItem, Copy-Item, and so on |
| Processing results | Mainly string manipulation | Filtering and sorting using properties |
| Automation | Batch files | .ps1 scripts |
| Strengths | Compatibility with legacy command assets | Windows administration, CSV, JSON, APIs, routine work |
To list files, for example, in cmd.exe you mostly end up reading the output of dir as text. In PowerShell, a file is handled as an object with properties such as Name, Length, and LastWriteTime.
Get-ChildItem
Once that difference clicks, something like “show only the files modified within the last 7 days, newest first” becomes natural to write.
Get-ChildItem -File |
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
Sort-Object LastWriteTime -Descending |
Select-Object Name, Length, LastWriteTime
3. Windows PowerShell 5.1 and PowerShell 7.x
Windows carries both the long-standing Windows PowerShell 5.1 and the newer PowerShell 7.x line.
In practice, thinking about them like this keeps it simple.
| Variant | Executable | Main use |
|---|---|---|
| Windows PowerShell 5.1 | powershell.exe |
Legacy Windows-only modules, existing scripts, maintaining internal assets |
| PowerShell 7.x | pwsh.exe |
New scripts, cross-platform work, ongoing feature improvements |
If you are learning fresh, basing yourself on PowerShell 7.x is perfectly fine. Old internal admin scripts and Windows-specific modules, however, are sometimes built on the assumption of Windows PowerShell 5.1.
That is why the first thing to do in practice is check the version.
$PSVersionTable
For a script that needs a minimum version, putting a condition at the top reduces the chance of mishaps.
#Requires -Version 7.0
Which Version the Samples in This Article Run On
Unless noted otherwise, the samples from here on are written to run as-is on both Windows PowerShell 5.1 and PowerShell 7.x. The same command does produce different results in the following places, so check them before you copy anything.
| Where they differ | Windows PowerShell 5.1 | PowerShell 7.x |
|---|---|---|
Default display columns for Get-Process |
Handles, NPM(K), PM(K), WS(K), CPU(s), Id, SI, ProcessName |
NPM(K), PM(M), WS(M), CPU(s), Id, SI, ProcessName (memory in MB) |
What -Encoding UTF8 means |
UTF-8 with a BOM | UTF-8 without a BOM. Specify utf8BOM when you want one |
When -Encoding is omitted |
Varies by command (Out-File uses UTF-16LE, Set-Content uses ANSI, Export-Csv uses ASCII) |
utf8NoBOM everywhere |
To avoid an unintended encoding, the samples in this article spell out -Encoding UTF8 on every write command. The reasoning behind BOMs and line endings themselves is covered in Windows Text Encodings and Line Endings.
4. Cmdlet Names Follow Verb-Noun
Standard PowerShell commands are, as a rule, in Verb-Noun form.
Get-Process
Get-Service
Get-ChildItem
Copy-Item
Remove-Item
Export-Csv
Once you have this shape in mind, commands you have never seen become easier to find.
| Verb | Meaning | Example |
|---|---|---|
Get |
Retrieve | Get-Process |
Set |
Configure | Set-Location |
New |
Create | New-Item |
Copy |
Copy | Copy-Item |
Move |
Move | Move-Item |
Remove |
Delete | Remove-Item |
Start |
Start | Start-Service |
Stop |
Stop | Stop-Process |
Import |
Read in | Import-Csv |
Export |
Write out | Export-Csv |
Short names such as dir, ls, cat, and cd work too, but most of them are aliases.
Get-Command dir
When you are writing something down as a script, using the formal name rather than an alias is safer.
# Readable, but avoid this in a script
ls *.log
# The intent is explicit
Get-ChildItem -Filter *.log
5. The Three Discovery Commands to Learn First
PowerShell has a lot of commands, so learning how to look things up is more practical than memorizing.
1. Get-Command — find available commands
Get-Command finds the commands, functions, aliases, and applications that are installed.
# Find commands with the noun Process
Get-Command -Noun Process
# Find Service-related commands
Get-Command *Service*
# Find CSV-related commands
Get-Command *Csv*
When you only half remember a command name, use wildcards.
Get-Command *Item*
Get-Command *Content*
Get-Command *Json*
2. Get-Help — see how to use a command
Get-Help shows a command’s description, parameters, and examples.
Get-Help Get-ChildItem
Get-Help Get-ChildItem -Examples
Get-Help Get-ChildItem -Full
Get-Help Get-ChildItem -Online
At the start, -Examples is the most useful.
Get-Help Where-Object -Examples
If the help is out of date or incomplete, update it from an elevated PowerShell session.
Update-Help
Depending on the environment, this needs internet access or specific privileges. On a corporate PC it can fail because of a proxy or a management policy.
3. Get-Member — look inside an object
PowerShell output is, in most cases, objects rather than strings. Get-Member shows you what properties and methods an object has.
Get-Process | Get-Member
Get-Service | Get-Member
Get-ChildItem | Get-Member
A service, for example, has properties such as Status and Name.
Get-Service | Select-Object Name, Status
A file has Name, Length, LastWriteTime, and others.
Get-ChildItem -File | Select-Object Name, Length, LastWriteTime
When you cannot tell what to filter on, check the property names with
Get-Memberfirst.
6. Pipeline Basics
In PowerShell, | passes the result of the command on the left to the command on the right.
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
This example performs the following steps from left to right.
Get the process list
-> Sort by CPU usage in descending order
-> Show only the top 10
What the Output Looks Like
By default, the result of Get-Process is displayed as a table with the following columns. The values differ from machine to machine, so what to look at here is the column layout.
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
| Column | Meaning |
|---|---|
NPM(K) |
Nonpaged pool memory usage (KB) |
PM(M) |
Pageable memory usage (MB) |
WS(M) |
Working set size, meaning the recently referenced memory pages (MB) |
CPU(s) |
Processor time used across all processors (seconds) |
Id |
Process ID |
SI |
Session ID |
ProcessName |
Process name |
That is the PowerShell 7.x default view. Windows PowerShell 5.1 puts Handles (the number of open handles) at the front and reports memory as PM(K) and WS(K) in KB. Even when the column names differ, the property names you pass to Sort-Object and Where-Object (CPU, WorkingSet, Id, Name, and so on) are the same. Display column names and property names are two different things, so when a filter condition has no effect, run Get-Process | Get-Member to find the real property names.
The combinations you will use most are these.
| Command | Role | Example |
|---|---|---|
Where-Object |
Filter by condition | Get only stopped services |
Sort-Object |
Sort | Order by most recently modified |
Select-Object |
Choose columns or counts | Show only name and size |
ForEach-Object |
Process each element | Process per file |
Export-Csv |
Output to CSV | Save investigation results |
Where-Object — filter by condition
# Show only stopped services
Get-Service | Where-Object { $_.Status -eq "Stopped" }
# Show only files larger than 100MB
Get-ChildItem -File |
Where-Object { $_.Length -gt 100MB }
# Show only files whose name contains backup
Get-ChildItem -File |
Where-Object { $_.Name -like "*backup*" }
$_ represents the object currently flowing through the pipeline.
Where-Object { $_.Length -gt 100MB }
This decides whether the Length of the file currently under inspection is greater than 100MB.
PowerShell 3.0 and later also accept a simplified syntax.
Get-Service | Where-Object Status -EQ "Stopped"
While you are still starting out, though, the scriptblock syntax makes the meaning easier to follow.
Get-Service | Where-Object { $_.Status -eq "Stopped" }
Sort-Object — sort
# Largest memory usage first
Get-Process |
Sort-Object WorkingSet -Descending |
Select-Object -First 10 Name, Id, WorkingSet
# Most recently modified first
Get-ChildItem -File |
Sort-Object LastWriteTime -Descending |
Select-Object -First 20 Name, LastWriteTime
Select-Object — choose only the columns you need
Get-Process |
Select-Object Name, Id, CPU, WorkingSet
It also limits the number of items.
Get-Process | Select-Object -First 5
Get-Process | Select-Object -Last 5
Trimming down to just the columns you need with Select-Object before writing a CSV makes the result much easier to work with.
Get-Service |
Select-Object Name, DisplayName, Status, StartType |
Export-Csv .\services.csv -NoTypeInformation -Encoding UTF8
7. Use the Format Commands Last
PowerShell has commands for tidying up the display.
Format-Table
Format-List
Format-Wide
These are for on-screen display. Use them before writing a CSV or before handing results to a later step, and what flows on is a formatting object rather than the original properties.
# Avoid: display information leaks into the CSV
Get-Process |
Format-Table Name, CPU |
Export-Csv .\process.csv -NoTypeInformation
# Correct: choose the properties first, then write the CSV
Get-Process |
Select-Object Name, CPU |
Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8
Remember
Format-*as “for showing on screen at the very end,” and you will run into fewer mishaps.
8. File and Folder Operation Basics
File and folder operations are what you will use most in PowerShell.
| What you want to do | Command |
|---|---|
| See the current location | Get-Location |
| Change location | Set-Location |
| See a listing | Get-ChildItem |
| Create a file or folder | New-Item |
| Copy | Copy-Item |
| Move | Move-Item |
| Rename | Rename-Item |
| Delete | Remove-Item |
| Check existence | Test-Path |
Check the current location
Get-Location
Move somewhere else.
Set-Location C:\Work
Wrap the path in quotes when it contains spaces.
Set-Location "C:\Work Files\Reports"
See the file listing
Get-ChildItem
Get-ChildItem -File
Get-ChildItem -Directory
Get-ChildItem -Recurse
Running it prints a heading for the target folder, and under it a table with the following columns.
Directory: C:\Work
Mode LastWriteTime Length Name
---- ------------- ------ ----
Mode is a set of attribute letters: d for directory, a for the archive attribute, r for read-only, h for hidden, s for system, and l for a link. Directory rows leave Length (the size) blank. The LastWriteTime and Length shown here are exactly the property names you can use in Where-Object and Sort-Object.
To narrow by extension, -Filter is convenient.
Get-ChildItem -Filter *.log
To search subfolders as well, use -Recurse.
Get-ChildItem C:\Logs -Filter *.log -Recurse
In a location with a huge number of files, do not reach for -Recurse straight away; limit the target folder first and then run it.
Create
# Create a folder
New-Item -ItemType Directory -Path .\archive
# Create an empty file
New-Item -ItemType File -Path .\memo.txt
When the target may already exist, check first.
if (-not (Test-Path .\archive)) {
New-Item -ItemType Directory -Path .\archive
}
Copy
Copy-Item .\report.xlsx .\backup\report.xlsx
To copy a whole folder, use -Recurse.
Copy-Item .\data .\backup\data -Recurse
When overwriting is involved, confirm the impact beforehand.
Copy-Item .\data .\backup\data -Recurse -WhatIf
Move
Move-Item .\old.log .\archive\old.log
When moving several files by a condition, add -WhatIf on the first run.
Get-ChildItem .\logs -Filter *.log |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Move-Item -Destination .\archive -WhatIf
If everything looks right, drop the -WhatIf.
Get-ChildItem .\logs -Filter *.log |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } |
Move-Item -Destination .\archive
Delete
Deletion deserves particular care.
Remove-Item .\old.log -WhatIf
Run it once you have confirmed the target is correct.
Remove-Item .\old.log
Wildcards combined with -Recurse are powerful. Do not run that against a production folder from the outset; confirm with a listing first.
# First, check the targets
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
Select-Object FullName, Length, LastWriteTime
# Next, check what would be deleted
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
Remove-Item -WhatIf
# Finally, execute
Get-ChildItem C:\Logs -Filter *.tmp -Recurse |
Remove-Item
9. Reading, Searching, and Writing Text Files
Log investigation leans heavily on text file operations.
Read a file
Get-Content .\app.log
To see only the end, use -Tail.
Get-Content .\app.log -Tail 50
To watch a log as lines are appended, use -Wait.
Get-Content .\app.log -Tail 20 -Wait
Search for strings
Select-String -Path .\app.log -Pattern "ERROR"
You can target multiple files.
Select-String -Path .\logs\*.log -Pattern "ERROR", "WARN"
You can also pull the file name, line number, and content out of the results and write them to CSV.
Select-String -Path .\logs\*.log -Pattern "ERROR" |
Select-Object Path, LineNumber, Line |
Export-Csv .\error-lines.csv -NoTypeInformation -Encoding UTF8
Write to a file
"hello" | Set-Content .\memo.txt -Encoding UTF8
"next line" | Add-Content .\memo.txt -Encoding UTF8
When saving command results, Export-Csv or ConvertTo-Json is sometimes easier to work with later than Out-File.
Get-Process |
Select-Object Name, Id, CPU |
Export-Csv .\process.csv -NoTypeInformation -Encoding UTF8
10. CSV Basics
CSV comes up constantly in business automation. In PowerShell you can treat a CSV as objects with columns rather than as strings.
Read a CSV
Suppose you have a users.csv like this.
Name,Department,Enabled
Suzuki,Sales,true
Tanaka,Accounting,false
Sato,Sales,true
Read it in.
$users = Import-Csv .\users.csv
$users
The column names become properties.
$users | Select-Object Name, Department
Filter by condition
$users |
Where-Object { $_.Department -eq "Sales" }
CSV values usually come in as strings, so take care when handling true / false or numbers.
$users |
Where-Object { $_.Enabled -eq "true" }
Output to CSV
$users |
Where-Object { $_.Department -eq "Sales" } |
Export-Csv .\sales-users.csv -NoTypeInformation -Encoding UTF8
The iron rule is to never put Format-Table in front of Export-Csv.
# Avoid
$users | Format-Table | Export-Csv .\out.csv -NoTypeInformation
# Correct
$users | Select-Object Name, Department, Enabled | Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8
11. JSON Basics
Configuration files and web APIs use JSON just as often.
$data = Get-Content .\settings.json -Raw | ConvertFrom-Json
$data
Convert an object to JSON.
[pscustomobject]@{
Name = "BatchJob"
Enabled = $true
Retry = 3
} | ConvertTo-Json
When deep nesting is involved, specify -Depth.
$config | ConvertTo-Json -Depth 10 | Set-Content .\settings.json -Encoding UTF8
12. Process and Service Basics
View processes
Get-Process
Check the processes with the largest memory usage.
Get-Process |
Sort-Object WorkingSet -Descending |
Select-Object -First 10 Name, Id, WorkingSet
Filter by name.
Get-Process -Name notepad
Stop with care.
Stop-Process -Name notepad -WhatIf
If everything looks right, execute.
Stop-Process -Name notepad
View services
Get-Service
To see only stopped services:
Get-Service |
Where-Object { $_.Status -eq "Stopped" }
Filter by name.
Get-Service -Name "Spooler"
When restarting, confirm the target first here as well.
Get-Service -Name "Spooler"
Restart-Service -Name "Spooler" -WhatIf
Service operations easily affect the business, so in production check the runbook, the maintenance window, and the recovery procedure before you start.
13. Event Log Basics
Event logs are indispensable for Windows investigation.
Check recent errors.
Get-WinEvent -LogName System -MaxEvents 100 |
Where-Object { $_.LevelDisplayName -eq "Error" } |
Select-Object TimeCreated, ProviderName, Id, Message
What the Output Looks Like
By default, the result of Get-WinEvent gets a heading per log provider (ProviderName), with a table of the following columns lined up underneath.
ProviderName: PowerShell
TimeCreated Id LevelDisplayName Message
----------- -- ---------------- -------
When you choose columns with Select-Object as in the example above, the provider heading disappears and you get a table of just the columns you picked. Message is long, so it is cut off on screen. To read one entry all the way through, narrow down to a single event and display it with Format-List.
Get-WinEvent -LogName System -MaxEvents 1 | Format-List *
LevelDisplayName holds Critical, Error, Warning, Information, or Verbose. On logs with many entries, passing the condition to -FilterHashtable is faster than filtering with Where-Object (Level = 3 is warning and Level = 4 is information).
View the most recent 50 entries from the Application log.
Get-WinEvent -LogName Application -MaxEvents 50 |
Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message
To narrow by time period:
$start = (Get-Date).AddHours(-24)
Get-WinEvent -FilterHashtable @{
LogName = "System"
StartTime = $start
} |
Select-Object TimeCreated, ProviderName, Id, LevelDisplayName, Message
Saving investigation results to CSV makes them easier to share later.
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
14. Variables, Arrays, and Hashtables
You can get work done with short commands alone, but once things get a little longer, variables become handy.
Variables
$path = "C:\Logs"
Get-ChildItem $path
PowerShell variables start with $.
$today = Get-Date
$limit = (Get-Date).AddDays(-30)
Arrays
$extensions = @("*.log", "*.txt", "*.csv")
foreach ($ext in $extensions) {
Get-ChildItem C:\Work -Filter $ext
}
Hashtables
A hashtable is a set of key-value pairs.
$params = @{
Path = "C:\Logs"
Filter = "*.log"
Recurse = $true
}
Get-ChildItem @params
Writing it in the @params style is called splatting. It keeps things readable as the number of parameters grows.
15. Shaping Results with PSCustomObject
When you want to summarize investigation results in tabular form, [pscustomobject] is convenient.
[pscustomobject]@{
ComputerName = $env:COMPUTERNAME
UserName = $env:USERNAME
CheckedAt = Get-Date
}
You can build multiple results and turn them into a CSV.
Get-ChildItem C:\Logs -Filter *.log |
ForEach-Object {
[pscustomobject]@{
Name = $_.Name
FullName = $_.FullName
SizeMB = [math]::Round($_.Length / 1MB, 2)
LastWriteTime = $_.LastWriteTime
}
} |
Export-Csv .\log-files.csv -NoTypeInformation -Encoding UTF8
16. Script File .ps1 Basics
Turn the work you repeat into .ps1 files.
As an example, build a script that lists old logs.
# Find-OldLogs.ps1
param(
[string]$Path = "C:\Logs",
[int]$Days = 30,
[string]$OutputPath = ".\old-logs.csv"
)
$limit = (Get-Date).AddDays(-$Days)
Get-ChildItem -Path $Path -Filter *.log -File -Recurse |
Where-Object { $_.LastWriteTime -lt $limit } |
Select-Object FullName, Length, LastWriteTime |
Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
Write-Host "Exported: $OutputPath"
Example run:
.\Find-OldLogs.ps1 -Path C:\Logs -Days 60 -OutputPath .\old-logs.csv
Accepting arguments with param() makes the conditions easy to change later.
17. Execution Policy Basics
When you try to run a .ps1, you may see an error like this.
... cannot be loaded because running scripts is disabled on this system...
In that case, check the current execution policy.
Get-ExecutionPolicy
Get-ExecutionPolicy -List
On a personal development machine, where all you want is to run locally created scripts, setting RemoteSigned at the current-user scope is the common choice.
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
On a corporate PC, however, this may be controlled by Group Policy. Do not force a workaround; check with your administrators and your operational rules.
Execution policy is a safety feature that controls the conditions under which PowerShell runs scripts. It is not, however, a complete security boundary. In an organization, it has to be considered together with signing, AppLocker, Microsoft Defender, privilege management, and log auditing.
18. Error Handling Basics
PowerShell sometimes keeps going even when an error occurs.
For work that matters, use -ErrorAction Stop together with try/catch.
try {
Copy-Item .\source.txt .\backup\source.txt -ErrorAction Stop
Write-Host "Copy succeeded"
}
catch {
Write-Error "Copy failed: $($_.Exception.Message)"
}
When processing several files, recording the failures lets you trace them afterward.
$results = foreach ($file in Get-ChildItem .\input -File) {
try {
Copy-Item $file.FullName .\backup -ErrorAction Stop
[pscustomobject]@{
FileName = $file.Name
Status = "OK"
Message = ""
}
}
catch {
[pscustomobject]@{
FileName = $file.Name
Status = "NG"
Message = $_.Exception.Message
}
}
}
$results | Export-Csv .\copy-result.csv -NoTypeInformation -Encoding UTF8
19. The Safe Order for Running Change Commands
In PowerShell, having a procedure for safely handling change commands such as delete, move, and stop matters.
The basic order is this.
1. Look at the targets with Get-* commands
2. Filter with Where-Object
3. Review the target list with Select-Object
4. Record it with Export-Csv
5. Preview the planned changes with -WhatIf
6. Run for real
As an example, take deleting .tmp files older than 30 days.
Step 1: Look at the targets
Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse
Step 2: Filter by condition
$limit = (Get-Date).AddDays(-30)
Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
Where-Object { $_.LastWriteTime -lt $limit }
Step 3: Show only the columns you need
$targets = Get-ChildItem C:\Temp -Filter *.tmp -File -Recurse |
Where-Object { $_.LastWriteTime -lt $limit }
$targets |
Select-Object FullName, Length, LastWriteTime
Step 4: Keep an audit trail
$targets |
Select-Object FullName, Length, LastWriteTime |
Export-Csv .\delete-targets.csv -NoTypeInformation -Encoding UTF8
Step 5: Confirm with WhatIf
$targets | Remove-Item -WhatIf
Step 6: Execute
$targets | Remove-Item
Following this order makes the “we have no idea what we just deleted” kind of mishap far less likely.
20. A List of Frequently Used Basic Commands
Location and files
| Purpose | Example command |
|---|---|
| Show the current folder | Get-Location |
| Change folders | Set-Location C:\Work |
| Show a listing | Get-ChildItem |
| Show files only | Get-ChildItem -File |
| Show folders only | Get-ChildItem -Directory |
| Search subfolders too | Get-ChildItem -Recurse |
| Check existence | Test-Path .\file.txt |
| Create a folder | New-Item -ItemType Directory .\backup |
| Copy | Copy-Item .\a.txt .\backup\a.txt |
| Move | Move-Item .\a.txt .\archive\a.txt |
| Preview a deletion | Remove-Item .\a.txt -WhatIf |
Object manipulation
| Purpose | Example command |
|---|---|
| Filter by condition | Where-Object { $_.Status -eq "Running" } |
| Sort | Sort-Object LastWriteTime -Descending |
| Choose columns | Select-Object Name, LastWriteTime |
| Show only the top entries | Select-Object -First 10 |
| Process each element | ForEach-Object { $_.Name } |
| Inspect the contents | Get-Member |
Input and output
| Purpose | Example command |
|---|---|
| Read text | Get-Content .\app.log |
| View the tail | Get-Content .\app.log -Tail 50 |
| Search strings | Select-String -Path .\app.log -Pattern "ERROR" |
| Read a CSV | Import-Csv .\users.csv |
| Write a CSV | Export-Csv .\out.csv -NoTypeInformation -Encoding UTF8 |
| Read JSON | Get-Content .\a.json -Raw | ConvertFrom-Json |
| Write JSON | $obj | ConvertTo-Json -Depth 10 |
Windows investigation
| Purpose | Example command |
|---|---|
| Process list | Get-Process |
| Service list | Get-Service |
| Event logs | Get-WinEvent -LogName System -MaxEvents 100 |
| Environment variables | Get-ChildItem Env: |
| PowerShell version | $PSVersionTable |
| Execution policy | Get-ExecutionPolicy -List |
21. Practical Sample: Investigate Logs and Build a Report
Consider a requirement like this.
From the .log files under C:\App\Logs, find the lines containing ERROR in files modified within the last 7 days, and compile them into a CSV.
Rather than writing the finished form straight away, build it in stages.
Step 1: Find the log files
Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse
Step 2: Narrow to the last 7 days
$since = (Get-Date).AddDays(-7)
Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
Where-Object { $_.LastWriteTime -ge $since }
Step 3: Search for ERROR
$since = (Get-Date).AddDays(-7)
Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
Where-Object { $_.LastWriteTime -ge $since } |
Select-String -Pattern "ERROR"
Step 4: Output to CSV
$since = (Get-Date).AddDays(-7)
Get-ChildItem C:\App\Logs -Filter *.log -File -Recurse |
Where-Object { $_.LastWriteTime -ge $since } |
Select-String -Pattern "ERROR" |
Select-Object Path, LineNumber, Line |
Export-Csv .\error-report.csv -NoTypeInformation -Encoding UTF8
Step 5: Turn it into a script
# Export-ErrorReport.ps1
param(
[string]$LogPath = "C:\App\Logs",
[int]$Days = 7,
[string]$Pattern = "ERROR",
[string]$OutputPath = ".\error-report.csv"
)
$since = (Get-Date).AddDays(-$Days)
Get-ChildItem $LogPath -Filter *.log -File -Recurse |
Where-Object { $_.LastWriteTime -ge $since } |
Select-String -Pattern $Pattern |
Select-Object Path, LineNumber, Line |
Export-Csv $OutputPath -NoTypeInformation -Encoding UTF8
Write-Host "Exported: $OutputPath"
Example run:
.\Export-ErrorReport.ps1 -LogPath C:\App\Logs -Days 14 -Pattern "ERROR|FATAL" -OutputPath .\errors.csv
22. Practical Sample: Archive Old Files
Next is an example that moves rather than deletes.
Move the .xlsx files in C:\Work\Reports that have not been modified for 90 days or more to C:\Work\Archive.
Confirm the targets
$source = "C:\Work\Reports"
$dest = "C:\Work\Archive"
$limit = (Get-Date).AddDays(-90)
$targets = Get-ChildItem $source -Filter *.xlsx -File |
Where-Object { $_.LastWriteTime -lt $limit }
$targets | Select-Object FullName, Length, LastWriteTime
Create the archive destination
if (-not (Test-Path $dest)) {
New-Item -ItemType Directory -Path $dest
}
Output an audit trail
$targets |
Select-Object FullName, Length, LastWriteTime |
Export-Csv .\archive-targets.csv -NoTypeInformation -Encoding UTF8
Confirm with WhatIf
$targets | Move-Item -Destination $dest -WhatIf
Execute
$targets | Move-Item -Destination $dest
If file name collisions are possible, this will fail as written. In practice, settle the rules up front: split into year-month folders, append a timestamp to the destination file name, or skip when a file already exists.
23. Common Stumbling Blocks
| Symptom | Cause | Remedy |
|---|---|---|
| Commands are too long to remember | You are trying to memorize them | Look them up with Get-Command and Get-Help -Examples |
$_ makes no sense |
The current pipeline value is not understood yet | Learn it through the form Where-Object { $_.Name -like "*log*" } |
| The CSV comes out strange | Export-Csv is running after Format-Table |
Run Export-Csv after Select-Object |
| Paths with spaces fail | Missing quotes | Wrap them like "C:\Work Files\a.txt" |
| The script will not run | Execution policy | Check with Get-ExecutionPolicy -List |
| Too many deletion targets | The condition is too broad | Confirm first with Select-Object FullName and -WhatIf |
| You cannot figure out the property names | You have not looked at the object structure | Use Get-Member |
| The text is garbled | The encoding assumptions do not match | Check -Encoding on input and output, and the application consuming the file |
24. The Order to Learn Commands In
There is no need to learn every command from the start.
The following order works well.
Stage 1: Look and find
Get-Command
Get-Help
Get-Member
Get-Location
Set-Location
Get-ChildItem
Get-Content
Select-String
Stage 2: Filter and shape
Where-Object
Sort-Object
Select-Object
ForEach-Object
Format-Table
Format-List
Stage 3: Input and output
Import-Csv
Export-Csv
ConvertFrom-Json
ConvertTo-Json
Set-Content
Add-Content
Out-File
Stage 4: Change
New-Item
Copy-Item
Move-Item
Rename-Item
Remove-Item
Start-Service
Stop-Service
Restart-Service
Stop-Process
Always learn the change commands paired with the verification commands that go with them.
# Look
Get-ChildItem .\logs -Filter *.tmp
# See what would be deleted
Get-ChildItem .\logs -Filter *.tmp | Remove-Item -WhatIf
# Execute
Get-ChildItem .\logs -Filter *.tmp | Remove-Item
25. An Operational Checklist for the Field
When you use PowerShell for business work, running through the following points keeps things safe.
- Confirmed whether the PowerShell being run is
powershell.exeorpwsh.exe - Checked the version with
$PSVersionTable - Displayed the targets with
Get-*commands before making changes - Reviewed the
Where-Objectconditions on screen - Used
-WhatIfbefore deleting, moving, or stopping - Saved the pre-execution target list to CSV
- Confirmed backups or a recovery procedure in production
- Checked the script execution policy and the internal rules
- Prepared log output for error cases
- Used the formal command names rather than aliases in shared scripts
26. Conclusion
The fundamentals of PowerShell are not about memorizing a mountain of commands. What pays off in real work is internalizing this pattern.
Find with Get-Command
See usage with Get-Help
Check properties with Get-Member
Look at targets with Get-*
Filter with Where-Object
Shape columns with Select-Object
Keep a trail with Export-Csv
Preview changes with -WhatIf
Execute last
Above all, PowerShell is a powerful environment that can delete files, stop services, kill processes, and even manipulate the registry. Precisely for that reason, the first thing to learn is not the dangerous commands but the procedure for confirming your targets safely.
Look -> Filter -> Record -> Rehearse -> Execute
Stick to this order, and PowerShell stops being just a black screen and becomes a practical tool for organizing, investigating, and automating Windows work.
Reference Links
- The complete sample code for this article (theme-by-theme scripts and Pester tests) - komurasoft-blog-samples (GitHub)
- PowerShell Documentation - Microsoft Learn
- Installing PowerShell 7 on Windows - Microsoft Learn
- Differences between Windows PowerShell 5.1 and PowerShell 7.x - Microsoft Learn
- Get-Command - Microsoft Learn
- Get-Help - Microsoft Learn
- Get-Member - Microsoft Learn
- about_Pipelines - Microsoft Learn
- Where-Object - Microsoft Learn
- Select-Object - Microsoft Learn
- Get-Process - Microsoft Learn (includes a description of the default display columns)
- Get-WinEvent - Microsoft Learn
- about_Character_Encoding (Windows PowerShell 5.1) - Microsoft Learn
- Import-Csv - Microsoft Learn
- Export-Csv - Microsoft Learn
- about_Execution_Policies - Microsoft Learn
Related Articles
- Practical PowerShell Command Recipes — Growing the Small Tools You Use Every Day
- Windows Text Encodings and Line Endings
- A Migration Guide for the VBScript Deprecation
- Pitfalls of COM/OCX/ActiveX Development
Services Related to This Topic
Windows Application Development
We support the development of Windows software such as business applications, equipment integration, and communication tools.
Legacy Asset Reuse and Migration Support
We support taking stock of, modifying, and migrating existing assets including old batch files, VBScript, VBA, PowerShell, and COM / ActiveX.
Related Articles
Recent articles sharing the same tags. Deepen your understanding with closely related topics.
Parameter Design and Modularization for PowerShell Scripts — From a Script That Works to a Script You Can Hand Over
A step-by-step procedure for raising a PowerShell script to a quality you can hand to someone else. Covers the param block and [CmdletBin...
Practical PowerShell Command Recipes — Growing the Small Tools You Use Every Day
A practical roundup of PowerShell commands for everyday work, covering where to use Measure-Object, Group-Object, Select-String, Compare-...
Calling COM and .NET from PowerShell — Widening What Your Scripts Can Reach
A practical guide to calling .NET classes from PowerShell, embedding C# and Win32 APIs with Add-Type, driving COM, cleaning up leftover E...
The Differences Between Windows PowerShell 5.1 and PowerShell 7 — A Practical Guide to Migrating In-House Scripts
The relationship between Windows PowerShell 5.1 and PowerShell 7 (side-by-side coexistence and pwsh.exe), Microsoft's official position t...
Automating Excel and CSV Work with PowerShell — Practical Recipes for Aggregation, Reconciliation, and Report Output
Practical recipes for automating CSV aggregation, reconciliation, and Excel report output with PowerShell. Covers the default encodings o...
Related Topics
These topic pages place the article in a broader service and decision context.
Windows Technical Topics
Topic hub for KomuraSoft LLC's Windows development, investigation, and legacy-asset articles.
Where This Topic Connects
This article connects naturally to the following service pages.
Windows App Development
We support Windows desktop applications that involve resident processing, device integration, operational logging, and maintainable structure.
Frequently Asked Questions
Common questions about the topic of this article.
- Where should I start when learning PowerShell?
- Learn how to look things up rather than memorizing commands. Three things matter: being able to research commands with Get-Command and Get-Help, being able to pass results to the next command through the pipeline (|), and checking the impact with -WhatIf or -Confirm before you delete, stop, or change anything. When you do not know an object's property names, inspect it with Get-Member. The basic flow is find, look, filter, sort, output, and change only if needed.
- What is the difference between PowerShell and the Command Prompt?
- The biggest difference is that Command Prompt output is mostly strings while PowerShell output is objects. A file, for example, is handled as an object with properties such as Name, Length, and LastWriteTime, so filtering with Where-Object and sorting with Sort-Object come naturally. Command names are also standardized on a Verb-Noun form such as Get-ChildItem and Copy-Item, which makes commands you have never seen easier to find.
- Should I use Windows PowerShell 5.1 or PowerShell 7.x?
- If you are learning fresh, basing yourself on PowerShell 7.x (pwsh.exe) is perfectly fine. That said, old internal admin scripts and Windows-specific modules are sometimes built on the assumption of Windows PowerShell 5.1 (powershell.exe). In practice, check the version with $PSVersionTable first, and for a script that needs a minimum version, put a condition such as #Requires -Version 7.0 at the top to reduce the risk of mishaps.
- How do I delete or change things safely in PowerShell?
- Keep to the order look, filter, record, rehearse, execute. Concretely: display the targets with a Get command, narrow them with Where-Object, review the list with Select-Object, leave an audit trail in CSV with Export-Csv, confirm the planned changes with -WhatIf, and only then run for real. Because PowerShell runs investigation and changes on the same screen, the habit of starting from read-only checks is essential.