PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely

· Updated: · · 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:

  1. Being able to look up commands with Get-Command and Get-Help
  2. Being able to pass results to the next command with the | pipeline
  3. Checking the impact with -WhatIf and -Confirm before 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-Member first.

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.exe or pwsh.exe
  • Checked the version with $PSVersionTable
  • Displayed the targets with Get-* commands before making changes
  • Reviewed the Where-Object conditions on screen
  • Used -WhatIf before 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.

Windows Application Development

We support the development of Windows software such as business applications, equipment integration, and communication tools.

See the service / Contact us

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.

Contact us

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.

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.

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