A Comprehensive Reference — 252 Commands
PowerShell
Handbook
All major cmdlets, syntax patterns, real-world examples, and scripting techniques — PowerShell 5.1 & 7.x, Windows & Cross-Platform
Contents — 25 Sections
▶25 Sections — 252 Commands
- Getting Help & Navigation
- File System Operations
- Text & File Content
- Process Management
- Service Management
- System Information
- User & Group Management
- Network Commands
- Registry Operations
- Variables & Data Types
- String Manipulation
- Pipelines & Filtering
- Loops & Conditionals
- Functions & Scripts
- Error Handling
- Output & Formatting
- Scheduled Tasks
- Event Logs
- Security & Permissions
- PowerShell Remoting
- Modules & Packages
- Environment Variables
- Date & Time
- Math & Numbers
- Aliases & Profiles
1. Getting Help & Navigation
▶PowerShell's help system is one of its most powerful features. These commands let you discover, explore, and understand any cmdlet, function, or concept without leaving the shell.
Get-Help [-Name] <string> [-Full] [-Examples] [-Online] [-Parameter <string>]
Get-Help Get-Process -Full
Get-Help about_Pipelines
Get-Help Copy-Item -Examples
-Full (complete help), -Examples (only examples), -Online (opens browser), -Parameter (info on specific param)
Update-Help -Force
Update-Help -Module Microsoft.PowerShell.Management
Get-Command -Verb Get
Get-Command -Noun Process
Get-Command *service* -CommandType Cmdlet
Key flags: -Verb, -Noun, -Module, -CommandType (Cmdlet, Function, Alias)
Get-Process | Get-Member
Get-Date | Get-Member -MemberType Method
[string] | Get-Member -Static
cd, pwd, sl, gl.Set-Location C:\Windows\System32
Set-Location HKLM:\SOFTWARE
Get-Location
(Get-Location).Path
Push-Location C:\Temp
# do work
Pop-Location # returns to original path
Get-Alias ls
Get-Alias -Definition Get-ChildItem
Get-Alias | Where-Object Definition -eq 'Set-Location'
2. File System Operations
▶PowerShell provides a rich set of cmdlets for managing the file system, handling copying, moving, renaming, and deleting files and directories, as well as querying file system information.
| Cmdlet | Alias | Description |
|---|---|---|
Get-ChildItem | ls, dir, gci | Lists files and directories at a given path |
Copy-Item | cp, copy | Copies files and directories to another location |
Move-Item | mv, move | Moves files and directories |
Remove-Item | rm, del, rd | Deletes files and directories |
New-Item | ni | Creates files, directories, symbolic links |
Rename-Item | ren, rni | Renames a file or directory |
Get-Item | gi | Gets the item at the specified path (without listing contents) |
Test-Path | — | Returns True/False whether a path exists |
Get-ItemProperty | gp | Gets properties of a file, directory, or registry key |
Join-Path | — | Combines path segments, handling slashes automatically |
Split-Path | — | Returns parent folder, file name, extension, or drive from a path |
Resolve-Path | rvpa | Resolves wildcard characters and returns the actual path(s) |
Get-ChildItem C:\Windows -Filter *.exe
Get-ChildItem -Recurse -Depth 2 -File
gci C:\Logs -Filter *.log | Sort-Object LastWriteTime -Descending
Get-ChildItem -Hidden # show hidden files
Get-ChildItem -Recurse -Include *.ps1,*.psm1
New-Item -Path C:\Temp\test.txt -ItemType File
New-Item -Path C:\NewFolder -ItemType Directory
New-Item -Path C:\link -ItemType SymbolicLink -Value C:\Target
New-Item -Path C:\HardLink -ItemType HardLink -Value C:\Target
if (Test-Path C:\config.txt) { Write-Host 'Found' }
Test-Path C:\folder -PathType Container # directory check
Test-Path C:\file.txt -PathType Leaf # file check
Test-Path HKLM:\Software\MyApp # registry check
# Combine paths safely
$full = Join-Path $env:USERPROFILE 'Documents' 'report.txt'
# Extract parts
Split-Path C:\Logs\app.log -Leaf # app.log
Split-Path C:\Logs\app.log -Parent # C:\Logs
Split-Path C:\Logs\app.log -Extension # .log
Split-Path C:\Logs\app.log -Qualifier # C:
3. Text & File Content
▶-Raw).Get-Content C:\log.txt
Get-Content C:\log.txt -Tail 20 # last 20 lines (like tail -f)
Get-Content C:\log.txt -TotalCount 10 # first 10 lines
Get-Content C:\data.txt -Raw -Encoding UTF8
Get-Content C:\log.txt -Wait # follow mode (live log)
Set-Content C:\output.txt 'Hello World' # overwrite
'Line1','Line2','Line3' | Set-Content C:\lines.txt
Add-Content C:\log.txt "$(Get-Date) - Script started" # append
'new line' | Add-Content C:\file.txt
Clear-Content C:\log.txt # empty without deleting
Select-String -Path C:\*.log -Pattern 'ERROR'
Select-String 'failed' C:\logs\*.txt -CaseSensitive
Select-String -Path app.log -Pattern 'timeout' -Context 2,3
Select-String -Path *.log -Pattern 'WARN|ERROR' -AllMatches
Get-Process | Export-Csv C:\procs.csv -NoTypeInformation
Get-Service | Export-Csv C:\svcs.csv -Append -Delimiter ';'
Import-Csv C:\users.csv | ForEach-Object { New-LocalUser $_.Name }
$data = Import-Csv C:\report.csv -Delimiter ';'
Get-Process | Select Name,CPU | ConvertTo-Json -Depth 3
$hash = @{Name='Alice';Age=30} | ConvertTo-Json -Compress
$json = '{"Name":"Alice","Age":30}'
$obj = $json | ConvertFrom-Json
$obj.Name # Alice
Set-Content, preserves PowerShell's formatted output (tables, lists).Get-Process | Out-File C:\procs.txt
Get-Service | Out-File C:\services.txt -Append
Get-Process | Out-File C:\procs.txt -Width 200 -Encoding UTF8
4. Process Management
▶Get-Process
Get-Process -Name chrome
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
Get-Process -IncludeUserName | Where-Object UserName -like '*admin*'
Start-Process notepad.exe
Start-Process cmd.exe -ArgumentList '/c dir C:\' -Wait
Start-Process powershell.exe -Verb RunAs # Run as admin
Start-Process app.exe -WindowStyle Hidden
Stop-Process -Name notepad
Stop-Process -Id 1234 -Force
Get-Process chrome | Stop-Process
Start-Process msiexec.exe -ArgumentList '/i app.msi /quiet'
Wait-Process msiexec
Write-Host 'Installation complete'
$job = Start-Job -ScriptBlock { Get-EventLog -Log Application -Newest 1000 }
Get-Job # list all jobs
Get-Job -State Running # filter by state
Wait-Job $job # block until complete
Receive-Job $job # get results
Receive-Job $job -Keep # keep results for re-reading
Stop-Job -Id 3
Remove-Job -Id 3
5. Service Management
▶| Cmdlet | Description | Common Example |
|---|---|---|
Get-Service | List services and their status | Get-Service | Where-Object Status -eq Running |
Start-Service | Start a stopped service | Start-Service -Name Spooler |
Stop-Service | Stop a running service | Stop-Service -Name bits -Force |
Restart-Service | Stop then start a service | Restart-Service -Name Spooler |
Set-Service | Change service properties | Set-Service -Name wuauserv -StartupType Disabled |
New-Service | Create a new Windows service | New-Service -Name MySvc -BinaryPathName C:\app.exe |
Remove-Service | Delete a service (PS7+) | Remove-Service -Name MySvc |
Suspend-Service | Pause a service that supports it | Suspend-Service -Name Spooler |
# Find all automatic-start services that are stopped
Get-Service | Where-Object { $_.StartType -eq 'Automatic' -and $_.Status -eq 'Stopped' }
# Restart all stopped auto-start services
Get-Service | Where-Object { $_.StartType -eq 'Automatic' -and $_.Status -eq 'Stopped' } | Start-Service
# Check service dependencies
Get-Service -Name Spooler -DependentServices
Get-Service -Name Spooler -RequiredServices
7. User & Group Management
▶Note
These cmdlets manage local user accounts and groups. For Active Directory management, use the ActiveDirectory module (Import-Module ActiveDirectory).
# List users
Get-LocalUser
Get-LocalUser | Where-Object Enabled -eq $true
# Create a user
$pw = Read-Host 'Password' -AsSecureString
New-LocalUser -Name 'jdoe' -Password $pw -FullName 'John Doe' -PasswordNeverExpires
# Modify, enable, disable
Set-LocalUser -Name jdoe -Description 'Developer'
Enable-LocalUser -Name jdoe
Disable-LocalUser -Name tempcontractor
# Remove
Remove-LocalUser -Name tempuser
Get-LocalUser | Where-Object Enabled -eq $false | Remove-LocalUser
Get-LocalGroup
Get-LocalGroupMember -Group Administrators
Add-LocalGroupMember -Group Administrators -Member jdoe
Add-LocalGroupMember -Group 'Remote Desktop Users' -Member 'DOMAIN\jsmith'
Remove-LocalGroupMember -Group Administrators -Member jdoe
6. System Information
▶Gather hardware, OS, BIOS, network, and software configuration details from local or remote systems.
Get-ComputerInfo [[-Property] <string[]>]
Get-ComputerInfo
Get-ComputerInfo -Property OsName, OsVersion, TotalPhysicalMemory
Get-ComputerInfo | Select-Object CsName, WindowsVersion
Key flags: -Property (filter returned properties)
Get-CimInstance [-ClassName] <string> [-Filter <string>] [-ComputerName <string[]>] [-Property <string[]>]
Get-CimInstance Win32_OperatingSystem
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3"
Get-CimInstance Win32_PhysicalMemory | Measure-Object Capacity -Sum
Key flags: -ClassName, -Filter (WQL WHERE clause), -ComputerName, -Query (full WQL)
Get-WmiObject [-Class] <string> [-Filter <string>] [-ComputerName <string[]>]
Get-WmiObject Win32_BIOS
Get-WmiObject Win32_DiskDrive | Select Model, Size
Key flags: -Class, -Filter, -ComputerName, -Query
Get-HotFix [[-Id] <string[]>] [-ComputerName <string[]>] [-Description <string>]
Get-HotFix
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10
Get-HotFix -Id KB5001234
Key flags: -Id, -ComputerName, -Description (Security Update, Update, etc.)
Get-Disk [-Number <uint32>] [-UniqueId <string>]
Get-Disk
Get-Disk | Where-Object IsSystem -eq $true
Key flags: -Number (disk index), -UniqueId, -SerialNumber
Get-Volume [-DriveLetter <char[]>] [-FileSystemLabel <string>]
Get-Volume
Get-Volume -DriveLetter C
Get-Volume | Where-Object DriveType -eq Fixed
Key flags: -DriveLetter, -FileSystemLabel
Get-PSDrive [[-Name] <string[]>] [-PSProvider <string[]>]
Get-PSDrive
Get-PSDrive -PSProvider FileSystem
Get-PSDrive C | Select-Object Used, Free
Key flags: -Name, -PSProvider, -Scope
Invoke-CimMethod [-ClassName] <string> [-MethodName] <string> [-Arguments <IDictionary>]
# Reboot remote computer
Invoke-CimMethod -ClassName Win32_OperatingSystem -MethodName Reboot
Key flags: -ClassName, -MethodName, -Arguments, -ComputerName, -InputObject
9. Registry Operations
▶PowerShell can navigate the Windows Registry like a file system using the HKLM: and HKCU: drives.
Get-ChildItem [-Path] <string>
Get-ChildItem HKLM:\Software
Get-ChildItem HKCU:\Software\Microsoft -Recurse
Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services"
Key flags: -Recurse, -Depth
Get-ItemProperty [-Path] <string> [[-Name] <string>]
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name ProgramFilesDir
(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").ReleaseId
Key flags: -Path, -Name
Set-ItemProperty [-Path] <string> [-Name] <string> [-Value] <object> [-Type <RegistryValueKind>]
Set-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Theme" -Value "Dark"
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies" -Name "Enabled" -Value 1 -Type DWord
Key flags: -Type: String, DWord, QWord, Binary, MultiString, ExpandString
New-Item [-Path] <string> [-Force]
New-Item -Path "HKCU:\Software\MyNewApp"
New-Item -Path "HKLM:\SOFTWARE\Policies\MyPolicy" -Force
Key flags: -Force (create parent keys as needed)
Remove-Item [-Path] <string> [-Recurse] [-Force]
Remove-Item -Path "HKCU:\Software\OldApp" -Recurse
Remove-ItemProperty -Path "HKCU:\Software\MyApp" -Name "OldValue"
Key flags: -Recurse (delete subkeys), -Force
Test-Path [-Path] <string>
Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion"
if (Test-Path "HKCU:\Software\MyApp") { "Key exists" }
New-ItemProperty [-Path] <string> [-Name] <string> [-Value] <object> [-PropertyType <string>]
New-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Version" -Value "1.0" -PropertyType String
New-ItemProperty -Path "HKLM:\SOFTWARE\Config" -Name "MaxRetries" -Value 3 -PropertyType DWord
Key flags: -PropertyType: String, DWord, QWord, Binary, MultiString, ExpandString
Copy-Item [-Path] <string> [-Destination] <string> [-Recurse]
Copy-Item -Path "HKCU:\Software\MyApp" -Destination "HKCU:\Software\MyApp_Backup" -Recurse
Key flags: -Recurse (include subkeys)
8. Network Commands
▶# Basic ping
Test-Connection google.com
Test-Connection 192.168.1.1 -Count 2 -Quiet # returns $true/$false
Test-Connection server01,server02 -Count 1 | Select-Object Address, Status
# TCP port test (more detailed than ping)
Test-NetConnection google.com -Port 443
Test-NetConnection 10.0.0.1 -Port 3389 -InformationLevel Detailed
Test-NetConnection server01 -TraceRoute
Resolve-DnsName google.com
Resolve-DnsName google.com -Type MX
Resolve-DnsName google.com -Type AAAA
Resolve-DnsName 8.8.8.8 -Type PTR # reverse lookup
Resolve-DnsName google.com -Server 1.1.1.1 # specific DNS server
Get-NetAdapter
Get-NetAdapter | Where-Object Status -eq Up
Get-NetAdapter -Physical | Select-Object Name, MacAddress, LinkSpeed
Get-NetIPAddress
Get-NetIPAddress -AddressFamily IPv4 | Where-Object IPAddress -notlike '169.*'
Get-NetIPAddress -InterfaceAlias Ethernet
Get-NetRoute -DestinationPrefix '0.0.0.0/0' # default gateway
Get-NetTCPConnection -State Established # like netstat
# Web requests
$r = Invoke-WebRequest https://example.com
$r.StatusCode
$r.Content
Invoke-WebRequest https://file.example.com/app.zip -OutFile app.zip
# REST APIs (auto-parses JSON/XML)
$resp = Invoke-RestMethod https://api.github.com/repos/microsoft/PowerShell
$resp.stargazers_count
# POST with JSON body
$body = @{name='Alice'; role='admin'} | ConvertTo-Json
Invoke-RestMethod https://api.example.com/users -Method POST -Body $body -ContentType 'application/json'
10. Variables & Data Types
▶$name = 'Alice'
$count = 42
$flag = $true
$nothing = $null
# Automatic variables
$PSScriptRoot # directory of the current script
$PSCommandPath # full path of the current script
$args # array of arguments passed to a script
$_ # current pipeline object
$Error[0] # most recent error
$nums = @(1, 2, 3, 4, 5)
$nums += 6 # adds element (creates new array)
$nums[0] # first element
$nums[-1] # last element
$nums[0..2] # slice: 1, 2, 3
$nums.Count
$nums | Where-Object { $_ -gt 3 }
# ArrayList for dynamic sizing
$list = [System.Collections.ArrayList]::new()
$list.Add('item') | Out-Null
$list.Remove('item')
$config = @{
Server = 'db01'
Port = 5432
DB = 'mydb'
}
$config.Server
$config['Port']
$config.Keys
$config.Values
$config.Remove('DB')
$config.ContainsKey('Server')
# Ordered hashtable
$ordered = [ordered]@{ A = 1; B = 2; C = 3 }
[int]'42'
[datetime]'2024-01-01'
[string]3.14
[bool]0 # $false
[bool]1 # $true
[array]$singleItem # wrap in array
# Common type checks
$x -is [int]
$x -isnot [string]
9. Registry Operations
▶PowerShell can navigate the Windows Registry like a file system using the HKLM: and HKCU: drives.
Get-ChildItem [-Path] <string>
Get-ChildItem HKLM:\Software
Get-ChildItem HKCU:\Software\Microsoft -Recurse
Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services"
Key flags: -Recurse, -Depth
Get-ItemProperty [-Path] <string> [[-Name] <string>]
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name ProgramFilesDir
(Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").ReleaseId
Key flags: -Path, -Name
Set-ItemProperty [-Path] <string> [-Name] <string> [-Value] <object> [-Type <RegistryValueKind>]
Set-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Theme" -Value "Dark"
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies" -Name "Enabled" -Value 1 -Type DWord
Key flags: -Type: String, DWord, QWord, Binary, MultiString, ExpandString
New-Item [-Path] <string> [-Force]
New-Item -Path "HKCU:\Software\MyNewApp"
New-Item -Path "HKLM:\SOFTWARE\Policies\MyPolicy" -Force
Key flags: -Force (create parent keys as needed)
Remove-Item [-Path] <string> [-Recurse] [-Force]
Remove-Item -Path "HKCU:\Software\OldApp" -Recurse
Remove-ItemProperty -Path "HKCU:\Software\MyApp" -Name "OldValue"
Key flags: -Recurse (delete subkeys), -Force
Test-Path [-Path] <string>
Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion"
if (Test-Path "HKCU:\Software\MyApp") { "Key exists" }
New-ItemProperty [-Path] <string> [-Name] <string> [-Value] <object> [-PropertyType <string>]
New-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Version" -Value "1.0" -PropertyType String
New-ItemProperty -Path "HKLM:\SOFTWARE\Config" -Name "MaxRetries" -Value 3 -PropertyType DWord
Key flags: -PropertyType: String, DWord, QWord, Binary, MultiString, ExpandString
Copy-Item [-Path] <string> [-Destination] <string> [-Recurse]
Copy-Item -Path "HKCU:\Software\MyApp" -Destination "HKCU:\Software\MyApp_Backup" -Recurse
Key flags: -Recurse (include subkeys)
11. String Manipulation
▶| Operation | Syntax / Example | Notes |
|---|---|---|
| Replace (regex) | 'abc123' -replace '\d+','NUM' | Use -creplace for case-sensitive |
| Split | 'a,b,c' -split ',' | Regex-capable; -csplit for case-sensitive |
| Join | 'a','b','c' -join ',' | Joins array to single string |
| Trim | ' hello '.Trim() | .TrimStart(), .TrimEnd() for one side |
| Upper/Lower | 'hello'.ToUpper() | Returns new string; original unchanged |
| Contains | 'PowerShell'.Contains('Shell') | Case-sensitive; use -like operator for wildcards |
| StartsWith | 'C:\Windows'.StartsWith('C:') | Add [StringComparison]::OrdinalIgnoreCase arg for case-insensitive |
| SubString | 'PowerShell'.Substring(5, 5) | Returns 'Shell' |
| IndexOf | 'hello'.IndexOf('l') | Returns 2; -1 if not found |
| Format | '{0} has {1} items' -f $name, $count | -f is the format operator |
| Interpolation | "Hello, $name!" | Use double quotes; single quotes are literal |
| Here-string | @" ... "@ | Multi-line string with interpolation; @' ... '@ for literal |
# Replace backslashes with forward slashes
'C:\path\file' -replace '\\','/'
# Extract filename without extension
[System.IO.Path]::GetFileNameWithoutExtension('C:\logs\app.log') # app
# Pad a string
'42'.PadLeft(6,'0') # 000042
# Split on multiple delimiters
'one,two;three' -split '[,;]'
# Multi-line string
$body = @"
Hello $name,
Your order of $count items is ready.
"@
13. Loops & Conditionals
▶$x = 15
if ($x -gt 20) {
'big'
} elseif ($x -gt 10) {
'medium'
} else {
'small'
}
# Comparison operators
# -eq -ne -gt -lt -ge -le (numbers and strings)
# -like 'wild*card' (wildcard match)
# -match 'regex' (regex match)
# -contains (array contains item)
# -in (item in array)
switch ($day) {
'Monday' { 'Start of week' }
'Friday' { 'End of week' }
default { 'Midweek' }
}
# Wildcard matching
switch -Wildcard ($file) {
'*.log' { 'Log file' }
'*.txt' { 'Text file' }
default { 'Other' }
}
# Regex matching
switch -Regex ($input) {
'^\d+' { 'Starts with number' }
'^[A-Z]' { 'Starts with uppercase' }
}
# for loop
for ($i = 0; $i -lt 10; $i++) { Write-Host $i }
# foreach (faster than ForEach-Object for local collections)
foreach ($file in Get-ChildItem C:\Logs) {
Write-Host $file.Name
}
foreach ($n in 1..10) { $n * $n }
# while (condition checked before first iteration)
$i = 0
while ($i -lt 5) { Write-Host $i; $i++ }
# do-while (runs at least once)
do {
$input = Read-Host 'Enter yes'
} while ($input -ne 'yes')
# Range operator
1..100 # array of 1 to 100
'a'..'z' # array of a to z
foreach ($i in 1..100) {
if ($i -eq 5) { break } # exit loop
if ($i % 2 -eq 0) { continue } # skip even
$i
}
# Break outer loop with label
:outer foreach ($a in 1..3) {
foreach ($b in 1..3) {
if ($b -eq 2) { break outer }
}
}
12. Pipelines & Filtering
▶The pipeline is PowerShell's superpower, passing objects between cmdlets for filtering, sorting, grouping, and transformation.
Where-Object [-Property] <string> [[-Value] <object>] [-EQ|-NE|-GT|-LT|-Like|-Match...]
Where-Object [-FilterScript] <scriptblock>
Get-Process | Where-Object CPU -gt 10
Get-Service | Where-Object Status -eq "Running"
Get-ChildItem | Where-Object { $_.Length -gt 1MB -and $_.Extension -eq ".log" }
Key flags: Comparison: -eq, -ne, -gt, -lt, -ge, -le, -like, -match, -in, -contains
Select-Object [[-Property] <object[]>] [-First <int>] [-Last <int>] [-Unique] [-ExpandProperty <string>]
Get-Process | Select-Object Name, CPU, WorkingSet
Get-Process | Select-Object -First 5
Get-ChildItem | Select-Object -ExpandProperty Name
Get-Service | Select-Object -Unique Status
Key flags: -First, -Last, -Skip, -Unique, -ExpandProperty
Sort-Object [[-Property] <object[]>] [-Descending] [-Unique]
Get-Process | Sort-Object CPU -Descending
Get-ChildItem | Sort-Object Length
Get-Process | Sort-Object Name, CPU -Descending
Key flags: -Descending, -Unique (remove duplicates), -Property (supports multiple)
ForEach-Object [-Process] <scriptblock> [-Begin <scriptblock>] [-End <scriptblock>]
Get-Service | ForEach-Object { $_.Name + ": " + $_.Status }
1..5 | ForEach-Object { $_ * 2 }
Get-Process | ForEach-Object -Begin { $total=0 } -Process { $total+=$_.CPU } -End { $total }
Key flags: $_ is the current object; -Begin / -End run once before/after pipeline
Group-Object [[-Property] <object[]>] [-NoElement] [-AsHashTable]
Get-Process | Group-Object Company
Get-Service | Group-Object Status | Select-Object Name, Count
Get-ChildItem | Group-Object Extension | Sort-Object Count -Descending
Key flags: -NoElement (count only), -AsHashTable (return hashtable)
Measure-Object [[-Property] <string[]>] [-Sum] [-Average] [-Minimum] [-Maximum] [-Count]
Get-Process | Measure-Object CPU -Sum -Average -Maximum
Get-ChildItem | Measure-Object Length -Sum
"Hello World" | Measure-Object -Word -Character
Key flags: -Sum, -Average, -Minimum, -Maximum, -Word, -Line, -Character
Compare-Object [-ReferenceObject] <object[]> [-DifferenceObject] <object[]> [-Property <object[]>] [-IncludeEqual]
Compare-Object (Get-Content file1.txt) (Get-Content file2.txt)
Compare-Object $list1 $list2 -Property Name
Compare-Object $before $after -IncludeEqual
Key flags: -Property, -IncludeEqual, -ExcludeDifferent, -PassThru
Select-String [-Pattern] <string[]> [-Path <string[]>] [-CaseSensitive] [-NotMatch] [-List]
Select-String -Pattern "error" -Path *.log
Get-Content app.log | Select-String "WARN|ERROR"
Select-String "192\.168\." -Path *.txt -CaseSensitive
Key flags: -Pattern (regex), -CaseSensitive, -NotMatch, -SimpleMatch, -List
Tee-Object [-FilePath] <string> | [-Variable <string>] [-Append]
Get-Process | Tee-Object -FilePath procs.txt | Where-Object CPU -gt 5
Get-Service | Tee-Object -Variable services | Measure-Object
Key flags: -FilePath, -Variable (no $), -Append
Out-GridView [-Title <string>] [-PassThru] [-OutputMode <OutputModeOption>]
Get-Process | Out-GridView
Get-Service | Out-GridView -Title "Services" -PassThru | Stop-Service
Get-HotFix | Out-GridView -OutputMode Multiple
Key flags: -PassThru (return selected rows), -OutputMode: None, Single, Multiple
14. Functions & Scripts
▶# Simple function
function Get-Greeting {
param([string]$Name = 'World')
"Hello, $Name!"
}
Get-Greeting -Name Alice
# Advanced function with CmdletBinding
function Remove-TempFiles {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory)][string]$Path,
[int]$OlderThanDays = 7
)
process {
if ($PSCmdlet.ShouldProcess($Path, 'Delete')) {
Remove-Item $Path -Recurse -Force
}
}
}
Remove-TempFiles -Path C:\Temp -WhatIf # -WhatIf works automatically
function Connect-Server {
[CmdletBinding()]
param(
[Parameter(Mandatory, HelpMessage='Server hostname or IP')]
[string]$Server,
[Parameter(ValueFromPipeline)]
[int]$Port = 443,
[switch]$UseSSL,
[ValidateSet('dev','staging','prod')]
[string]$Environment = 'prod',
[ValidateRange(1,65535)]
[int]$Timeout = 30
)
process {
Write-Verbose "Connecting to $Server:$Port"
}
}
function Show-Name {
param([Parameter(ValueFromPipeline)][string]$Name)
process { "Name: $Name" }
}
'Alice','Bob' | Show-Name
# Full begin/process/end structure
function Measure-Items {
[CmdletBinding()]
param([Parameter(ValueFromPipeline)]$Item)
begin { $count = 0 }
process { $count++ }
end { "Total: $count" }
}
Get-Process | Measure-Items
# Dot-source: load functions into current scope
. ./functions.ps1
. C:\Scripts\Connect-DB.ps1
# Connect-DB is now available in this session
# Call operator: run in child scope (variables don't persist)
& ./script.ps1
# Reliable path resolution in scripts
$configPath = Join-Path $PSScriptRoot 'config.json'
$logPath = Join-Path $PSScriptRoot 'logs' 'app.log'
15. Error Handling
▶Key Concept
PowerShell has two types of errors: terminating (throw exceptions, catchable) and non-terminating (write to error stream, execution continues). Most cmdlet errors are non-terminating by default. Use -ErrorAction Stop to make them catchable.
try {
Get-Item 'C:\nonexistent.txt' -ErrorAction Stop # -EA Stop required!
} catch [System.IO.FileNotFoundException] {
Write-Warning "File not found: $_"
} catch [System.UnauthorizedAccessException] {
Write-Warning "Access denied"
} catch {
Write-Error "Unexpected error: $($_.Exception.Message)"
} finally {
Write-Host 'This always runs (cleanup here)'
}
# Per-cmdlet error handling
Get-Item 'missing.txt' -ErrorAction SilentlyContinue # suppress error, continue
Get-Process 'noexist' -ErrorAction Stop # make error terminating
Get-Service -ErrorAction Ignore # ignore completely
# Script-wide setting (at top of script)
$ErrorActionPreference = 'Stop' # all errors become terminating
# All subsequent errors will throw
# $Error automatic array
$Error[0] # most recent error
$Error[0].Exception.Message # error message
$Error[0].InvocationInfo.Line # line that caused error
$Error.Clear() # clear error history
# Common shorthand
$EA = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
# ... code ...
$ErrorActionPreference = $EA # restore
Write-Error 'Something went wrong'
Write-Error -Message 'File not found' -Category ObjectNotFound
Write-Warning 'This is a warning'
Write-Verbose 'Debug info' # only shown with -Verbose flag or $VerbosePreference = 'Continue'
Write-Debug 'Debug detail' # only shown with -Debug flag
18. Event Logs
▶Query, filter, and write to Windows Event Logs using PowerShell cmdlets.
Get-EventLog [-LogName] <string> [-Newest <int>] [-EntryType <string[]>] [-Source <string[]>] [-After <datetime>] [-Before <datetime>]
Get-EventLog -LogName System -Newest 50
Get-EventLog -LogName Application -EntryType Error -Newest 20
Get-EventLog -LogName System -After (Get-Date).AddDays(-7)
Key flags: -LogName, -Newest, -EntryType: Error, Warning, Information, -Source, -After, -Before
Get-WinEvent [-LogName] <string[]> [-MaxEvents <int64>] [-FilterHashtable <hashtable>] [-ComputerName <string>]
Get-WinEvent -LogName System -MaxEvents 50
Get-WinEvent -FilterHashtable @{LogName="System"; Level=2; StartTime=(Get-Date).AddDays(-1)}
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4624} -MaxEvents 10
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational"
Key flags: -FilterHashtable: LogName, Level (1=Critical,2=Error,3=Warning,4=Info), Id, StartTime, EndTime, ProviderName
Clear-EventLog [-LogName] <string[]> [-ComputerName <string[]>]
Clear-EventLog -LogName Application
Clear-EventLog -LogName Application, System -ComputerName Server01
Key flags: -LogName, -ComputerName
Write-EventLog [-LogName] <string> [-Source] <string> [-EventId] <int> [-Message] <string> [-EntryType <EventLogEntryType>]
Write-EventLog -LogName Application -Source "MyScript" -EventId 1000 -Message "Backup completed" -EntryType Information
Write-EventLog -LogName Application -Source "MyScript" -EventId 9001 -Message "Error occurred" -EntryType Error
Key flags: -EntryType: Error, Warning, Information, SuccessAudit, FailureAudit. Source must be registered first.
New-EventLog [-LogName] <string> [-Source] <string[]> [-ComputerName <string[]>]
New-EventLog -LogName "MyApplication" -Source "MyScript"
Key flags: Must be run as Administrator. Creates the log and registers the source for Write-EventLog.
Get-WinEvent -FilterHashtable @{Key=Value; ...}
# All errors in last 24 hours across System and Application logs
Get-WinEvent -FilterHashtable @{LogName="System","Application"; Level=2; StartTime=(Get-Date).AddHours(-24)}
# Specific event ID (e.g. successful logon)
Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4624} | Select -First 20 | Format-List TimeCreated, Message
# By provider name
Get-WinEvent -FilterHashtable @{ProviderName="Microsoft-Windows-WindowsUpdateClient"; Id=19}
Key flags: Keys: LogName, Level, Id, StartTime, EndTime, ProviderName, Keywords, UserID
Limit-EventLog [-LogName] <string[]> [-MaximumSize <int64>] [-RetentionDays <int>] [-OverflowAction <OverflowAction>]
Limit-EventLog -LogName Application -MaximumSize 64MB
Limit-EventLog -LogName System -OverflowAction OverwriteAsNeeded
Key flags: -MaximumSize, -RetentionDays, -OverflowAction: DoNotOverwrite, OverwriteAsNeeded, OverwriteOlder
19. Security & Permissions
▶Manage file/folder ACLs, script execution policies, credentials, and security contexts.
Get-Acl [-Path] <string[]>
Get-Acl C:\Sensitive
Get-Acl C:\Sensitive | Format-List
Get-Acl HKLM:\SOFTWARE\MyApp
(Get-Acl C:\Sensitive).Access | Format-Table
Key flags: Works with file system, registry, and other providers. .Access property contains ACEs (access control entries).
Set-Acl [-Path] <string[]> [-AclObject] <object>
$acl = Get-Acl C:\Folder
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Domain\User","FullControl","Allow")
$acl.SetAccessRule($rule)
Set-Acl -Path C:\Folder -AclObject $acl
Key flags: Typically used with Get-Acl to copy ACL from another object, or with New-Object to build custom rules.
Get-ExecutionPolicy [-Scope <ExecutionPolicyScope>] [-List]
Get-ExecutionPolicy
Get-ExecutionPolicy -List
Get-ExecutionPolicy -Scope CurrentUser
Key flags: Scopes: MachinePolicy, UserPolicy, Process, CurrentUser, LocalMachine
Set-ExecutionPolicy [-ExecutionPolicy] <ExecutionPolicy> [-Scope <ExecutionPolicyScope>] [-Force]
Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy Bypass -Scope Process -Force
Set-ExecutionPolicy Restricted -Scope CurrentUser
Key flags: Policies: Restricted, AllSigned, RemoteSigned, Unrestricted, Bypass. Requires elevation for LocalMachine scope.
Get-Credential [[-Credential] <pscredential>] [-Message <string>] [-UserName <string>]
$cred = Get-Credential
$cred = Get-Credential -UserName "DOMAIN\Admin" -Message "Enter admin credentials"
Invoke-Command -ComputerName Server01 -Credential $cred -ScriptBlock { Get-Process }
Key flags: Returns a [PSCredential] object. Password is stored as a [SecureString].
ConvertTo-SecureString [-String] <string> [-AsPlainText] [-Force]
$secure = ConvertTo-SecureString "MyPassword123" -AsPlainText -Force
$cred = New-Object PSCredential ("user@domain.com", $secure)
# From encrypted standard string (same user/machine only):
$encrypted = "01000000..." | ConvertTo-SecureString
Key flags: -AsPlainText -Force required for plain text input
New-LocalUser [-Name] <string> [-Password <SecureString>] [-Description <string>] [-FullName <string>]
$password = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
New-LocalUser -Name "svcaccount" -Password $password -Description "Service account" -PasswordNeverExpires
Key flags: -PasswordNeverExpires, -UserMayNotChangePassword, -AccountNeverExpires
Get-LocalUser [[-Name] <string[]>]
Get-LocalGroup [[-Name] <string[]>]
Get-LocalUser
Get-LocalUser -Name "Administrator"
Get-LocalGroup
Get-LocalGroupMember -Group "Administrators"
Key flags: Works on Windows only. For domain accounts, use Active Directory module cmdlets.
20. PowerShell Remoting
▶# Single remote command
Invoke-Command -ComputerName server01 -ScriptBlock { Get-Process }
# Multiple computers
Invoke-Command -ComputerName server01,server02,server03 -ScriptBlock {
Get-Service Spooler | Select-Object Name, Status
}
# With credentials
$cred = Get-Credential
Invoke-Command -ComputerName server01 -Credential $cred -ScriptBlock { whoami }
# Pass local variables using $using:
$path = 'C:\Logs'
Invoke-Command -ComputerName server01 -ScriptBlock { Get-ChildItem $using:path }
# Run a local script on remote machines
Invoke-Command -ComputerName server01 -FilePath C:\Scripts\deploy.ps1
# Interactive remote session
Enter-PSSession -ComputerName server01
# You are now inside server01's PowerShell
Exit-PSSession
# Persistent session (reuse for multiple commands)
$s = New-PSSession -ComputerName server01
Invoke-Command -Session $s -ScriptBlock { ... do remote work ... }
Invoke-Command -Session $s -ScriptBlock { ... more work ... }
Remove-PSSession $s
# Copy files to/from remote machines
Copy-Item C:\file.txt -Destination C:\remote\ -ToSession $s
Copy-Item C:\remote\file.txt -Destination C:\ -FromSession $s
16. Output & Formatting
▶Control how output is displayed, formatted, and written to files or streams.
Format-Table [[-Property] <object[]>] [-AutoSize] [-Wrap] [-GroupBy <object>]
Get-Process | Format-Table Name, CPU, WorkingSet -AutoSize
Get-Service | Format-Table -Property Name, Status, StartType -Wrap
Get-Process | Format-Table -GroupBy Company
Key flags: -AutoSize (fit columns), -Wrap (wrap long values), -GroupBy
Format-List [[-Property] <object[]>]
Get-Process -Name chrome | Format-List *
Get-Service bits | Format-List Name, Status, Description
Get-Error | Format-List -Force
Key flags: * shows all properties; -Force expands hidden properties
Format-Wide [[-Property] <object>] [-Column <int>] [-AutoSize]
Get-Process | Format-Wide Name -Column 4
Get-Command | Format-Wide -AutoSize
Key flags: -Column, -AutoSize
Out-File [-FilePath] <string> [-Encoding <Encoding>] [-Append] [-Width <int>] [-Force]
Get-Process | Out-File processes.txt
Get-Service | Out-File -FilePath services.txt -Append
Get-Process | Format-Table | Out-File report.txt -Width 200
Key flags: -Append, -Encoding (UTF8, ASCII, Unicode), -Width (line width), -Force
ConvertTo-Csv [-InputObject] <psobject> [-Delimiter <char>] [-NoTypeInformation]
Get-Process | ConvertTo-Csv -NoTypeInformation
Get-Service | ConvertTo-Csv -Delimiter ";" | Out-File services.csv
Key flags: -NoTypeInformation (omit type header), -Delimiter
ConvertTo-Json [-InputObject] <object> [-Depth <int>] [-Compress]
Get-Process | Select Name,CPU | ConvertTo-Json
Get-ComputerInfo | ConvertTo-Json -Depth 3
@{Name="Alice";Age=30} | ConvertTo-Json -Compress
Key flags: -Depth (default 2 — increase for nested objects), -Compress (no whitespace)
ConvertTo-Html [[-Property] <object[]>] [-Title <string>] [-Head <string[]>] [-Body <string[]>]
Get-Process | ConvertTo-Html -Title "Process Report" | Out-File report.html
Get-Service | Select Name,Status | ConvertTo-Html -Property Name,Status
Key flags: -Title, -Head (HTML head content), -Body (additional body content)
Write-Output [-InputObject] <psobject[]> [-NoEnumerate]
Write-Output "Hello World"
Write-Output $processlist
1,2,3 | Write-Output
Key flags: -NoEnumerate (pass arrays as single object rather than enumerating elements)
Write-Host [-Object] <object> [-ForegroundColor <ConsoleColor>] [-BackgroundColor <ConsoleColor>] [-NoNewline]
Write-Host "Starting process..." -ForegroundColor Green
Write-Host "Error: " -ForegroundColor Red -NoNewline; Write-Host $error
Write-Host "Progress: $i%" -NoNewline
Key flags: -ForegroundColor/-BackgroundColor: Red, Green, Yellow, Blue, Cyan, Magenta, White, Gray, etc.
Write-Verbose [-Message] <string>
Write-Debug [-Message] <string>
Write-Warning [-Message] <string>
Write-Verbose "Connecting to server..." -Verbose
Write-Debug "Variable value: $x"
Write-Warning "File not found — using default"
Key flags: Verbose messages shown when -Verbose switch used or $VerbosePreference = "Continue"
21. Modules & Packages
▶PowerShell modules package cmdlets, functions, and providers. PowerShellGet provides online module management.
Get-Module [[-Name] <string[]>] [-ListAvailable] [-All]
Get-Module
Get-Module -ListAvailable
Get-Module -Name ActiveDirectory -ListAvailable
Get-Module | Select-Object Name, Version, ExportedCommands
Key flags: -ListAvailable (all installed, not just imported), -All (include hidden modules)
Import-Module [-Name] <string[]> [-Force] [-PassThru] [-Version <version>]
Import-Module ActiveDirectory
Import-Module -Name Pester -Force
Import-Module Az -Version 9.0.0
Key flags: -Force (reimport if already loaded), -PassThru (return module object), -Version
Find-Module [[-Name] <string[]>] [-Repository <string[]>] [-Tag <string[]>] [-MinimumVersion <version>]
Find-Module -Name PSReadLine
Find-Module -Tag "ActiveDirectory"
Find-Module -Name Az* | Sort-Object Name
Key flags: -Repository, -Tag, -MinimumVersion, -MaximumVersion
Install-Module [-Name] <string[]> [-Scope <string>] [-Force] [-AllowClobber] [-Repository <string>]
Install-Module -Name PSReadLine -Scope CurrentUser
Install-Module -Name Az -AllowClobber -Force
Install-Module -Name Pester -MinimumVersion 5.0 -Scope CurrentUser
Key flags: -Scope: AllUsers (requires elevation) or CurrentUser; -AllowClobber (allow overwriting commands)
Update-Module [[-Name] <string[]>] [-Force] [-RequiredVersion <version>]
Update-Module -Name PSReadLine
Update-Module -Force
Update-Module -Name Az -RequiredVersion 10.0.0
Key flags: -Force (bypass version checks), -RequiredVersion
Uninstall-Module [-Name] <string[]> [-AllVersions] [-RequiredVersion <version>]
Uninstall-Module -Name OldModule -AllVersions
Uninstall-Module -Name Az -RequiredVersion 9.0.0
Key flags: -AllVersions, -RequiredVersion, -Force
Register-PSRepository [-Name] <string> [-SourceLocation] <uri> [-InstallationPolicy <string>]
Register-PSRepository -Name "MyRepo" -SourceLocation "https://my.repo.com/api/v2" -InstallationPolicy Trusted
Register-PSRepository -Default # Re-register PSGallery
Key flags: -InstallationPolicy: Trusted or Untrusted
Save-Module [-Name] <string[]> [-Path] <string> [-Repository <string>]
Save-Module -Name Az -Path "C:\ModuleCache"
Save-Module -Name Pester -Path .\offline-modules
Key flags: Useful for offline environments — copy to a machine without internet access and import directly.
24. Math & Numbers
▶PowerShell supports standard arithmetic operators and exposes .NET Math functions for advanced calculations.
$a + $b # Addition
$a - $b # Subtraction
$a * $b # Multiplication
$a / $b # Division
$a % $b # Modulo (remainder)
$a -shl 2 # Bitwise shift left
$a -shr 2 # Bitwise shift right
10 + 3 # 13
10 - 3 # 7
10 * 3 # 30
10 / 3 # 3.33333...
10 % 3 # 1 (remainder)
[int]10 / 3 # 3 (integer division)
1KB, 1MB, 1GB # Built-in byte multipliers: 1024, 1048576, etc.
[Math]::MethodName(args)
[Math]::Round(3.14159, 2) # 3.14
[Math]::Abs(-42) # 42
[Math]::Sqrt(144) # 12
[Math]::Pow(2, 10) # 1024
[Math]::Floor(3.9) # 3
[Math]::Ceiling(3.1) # 4
[Math]::Log(100, 10) # 2 (log base 10)
[Math]::PI # 3.14159265358979
[Math]::Max(10, 20) # 20
[Math]::Min(10, 20) # 10
Measure-Object [[-Property] <string[]>] [-Sum] [-Average] [-Minimum] [-Maximum] [-StandardDeviation]
1..100 | Measure-Object -Sum -Average
Get-Process | Measure-Object CPU -Sum -Average -Maximum -Minimum
Get-ChildItem C:\Logs | Measure-Object Length -Sum | Select @{N="Total MB";E={$_.Sum/1MB}}
Key flags: -Sum, -Average, -Minimum, -Maximum, -StandardDeviation (PS 6+)
$a -band $b # Bitwise AND
$a -bor $b # Bitwise OR
$a -bxor $b # Bitwise XOR
-bnot $a # Bitwise NOT
0xFF -band 0x0F # 15 (0x0F)
0x0F -bor 0xF0 # 255 (0xFF)
0xFF -bxor 0x0F # 240 (0xF0)
-bnot 0 # -1 (all bits set)
# Check if bit 3 is set:
$flags -band 0x04 # Non-zero if bit 3 set
"{0:format}" -f $number
$number.ToString("format")
"{0:N2}" -f 1234567.891 # 1,234,567.89 (two decimal places, grouped)
"{0:C2}" -f 99.5 # £99.50 or $99.50 (currency, locale-dependent)
"{0:P1}" -f 0.753 # 75.3%
"{0:X}" -f 255 # FF (hexadecimal)
"{0:B}" -f 10 # 1010 (binary — PS 7+ only)
"{0:E2}" -f 0.000123 # 1.23E-004 (scientific notation)
Get-Random [[-Maximum] <object>] [-Minimum <object>] [-Count <int>]
Get-Random # Random int32
Get-Random -Maximum 100 # 0–99
Get-Random -Minimum 1 -Maximum 7 # 1–6 (dice roll)
Get-Random -Count 5 -InputObject (1..50) # 5 unique random from 1–50
1..10 | Get-Random -Count 3 # 3 random items from array
Key flags: -Minimum, -Maximum, -Count, -InputObject, -SetSeed (for reproducibility)
[type]$value
[int]3.7 # 4 (rounds to nearest even)
[int]"42" # 42 (parse from string)
[double]10/3 # 3.33333333333333
[decimal]1.1 + [decimal]2.2 # 3.3 exactly (vs. float rounding)
[int64]::MaxValue # 9223372036854775807
0x1F # 31 (hex literal)
[convert]::ToString(255, 16) # "ff" — convert to hex string
[Math]::Round($number, $digits, [System.MidpointRounding]::Mode)
[Math]::Round(2.5, 0, [MidpointRounding]::AwayFromZero) # 3
[Math]::Round(2.5, 0, [MidpointRounding]::ToEven) # 2 (banker's rounding — default!)
[Math]::Round(3.5, 0, [MidpointRounding]::AwayFromZero) # 4
# Note: [int]2.5 uses ToEven by default: (int)2.5 = 2
Key flags: AwayFromZero = traditional rounding; ToEven = banker's rounding (default in .NET)
25. Aliases & Profiles
▶Set-Alias -Name ll -Value Get-ChildItem
Set-Alias -Name grep -Value Select-String
Set-Alias -Name which -Value Get-Command
Get-Alias
Get-Alias ls # find what ls maps to
Get-Alias -Definition Get-ChildItem # find aliases for a cmdlet
# Profile locations
$PROFILE # current user, current host
$PROFILE.CurrentUserAllHosts # all hosts (ISE, VS Code, etc.)
$PROFILE.AllUsersCurrentHost # all users, current host
# Create profile if it doesn't exist
if (-not (Test-Path $PROFILE)) {
New-Item $PROFILE -ItemType File -Force
}
# Open profile for editing
notepad $PROFILE
code $PROFILE # VS Code
# Example profile contents
function prompt { "PS [$env:COMPUTERNAME] $(Get-Location)> " }
Set-Alias ll Get-ChildItem
$env:PATH += ';C:\MyTools'
Import-Module posh-git
Set-PSReadLineOption -PredictionSource History
# Read
$env:PATH
$env:USERPROFILE
$env:COMPUTERNAME
# Set (current session only)
$env:MY_VAR = 'value'
# Persistent PATH update
[Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\MyTool', 'User')
[Environment]::SetEnvironmentVariable('PATH', $env:PATH + ';C:\MyTool', 'Machine') # requires admin
# List all env vars
Get-ChildItem Env:
22. Environment Variables
▶Environment variables store configuration for the OS and processes. PowerShell exposes them via the Env: drive and $env: notation.
$env:VARNAME
$env:PATH
$env:COMPUTERNAME
$env:USERNAME
$env:USERPROFILE
$env:TEMP
$env:SystemRoot
Key flags: Read-only in this form — use assignment to change. Case-insensitive on Windows.
$env:VARNAME = "value"
$env:MY_APP_CONFIG = "C:\Config\app.json"
$env:PATH += ";C:\Tools" # Append to PATH
$env:DEBUG = "true"
Key flags: Changes persist only for the current session. To persist, use [System.Environment]::SetEnvironmentVariable()
Get-ChildItem Env:
Get-ChildItem Env: | Where-Object Name -like "APP_*"
Get-ChildItem Env:
Get-ChildItem Env: | Sort-Object Name
Get-ChildItem Env: | Where-Object Value -like "*System32*"
Key flags: The Env: drive exposes environment variables like a file system.
[System.Environment]::SetEnvironmentVariable("Name", "Value", "Scope")
[System.Environment]::SetEnvironmentVariable("MY_VAR", "Hello", "User")
[System.Environment]::SetEnvironmentVariable("MY_VAR", "Hello", "Machine") # Requires elevation
[System.Environment]::SetEnvironmentVariable("TEMP_VAR", $null, "User") # Delete by setting to $null
Key flags: Scopes: Process (current session), User (HKCU), Machine (HKLM — requires admin)
[System.Environment]::GetEnvironmentVariable("Name", "Scope")
[System.Environment]::GetEnvironmentVariable("PATH", "Machine")
[System.Environment]::GetEnvironmentVariable("PATH", "User")
Key flags: Useful for reading the persistent value independent of current session overrides.
Remove-Item Env:\VARNAME
Remove-Item Env:\MY_TEMP_VAR
Remove-Item Env:\DEBUG -ErrorAction SilentlyContinue
Key flags: Removes from the current session only. For persistent removal, use [System.Environment]::SetEnvironmentVariable with $null value.
17. Scheduled Tasks
▶PowerShell provides full cmdlets for creating, managing, and querying Windows Task Scheduler entries.
Get-ScheduledTask [[-TaskName] <string[]>] [-TaskPath <string[]>]
Get-ScheduledTask
Get-ScheduledTask -TaskName "WindowsUpdate"
Get-ScheduledTask -TaskPath "\Microsoft\Windows\"
Get-ScheduledTask | Where-Object State -eq "Running"
Key flags: -TaskName, -TaskPath (folder in Task Scheduler)
Register-ScheduledTask [-TaskName] <string> -Action <CimInstance[]> -Trigger <CimInstance[]> [-Principal <CimInstance>] [-Settings <CimInstance>]
$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\backup.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At 2am
Register-ScheduledTask -TaskName "DailyBackup" -Action $action -Trigger $trigger -RunLevel Highest
Key flags: -RunLevel: Limited, Highest; -Force (overwrite existing)
New-ScheduledTaskAction [-Execute] <string> [[-Argument] <string>] [[-WorkingDirectory] <string>]
New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-NonInteractive -File C:\script.ps1"
New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c cleanup.bat" -WorkingDirectory "C:\Tools"
Key flags: -Execute, -Argument, -WorkingDirectory
New-ScheduledTaskTrigger [-Once|-Daily|-Weekly|-AtStartup|-AtLogOn] [-At <datetime>] [-RepetitionInterval <timespan>]
New-ScheduledTaskTrigger -Daily -At "3:00AM"
New-ScheduledTaskTrigger -Weekly -WeeksInterval 1 -DaysOfWeek Monday -At "9:00AM"
New-ScheduledTaskTrigger -AtStartup
New-ScheduledTaskTrigger -Once -At "2025-01-01 00:00"
Key flags: -Once, -Daily, -Weekly, -AtStartup, -AtLogOn, -RepetitionInterval
Start-ScheduledTask [-TaskName] <string> [-TaskPath <string>]
Start-ScheduledTask -TaskName "DailyBackup"
Get-ScheduledTask -TaskName "DailyBackup" | Start-ScheduledTask
Key flags: -TaskName, -TaskPath
Unregister-ScheduledTask [-TaskName] <string[]> [-Confirm:$false]
Unregister-ScheduledTask -TaskName "OldTask" -Confirm:$false
Get-ScheduledTask -TaskPath "\MyTasks\" | Unregister-ScheduledTask -Confirm:$false
Key flags: -Confirm:$false (suppress confirmation prompt)
Set-ScheduledTask [-TaskName] <string> [-Action <CimInstance[]>] [-Trigger <CimInstance[]>] [-Settings <CimInstance>]
$newTrigger = New-ScheduledTaskTrigger -Daily -At 4am
Set-ScheduledTask -TaskName "DailyBackup" -Trigger $newTrigger
Key flags: -Action, -Trigger, -Settings, -Principal
23. Date & Time
▶PowerShell provides rich date and time capabilities through Get-Date and the .NET DateTime class.
Get-Date [[-Date] <datetime>] [-Format <string>] [-UFormat <string>] [-Year/-Month/-Day/-Hour/-Minute/-Second]
Get-Date
Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Get-Date -UFormat "%Y-%m-%d"
Get-Date -Year 2025 -Month 1 -Day 1 # Specific date
Get-Date | Select-Object Year, Month, Day, DayOfWeek
Key flags: -Format (standard .NET format strings), -UFormat (Unix-style format)
(Get-Date).AddDays(n)
(Get-Date).AddHours(n)
(Get-Date).AddMonths(n)
(Get-Date).AddDays(30) # 30 days from now
(Get-Date).AddDays(-7) # 7 days ago
(Get-Date).AddHours(-24) # 24 hours ago
(Get-Date "2025-01-01").AddMonths(6) # 6 months after a specific date
# Difference between dates:
$diff = (Get-Date) - (Get-Date "2024-01-01")
$diff.Days # Number of days between
[datetime]::Parse("date string")
[datetime]::Parse("2025-03-15")
[datetime]::Parse("15 March 2025")
[datetime]::ParseExact("15/03/2025", "dd/MM/yyyy", $null)
$date = [datetime]"2025-06-01" # Implicit cast also works
Key flags: Use ParseExact when the format is ambiguous (e.g. 01/02/2025 — day or month first?)
$date1 -lt $date2
$date1 -gt $date2
$date1 -eq $date2
$cutoff = (Get-Date).AddDays(-30)
Get-ChildItem C:\Logs | Where-Object LastWriteTime -lt $cutoff
Get-EventLog System -After (Get-Date).AddHours(-24)
if ((Get-Date) -gt [datetime]"2025-12-31") { "Year has ended" }
Get-Date -Format "format string"
Get-Date -Format "yyyy-MM-dd" # 2025-03-15
Get-Date -Format "dd/MM/yyyy HH:mm" # 15/03/2025 14:30
Get-Date -Format "dddd, dd MMMM yyyy" # Saturday, 15 March 2025
Get-Date -Format "yyyyMMdd_HHmmss" # Useful for filenames: 20250315_143022
Get-Date -UFormat "%s" # Unix timestamp (seconds since epoch)
Key flags: Common tokens: yyyy (year), MM (month), dd (day), HH (24h hour), mm (minute), ss (second), ddd (short day name)
[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($date, "Zone ID")
[System.TimeZoneInfo]::GetSystemTimeZones() | Select Id, DisplayName
$utc = [System.TimeZoneInfo]::ConvertTimeToUtc((Get-Date))
[System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), "Eastern Standard Time")
Key flags: Use Get-TimeZone for current machine time zone info.
New-TimeSpan [-Days <int>] [-Hours <int>] [-Minutes <int>] [-Seconds <int>]
New-TimeSpan [-Start <datetime>] [-End <datetime>]
$span = New-TimeSpan -Hours 2 -Minutes 30
$span.TotalMinutes # 150
$elapsed = New-TimeSpan -Start $startTime -End (Get-Date)
$elapsed.TotalSeconds