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

PowerShell Basic Concepts: Cmdlets, Modules & the Pipeline Explained

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

PowerShell Basic Concepts: Cmdlets, Modules & the Pipeline Explained

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.

PowerShell Basic Concepts: Cmdlets, Modules & the Pipeline Explained

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

PowerShell Basic Concepts: Cmdlets, Modules & the Pipeline Explained

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 -WhatIf before 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-Object before 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 
}

PowerShell Basic Concepts: Cmdlets, Modules & the Pipeline Explained

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.