PowerShell has revolutionized system administration and automation on Windows, Linux, and macOS. Understanding its three fundamental concepts—cmdlets, modules, and the pipeline—is essential for anyone looking to harness the full power of this command-line shell and scripting language.
This comprehensive guide breaks down each concept with detailed explanations, real-world examples, and visual diagrams to help you build a solid foundation in PowerShell.
What Are Cmdlets?
Cmdlets (pronounced “command-lets”) are specialized .NET classes that perform specific actions in PowerShell. Unlike traditional command-line tools that return text, cmdlets work with objects, making data manipulation more powerful and flexible.
Cmdlet Naming Convention
Every cmdlet follows the Verb-Noun naming convention, making them intuitive and predictable. The verb describes the action, and the noun specifies what the action affects.
Get-Process # Retrieves running processes
Set-Location # Changes the current directory
New-Item # Creates a new item
Remove-Service # Removes a service
Common PowerShell Verbs
PowerShell uses approved verbs to maintain consistency across cmdlets:
- Get – Retrieves data or resources
- Set – Modifies or establishes data
- New – Creates new resources
- Remove – Deletes resources
- Start – Initiates an operation
- Stop – Terminates an operation
- Out – Sends data to a destination
- Write – Adds information to a target
Cmdlet Parameters
Parameters refine cmdlet behavior and specify additional information. They use a dash (-) prefix followed by the parameter name.
# Basic cmdlet with parameter
Get-Process -Name "chrome"
# Multiple parameters
Get-ChildItem -Path "C:\Windows" -Filter "*.log" -Recurse
# Parameter values with spaces need quotes
Set-Location -Path "C:\Program Files"
Output:
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
463 32 89564 124532 15.42 7856 1 chrome
351 25 65432 98765 8.21 8924 1 chrome
287 19 45678 76543 4.56 9012 1 chrome
Common Parameters
Some parameters are available across many cmdlets:
# -WhatIf shows what would happen without executing
Remove-Item -Path "test.txt" -WhatIf
# -Confirm prompts for confirmation
Stop-Process -Name "notepad" -Confirm
# -Verbose displays detailed operation information
Copy-Item -Path "source.txt" -Destination "dest.txt" -Verbose
Discovering Cmdlets
PowerShell provides built-in cmdlets to explore available commands:
# List all cmdlets
Get-Command -CommandType Cmdlet
# Find cmdlets with specific verb
Get-Command -Verb Get
# Find cmdlets with specific noun
Get-Command -Noun Process
# Search for cmdlets by pattern
Get-Command *Service*
Getting Help
The help system is your best friend when learning cmdlets:
# View help for a cmdlet
Get-Help Get-Process
# Detailed help with examples
Get-Help Get-Process -Detailed
# Show only examples
Get-Help Get-Process -Examples
# Online help in browser
Get-Help Get-Process -Online
# Update help files
Update-Help
Understanding Modules
Modules are packages that bundle related cmdlets, functions, variables, and other resources together. They enable code reusability and organization, similar to libraries in programming languages.
Types of Modules
PowerShell supports several module types:
- Script Modules (.psm1) – Written in PowerShell script
- Binary Modules (.dll) – Compiled .NET assemblies
- Manifest Modules (.psd1) – Describe module contents and metadata
- Dynamic Modules – Created in memory during runtime
Working with Modules
# List all available modules
Get-Module -ListAvailable
# Import a module
Import-Module ActiveDirectory
# View imported modules
Get-Module
# List cmdlets in a module
Get-Command -Module ActiveDirectory
# Remove a module from session
Remove-Module ActiveDirectory
Output of Get-Module -ListAvailable:
Directory: C:\Program Files\WindowsPowerShell\Modules
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 1.0.0.0 ActiveDirectory {Add-ADCentralAcc...
Script 2.0.0 Az.Accounts {Add-AzEnvironmen...
Script 1.9.0 Az.Compute {Add-AzContainerS...
Manifest 7.0.0.0 Hyper-V {Add-VMAssignableD...
Module Auto-Loading
PowerShell automatically loads modules when you use their cmdlets:
# This automatically loads the NetAdapter module
Get-NetAdapter
# Disable auto-loading (not recommended)
$PSModuleAutoLoadingPreference = 'None'
# Re-enable auto-loading
$PSModuleAutoLoadingPreference = 'All'
Finding and Installing Modules
The PowerShell Gallery hosts thousands of community modules:
# Search for modules
Find-Module -Name "*Azure*"
# Install a module from PowerShell Gallery
Install-Module -Name Az -Scope CurrentUser
# Update installed modules
Update-Module -Name Az
# View module installation location
$env:PSModulePath -split ';'
Creating a Simple Module
Create a file named MyFunctions.psm1:
# MyFunctions.psm1
function Get-Greeting {
param([string]$Name = "World")
return "Hello, $Name!"
}
function Get-SystemInfo {
[PSCustomObject]@{
ComputerName = $env:COMPUTERNAME
Username = $env:USERNAME
OS = (Get-CimInstance Win32_OperatingSystem).Caption
PowerShellVersion = $PSVersionTable.PSVersion.ToString()
}
}
Export-ModuleMember -Function Get-Greeting, Get-SystemInfo
Using your custom module:
# Import your module
Import-Module .\MyFunctions.psm1
# Use the functions
Get-Greeting -Name "PowerShell User"
Get-SystemInfo
The PowerShell Pipeline
The pipeline is PowerShell’s most powerful feature, allowing you to chain cmdlets together by passing objects from one command to the next. This enables complex operations with simple, readable code.
How the Pipeline Works
Unlike traditional shells that pass text between commands, PowerShell passes rich .NET objects. This means properties and methods travel through the pipeline intact.
Basic Pipeline Examples
# Get processes and sort by CPU usage
Get-Process | Sort-Object CPU -Descending
# Get services and filter running ones
Get-Service | Where-Object Status -eq "Running"
# Get files and display only names
Get-ChildItem | Select-Object Name
# Chain multiple operations
Get-Process |
Where-Object CPU -gt 10 |
Sort-Object CPU -Descending |
Select-Object -First 5 Name, CPU, Id
Output:
Name CPU Id
---- --- --
chrome 145.23 7856
firefox 98.45 8924
Code 67.89 9012
Teams 45.67 7234
Outlook 34.21 8765
Pipeline Variable ($_)
The automatic variable $_ represents the current object in the pipeline:
# Filter with complex logic
Get-Process | Where-Object { $_.CPU -gt 10 -and $_.WorkingSet -gt 100MB }
# Custom formatting
Get-Service | ForEach-Object {
"$($_.Name): $($_.Status)"
}
# Calculate totals
Get-Process | Measure-Object WorkingSet -Sum |
ForEach-Object {
"Total Memory: $([math]::Round($_.Sum / 1GB, 2)) GB"
}
Pipeline Parameter Binding
PowerShell automatically matches pipeline output to cmdlet parameters through two methods:
- ByValue – Matches the entire object type
- ByPropertyName – Matches object properties to parameter names
# ByValue: Process objects pipe to Stop-Process
Get-Process -Name "notepad" | Stop-Process
# ByPropertyName: Name property maps to -Name parameter
Get-ChildItem | Where-Object Name -like "*.log" | Remove-Item
# Examine pipeline binding
Get-Help Stop-Process -Parameter ProcessName
Advanced Pipeline Techniques
# Group and count
Get-Process | Group-Object ProcessName |
Sort-Object Count -Descending |
Select-Object Count, Name -First 10
# Export to different formats
Get-Process | Export-Csv processes.csv -NoTypeInformation
Get-Service | Export-Clixml services.xml
Get-EventLog -LogName System -Newest 100 | ConvertTo-Html | Out-File events.html
# Parallel processing (PowerShell 7+)
1..100 | ForEach-Object -Parallel {
Start-Sleep -Seconds 1
"Processed item $_"
} -ThrottleLimit 10
Pipeline Performance Considerations
The pipeline processes objects one at a time (streaming), which is memory-efficient for large datasets:
# Memory-efficient: processes one file at a time
Get-ChildItem -Recurse | Where-Object Length -gt 1MB
# Memory-intensive: loads all into memory first
$files = Get-ChildItem -Recurse
$files | Where-Object Length -gt 1MB
# Use -PipelineVariable to track objects
Get-Process -PipelineVariable proc |
ForEach-Object {
"$($proc.Name) uses $($_.WorkingSet / 1MB) MB"
}
Combining Concepts: Real-World Examples
System Monitoring Script
# Monitor high CPU processes
Get-Process |
Where-Object CPU -gt 50 |
Sort-Object CPU -Descending |
Select-Object Name, CPU, WorkingSet, Id |
Format-Table -AutoSize
# Find large files
Get-ChildItem -Path C:\Temp -Recurse -File |
Where-Object Length -gt 100MB |
Sort-Object Length -Descending |
Select-Object Name, @{Name="SizeMB";Expression={[math]::Round($_.Length / 1MB, 2)}}, FullName |
Export-Csv large_files.csv -NoTypeInformation
Service Management
# Restart all stopped automatic services
Get-Service |
Where-Object { $_.Status -eq 'Stopped' -and $_.StartType -eq 'Automatic' } |
ForEach-Object {
Write-Host "Restarting $($_.Name)..."
Start-Service -Name $_.Name -ErrorAction Continue
}
# Export service configuration
Get-Service |
Select-Object Name, DisplayName, Status, StartType |
Export-Clixml service_backup.xml
Log Analysis
# Analyze Windows Event Log
Get-EventLog -LogName System -EntryType Error -Newest 100 |
Group-Object Source |
Sort-Object Count -Descending |
Select-Object Count, Name |
Format-Table -AutoSize
# Find errors in the last 24 hours
Get-EventLog -LogName Application -After (Get-Date).AddHours(-24) |
Where-Object EntryType -eq 'Error' |
Select-Object TimeGenerated, Source, Message |
Export-Csv recent_errors.csv -NoTypeInformation
Working with Object Properties and Methods
Understanding object structure is crucial for effective pipeline usage:
# Examine object properties
Get-Process | Get-Member -MemberType Property
# View object methods
Get-Process | Get-Member -MemberType Method
# Access properties
$process = Get-Process -Name "chrome" | Select-Object -First 1
$process.ProcessName
$process.CPU
$process.WorkingSet
# Call methods
$process.Refresh()
$process.Kill() # Use with caution!
Calculated Properties
Create custom properties in the pipeline:
# Add calculated property
Get-Process | Select-Object Name,
@{Name="WorkingSetMB"; Expression={[math]::Round($_.WorkingSet / 1MB, 2)}},
@{Name="PrivateMemoryMB"; Expression={[math]::Round($_.PrivateMemorySize / 1MB, 2)}}
# Multiple calculations
Get-ChildItem | Select-Object Name,
@{N="SizeKB"; E={[math]::Round($_.Length / 1KB, 2)}},
@{N="Age"; E={(Get-Date) - $_.CreationTime}},
@{N="Category"; E={
if ($_.Length -gt 1MB) { "Large" }
elseif ($_.Length -gt 100KB) { "Medium" }
else { "Small" }
}}
Error Handling in Pipelines
Proper error handling ensures robust scripts:
# Continue on errors
Get-ChildItem -Path "C:\NonExistent" -ErrorAction SilentlyContinue
# Stop on errors
Get-Service -Name "FakeService" -ErrorAction Stop
# Try-Catch with pipeline
try {
Get-Process |
Where-Object CPU -gt 100 |
Stop-Process -ErrorAction Stop
} catch {
Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red
}
# Log errors from pipeline
Get-ChildItem -Recurse -ErrorAction SilentlyContinue -ErrorVariable errors
$errors | Export-Clixml error_log.xml
Best Practices
Cmdlet Best Practices
- Use full cmdlet names in scripts (avoid aliases like
ls,dir) - Specify parameters explicitly for clarity
- Use
-WhatIfbefore destructive operations - Always check cmdlet help for available parameters
Module Best Practices
- Organize related functions into modules
- Use manifest files (.psd1) to describe modules
- Export only necessary functions with
Export-ModuleMember - Keep modules updated with
Update-Module - Document your custom modules with comment-based help
Pipeline Best Practices
- Filter early in the pipeline to reduce data processed
- Use
Where-Objectbefore expensive operations - Consider memory usage with large datasets
- Break complex pipelines across multiple lines for readability
- Test pipeline segments incrementally
Performance Tips
# SLOW: Filtering after sorting all items
Get-ChildItem -Recurse | Sort-Object Length | Where-Object Length -gt 1MB
# FAST: Filter first, then sort smaller dataset
Get-ChildItem -Recurse | Where-Object Length -gt 1MB | Sort-Object Length
# Use -Filter instead of Where-Object when possible
Get-ChildItem -Path C:\Logs -Filter "*.log" # Faster
Get-ChildItem -Path C:\Logs | Where-Object Name -like "*.log" # Slower
# Measure execution time
Measure-Command {
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
}
Practical Exercise
Try this comprehensive exercise combining all concepts:
# Create a system report module
# Save as SystemReport.psm1
function Get-SystemReport {
param(
[string]$ComputerName = $env:COMPUTERNAME,
[string]$OutputPath = ".\SystemReport.html"
)
$report = [PSCustomObject]@{
ComputerName = $ComputerName
ReportDate = Get-Date
TopProcesses = Get-Process |
Sort-Object CPU -Descending |
Select-Object -First 10 Name, CPU, WorkingSet
RunningServices = (Get-Service | Where-Object Status -eq 'Running').Count
StoppedServices = (Get-Service | Where-Object Status -eq 'Stopped').Count
DiskSpace = Get-PSDrive -PSProvider FileSystem |
Select-Object Name,
@{N="UsedGB";E={[math]::Round($_.Used/1GB,2)}},
@{N="FreeGB";E={[math]::Round($_.Free/1GB,2)}}
}
$report | ConvertTo-Html | Out-File $OutputPath
Write-Host "Report saved to $OutputPath" -ForegroundColor Green
return $report
}
Export-ModuleMember -Function Get-SystemReport
# Use the module
# Import-Module .\SystemReport.psm1
# Get-SystemReport
Conclusion
Mastering cmdlets, modules, and the pipeline forms the foundation of PowerShell proficiency. Cmdlets provide powerful, object-oriented commands with consistent syntax. Modules organize and package functionality for reuse and distribution. The pipeline chains these components together, enabling complex workflows with readable, efficient code.
As you continue your PowerShell journey, remember that these three concepts work together synergistically. Practice combining them in real-world scenarios, explore the extensive module ecosystem, and leverage the pipeline’s object-passing capabilities to write cleaner, more maintainable automation scripts.
The PowerShell community is vast and helpful—don’t hesitate to explore the PowerShell Gallery, read module documentation, and experiment with different pipeline techniques. With these fundamentals in place, you’re well-equipped to tackle advanced PowerShell topics and build sophisticated automation solutions.








