0 min read

Last updated: August 25, 2024

Share

PowerShell Scripting

August 25, 2024

PowerShell Scripting

Introduction

PowerShell is a powerful task automation and configuration management framework from Microsoft, consisting of a command-line shell and associated scripting language. Initially built on .NET Framework, and now cross-platform with PowerShell Core (built on .NET Core), it provides robust capabilities for system administrators and developers to automate tasks across Windows, macOS, and Linux environments.

This guide covers PowerShell fundamentals, advanced techniques, best practices, and real-world applications to help you leverage its full potential in your DevOps workflows.

Table of Contents

  1. PowerShell Basics
  2. Script Structure and Syntax
  3. Variables and Data Types
  4. Flow Control
  5. Functions and Modules
  6. Error Handling
  7. Working with Files and Folders
  8. Network Operations
  9. Working with APIs
  10. PowerShell and Azure
  11. PowerShell in DevOps
  12. Security Best Practices
  13. Performance Optimization
  14. Common Use Cases
  15. Resources

PowerShell Basics

PowerShell Versions

PowerShell has evolved significantly over time:

  • Windows PowerShell 1.0-5.1: Built on .NET Framework, Windows-only
  • PowerShell Core 6.x+: Cross-platform, built on .NET Core
  • PowerShell 7+: Modern, cross-platform version (current recommendation)

Check your PowerShell version with:

hljs powershell
$PSVersionTable

Example output:

hljs txt
Name Value ---- ----- PSVersion 7.3.0 PSEdition Core GitCommitId 7.3.0 OS Microsoft Windows 10.0.19045 Platform Win32NT PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…} PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1 WSManStackVersion 3.0

To install the latest PowerShell version:

hljs powershell
# On Windows using winget winget install Microsoft.PowerShell # On Windows using chocolatey choco install powershell-core # On macOS using Homebrew brew install --cask powershell # On Ubuntu Linux sudo apt-get update sudo apt-get install -y wget apt-transport-https software-properties-common wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" sudo dpkg -i packages-microsoft-prod.deb sudo apt-get update sudo apt-get install -y powershell

Command Types

PowerShell has several command types:

  1. Cmdlets: Native PowerShell commands following verb-noun format (e.g., Get-Process)
  2. Functions: Custom reusable code blocks
  3. Scripts: Collections of commands saved as .ps1 files
  4. Aliases: Shortcuts for commands (e.g., dir is an alias for Get-ChildItem)

Discovering commands:

hljs powershell
# List all commands Get-Command # Find commands with specific noun Get-Command -Noun Process # Find commands with specific verb Get-Command -Verb Get # Get all aliases Get-Alias # Find help on how to use a command Get-Help Get-Process -Detailed Get-Help Get-Process -Examples Get-Help Get-Process -Online # Opens browser documentation

Basic Command Structure

PowerShell cmdlets follow a verb-noun naming convention:

hljs powershell
Verb-Noun -Parameter Value

Common verbs include Get, Set, New, Remove, Start, Stop, etc.

Examples of common cmdlets:

hljs powershell
# List running processes Get-Process # List specific processes Get-Process -Name chrome, firefox # Get process by ID Get-Process -Id 1234 # Get services Get-Service # Start/stop a service Start-Service -Name Spooler Stop-Service -Name Spooler # Get event logs Get-EventLog -LogName System -Newest 10 # Get system information Get-ComputerInfo # List environment variables Get-ChildItem Env: $env:USERNAME # Access specific environment variable

Execution Policy

PowerShell's execution policy determines which scripts can run:

hljs powershell
# View the current execution policy Get-ExecutionPolicy # View execution policy for all scopes Get-ExecutionPolicy -List # Set execution policy (run as administrator) Set-ExecutionPolicy -ExecutionPolicy RemoteSigned # Set execution policy for current user only Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # Bypass execution policy for a single script execution PowerShell -ExecutionPolicy Bypass -File "C:\Scripts\MyScript.ps1"

Common policies:

  • Restricted: No scripts can run (default)
  • AllSigned: Only signed scripts can run
  • RemoteSigned: Local scripts can run; downloaded scripts need signing
  • Unrestricted: All scripts can run (not recommended for production)
  • Bypass: No restrictions; nothing is blocked and no warnings (use with caution)

PowerShell Profiles

PowerShell profiles allow you to customize your PowerShell environment by loading settings, functions, and aliases whenever you start PowerShell:

hljs powershell
# Check if you have a profile Test-Path $PROFILE # Create a profile if it doesn't exist if (!(Test-Path $PROFILE)) { New-Item -Type File -Path $PROFILE -Force } # Edit your profile notepad $PROFILE # or code $PROFILE # With VS Code # Example profile content # Add this to your profile file: function prompt { $currentDir = $executionContext.SessionState.Path.CurrentLocation.Path "PS [$env:COMPUTERNAME] $currentDir> " } # Create custom aliases Set-Alias -Name np -Value notepad

Profile locations:

  • Current user, current host: $PROFILE
  • Current user, all hosts: $PROFILE.CurrentUserAllHosts
  • All users, current host: $PROFILE.AllUsersCurrentHost
  • All users, all hosts: $PROFILE.AllUsersAllHosts

Script Structure and Syntax

Basic Script Structure

PowerShell scripts use the .ps1 extension. Here's a more comprehensive example of a well-structured script:

hljs powershell
<# .SYNOPSIS Brief description of what the script does. .DESCRIPTION Detailed description of the script's functionality. .PARAMETER ComputerName The name of the computer to query. .PARAMETER OutputPath The path where the report will be saved. .EXAMPLE .\Get-SystemReport.ps1 -ComputerName "Server01" -OutputPath "C:\Reports" .NOTES Author: Your Name Date: April 13, 2025 Version: 1.0 #> #Requires -Version 7.0 #Requires -Modules ActiveDirectory, SqlServer #Requires -RunAsAdministrator param ( [Parameter(Mandatory=$true, Position=0)] [string]$ComputerName, [Parameter(Mandatory=$false)] [string]$OutputPath = ".\Reports", [switch]$IncludeServices ) # Script initialization $ErrorActionPreference = "Stop" $VerbosePreference = "Continue" # Import required modules Import-Module ActiveDirectory -ErrorAction Stop # Define functions function Get-ComputerInfo { [CmdletBinding()] param ( [string]$Name ) Write-Verbose "Querying system information for $Name" return Get-CimInstance -ComputerName $Name -ClassName Win32_ComputerSystem } function Write-Report { [CmdletBinding()] param ( [object]$Data, [string]$Path ) if (!(Test-Path -Path $Path)) { New-Item -Path $Path -ItemType Directory -Force | Out-Null } $reportPath = Join-Path -Path $Path -ChildPath "$($Data.Name)_Report.json" $Data | ConvertTo-Json -Depth 5 | Out-File -FilePath $reportPath return $reportPath } # Main script execution try { Write-Verbose "Script started at $(Get-Date)" # Verify computer is reachable if (!(Test-Connection -ComputerName $ComputerName -Count 1 -Quiet)) { throw "Computer $ComputerName is not reachable." } # Get computer information $systemInfo = Get-ComputerInfo -Name $ComputerName # Add services if requested if ($IncludeServices) { Write-Verbose "Including services information" $services = Get-Service -ComputerName $ComputerName $systemInfo | Add-Member -MemberType NoteProperty -Name Services -Value $services } # Generate report $reportFile = Write-Report -Data $systemInfo -Path $OutputPath Write-Output "Report generated successfully at $reportFile" } catch { Write-Error "An error occurred: $_" exit 1 } finally { Write-Verbose "Script completed at $(Get-Date)" }

Advanced Script Header Comments

PowerShell supports special comment-based help that VS Code and PowerShell ISE can recognize:

hljs powershell
<# .SYNOPSIS Short description of the script's purpose. .DESCRIPTION Detailed explanation of what the script does and how it works. .PARAMETER ParameterName Description of a parameter. .EXAMPLE PS> .\MyScript.ps1 -Parameter1 "Value" Example description of what happens. .EXAMPLE PS> .\MyScript.ps1 -Parameter1 "Value" -Switch Another example with different parameters. .INPUTS Description of input objects if your script accepts pipeline input. .OUTPUTS Description of objects that the script returns. .NOTES Additional information about the script. .LINK https://related-documentation-url.com #>

Parameter Declarations with Validation

PowerShell allows for sophisticated parameter validation:

hljs powershell
param ( [Parameter(Mandatory=$true, Position=0, HelpMessage="Enter the server name:")] [ValidateNotNullOrEmpty()] [string]$ServerName, [Parameter(Mandatory=$false)] [ValidateSet("Development", "Testing", "Production")] [string]$Environment = "Development", [Parameter(Mandatory=$false)] [ValidateRange(1, 100)] [int]$MaxItems = 25, [Parameter(Mandatory=$false)] [ValidatePattern("[a-zA-Z][a-zA-Z0-9]{5,10}")] [string]$UserName, [Parameter(Mandatory=$false)] [ValidateScript({Test-Path $_ -PathType Container})] [string]$OutputFolder = ".\Output", [switch]$Force )

Here-Strings for Multi-line Text

PowerShell provides "here-strings" for multi-line text content:

hljs powershell
# Basic here-string with variable substitution $name = "John" $message = @" Hello, $name! This is a multi-line message that preserves all whitespace and line breaks. Today is $(Get-Date -Format "yyyy-MM-dd"). "@ # Single-quoted here-string without variable substitution $sql = @' SELECT * FROM Customers WHERE Region = 'North' AND Status = 'Active'; '@

Pipeline Techniques and Examples

The pipeline is one of PowerShell's most powerful features:

hljs powershell
# Basic pipeline example Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 | Format-Table Name, CPU, WorkingSet # Pipeline with calculated properties Get-ChildItem -Path C:\Windows -Filter *.exe -Recurse -ErrorAction SilentlyContinue | Select-Object -Property Name, @{Name="SizeKB"; Expression={[math]::Round($_.Length/1KB, 2)}}, LastWriteTime | Sort-Object -Property SizeKB -Descending | Select-Object -First 10 # Pipeline with filtering and grouping Get-Service | Where-Object {$_.Status -eq "Running"} | Group-Object -Property StartType | Select-Object Name, Count # Processing each item in the pipeline Get-ChildItem -Path C:\Logs -Filter *.log | ForEach-Object { $content = Get-Content -Path $_.FullName $errorCount = ($content | Select-String -Pattern "ERROR" -SimpleMatch).Count $warningCount = ($content | Select-String -Pattern "WARNING" -SimpleMatch).Count [PSCustomObject]@{ LogFile = $_.Name ErrorCount = $errorCount WarningCount = $warningCount TotalLines = $content.Count } } | Sort-Object -Property ErrorCount -Descending

Using the Splatting Technique

Splatting is a technique for passing parameters to a command using a hashtable:

hljs powershell
# Traditional approach - long command line Send-MailMessage -From "sender@example.com" -To "recipient@example.com" -Subject "Report" -Body "See attached report." -SmtpServer "smtp.example.com" -Port 587 -UseSsl -Credential $credential -Attachments "C:\Reports\Report.pdf" # Using splatting - cleaner and more maintainable $emailParams = @{ From = "sender@example.com" To = "recipient@example.com" Subject = "Report" Body = "See attached report." SmtpServer = "smtp.example.com" Port = 587 UseSsl = $true Credential = $credential Attachments = "C:\Reports\Report.pdf" } Send-MailMessage @emailParams # Note the @ instead of $

Script Flow Control with Break, Continue, and Return

hljs powershell
# Break and Continue example foreach ($server in $servers) { if ($server.Status -eq "Maintenance") { Write-Warning "Server $($server.Name) is in maintenance mode. Skipping..." continue # Skip to the next iteration } if ($server.Status -eq "Offline") { Write-Error "Server $($server.Name) is offline. Stopping script." break # Exit the loop completely } # Process server Write-Output "Processing server $($server.Name)" } # Return example in a function function Test-ServerConnection { param ( [string]$ServerName ) if (!(Test-Connection -ComputerName $ServerName -Count 1 -Quiet)) { return $false # Exit the function with a false value } # Continue with other tests $portTest = Test-NetConnection -ComputerName $ServerName -Port 3389 -WarningAction SilentlyContinue return $portTest.TcpTestSucceeded # Return the result of the port test }

Using Requires Statements

Require statements help ensure script prerequisites are met:

hljs powershell
#Requires -Version 7.0 # Minimum PowerShell version #Requires -Modules ActiveDirectory, Az # Required modules #Requires -RunAsAdministrator # Must run as admin #Requires -PSEdition Core # Must be PowerShell Core

Variables and Data Types

Variable Declaration

Variables in PowerShell start with $:

hljs powershell
$name = "PowerShell" $age = 15 $isAwesome = $true

Common Data Types

PowerShell variables can hold different data types:

hljs powershell
$string = "Hello" # String $int = 42 # Integer $double = 3.14 # Double $bool = $true # Boolean $array = 1, 2, 3, "four" # Array $hash = @{Key1 = "Value1"; Key2 = 2} # Hashtable $null = $null # Null value

Arrays

hljs powershell
# Array creation $array = @(1, 2, 3, 4, 5) $array = 1..5 # Range operator # Accessing elements $firstElement = $array[0] $lastElement = $array[-1] # Adding elements $array += 6 # Filtering arrays $filtered = $array | Where-Object { $_ -gt 3 }

Hashtables (Dictionaries)

hljs powershell
# Creating a hashtable $user = @{ Name = "John Doe" Age = 30 Role = "Developer" } # Accessing elements $userName = $user["Name"] $userAge = $user.Age # Adding or updating elements $user["Department"] = "IT" $user.Location = "New York" # Removing an element $user.Remove("Age")

Flow Control

Conditional Statements

hljs powershell
# If-ElseIf-Else if ($condition1) { # Code block } elseif ($condition2) { # Code block } else { # Code block } # Switch statement $value = "apple" switch ($value) { "apple" { "It's an apple" } "orange" { "It's an orange" } default { "Unknown fruit" } } # Switch with wildcards switch -Wildcard ($filename) { "*.txt" { "Text file" } "*.jpg" { "Image file" } default { "Other file type" } }

Loops

hljs powershell
# For loop for ($i = 0; $i -lt 10; $i++) { # Code block } # ForEach loop foreach ($item in $collection) { # Code block } # ForEach-Object in pipeline $collection | ForEach-Object { # Process $_ (current item) } # While loop while ($condition) { # Code block } # Do-While loop (executes at least once) do { # Code block } while ($condition) # Do-Until loop do { # Code block } until ($condition)

Functions and Modules

Basic Functions

hljs powershell
function Get-FullName { param ( [string]$FirstName, [string]$LastName ) return "$FirstName $LastName" } $fullName = Get-FullName -FirstName "John" -LastName "Doe"

Advanced Functions

hljs powershell
function Get-SystemInfo { [CmdletBinding()] param ( [Parameter(Mandatory=$true, Position=0)] [string]$ComputerName, [Parameter(Mandatory=$false)] [switch]$IncludeServices, [ValidateSet("Basic", "Detailed", "Full")] [string]$Level = "Basic" ) begin { # Initialization code } process { # Main processing $systemInfo = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_OperatingSystem if ($IncludeServices) { $services = Get-Service -ComputerName $ComputerName } # Return based on level switch ($Level) { "Basic" { return $systemInfo | Select-Object Caption, Version } "Detailed" { return $systemInfo } "Full" { return @{ OS = $systemInfo; Services = $services } } } } end { # Cleanup code } }

Modules

Modules are collections of related functions, cmdlets, variables, etc.:

hljs powershell
# Module structure (MyModule.psm1) function Get-Something { # Function code } function Set-Something { # Function code } # Export only specific functions Export-ModuleMember -Function Get-Something, Set-Something

Using modules:

hljs powershell
# Import a module Import-Module -Name MyModule # List available modules Get-Module -ListAvailable # Find commands in a module Get-Command -Module MyModule

Error Handling

Try-Catch-Finally

hljs powershell
try { # Code that might cause an error $result = 10 / 0 } catch [System.DivideByZeroException] { # Handle specific exception Write-Error "Division by zero error" } catch { # Handle any other exception Write-Error "An error occurred: $_" } finally { # Code that always runs Write-Output "Cleanup operations" }

Error Preference Variables

hljs powershell
# Set behavior for non-terminating errors $ErrorActionPreference = "Stop" # Options: Continue, SilentlyContinue, Stop, Inquire # Use -ErrorAction parameter for individual commands Get-Content -Path "NonExistentFile.txt" -ErrorAction SilentlyContinue

Working with Files and Folders

File Operations

hljs powershell
# Read file content $content = Get-Content -Path "C:\path\to\file.txt" # Write to a file "Content" | Out-File -FilePath "C:\path\to\output.txt" "Appended content" | Add-Content -FilePath "C:\path\to\output.txt" # Test if file exists if (Test-Path -Path "C:\path\to\file.txt") { # File exists } # Copy files Copy-Item -Path "C:\source\file.txt" -Destination "C:\destination\" # Move files Move-Item -Path "C:\source\file.txt" -Destination "C:\destination\" # Delete files Remove-Item -Path "C:\path\to\file.txt"

Folder Operations

hljs powershell
# Create a new directory New-Item -Path "C:\path\to\new\folder" -ItemType Directory # List directory contents Get-ChildItem -Path "C:\path" -Recurse # Filter files by extension Get-ChildItem -Path "C:\path" -Filter "*.txt"

Working with CSV/JSON/XML

hljs powershell
# CSV $csvData = Import-Csv -Path "data.csv" $objects | Export-Csv -Path "output.csv" -NoTypeInformation # JSON $jsonData = Get-Content -Path "data.json" | ConvertFrom-Json $objects | ConvertTo-Json | Out-File -FilePath "output.json" # XML [xml]$xmlData = Get-Content -Path "data.xml" $objects | Export-Clixml -Path "output.xml"

Network Operations

Basic Network Commands

hljs powershell
# Test network connectivity Test-NetConnection -ComputerName "www.example.com" -Port 443 # Get IP configuration Get-NetIPConfiguration # DNS resolution Resolve-DnsName -Name "www.example.com" # TCP port test Test-NetConnection -ComputerName "server" -Port 80 -InformationLevel Detailed

Web Requests

hljs powershell
# GET request $response = Invoke-WebRequest -Uri "https://api.example.com/data" $responseContent = $response.Content # POST request with JSON body $body = @{ name = "John Doe" email = "john@example.com" } | ConvertTo-Json $response = Invoke-WebRequest -Uri "https://api.example.com/users" -Method Post -Body $body -ContentType "application/json" # REST API calls $params = @{ Uri = "https://api.example.com/users" Method = "POST" Headers = @{ Authorization = "Bearer $token" } ContentType = "application/json" Body = $body } $response = Invoke-RestMethod @params

Working with APIs

REST API Example

hljs powershell
# Function to interact with REST API function Invoke-ApiRequest { [CmdletBinding()] param ( [string]$Endpoint, [string]$Method = "GET", [hashtable]$Headers = @{}, [object]$Body = $null ) $baseUrl = "https://api.example.com/v1" $uri = "$baseUrl/$Endpoint" $params = @{ Uri = $uri Method = $Method Headers = $Headers ContentType = "application/json" } if ($Body -and $Method -ne "GET") { $params.Body = ($Body | ConvertTo-Json -Depth 10) } try { $response = Invoke-RestMethod @params return $response } catch { Write-Error "API error: $_" throw } } # Usage $token = "YOUR_API_TOKEN" $headers = @{ "Authorization" = "Bearer $token" } # Get users $users = Invoke-ApiRequest -Endpoint "users" -Headers $headers # Create user $newUser = @{ name = "Jane Smith" email = "jane@example.com" role = "admin" } $createdUser = Invoke-ApiRequest -Endpoint "users" -Method "POST" -Headers $headers -Body $newUser

PowerShell and Azure

Azure PowerShell Module

hljs powershell
# Install Azure PowerShell module Install-Module -Name Az -AllowClobber -Force # Connect to Azure Connect-AzAccount # Select subscription Set-AzContext -SubscriptionId "subscription-id" # Common Azure operations $resourceGroup = "MyResourceGroup" $location = "eastus" # Create a resource group New-AzResourceGroup -Name $resourceGroup -Location $location # Deploy a virtual machine New-AzVM -ResourceGroupName $resourceGroup -Name "myVM" -Location $location -Image "UbuntuLTS" # List resources Get-AzResource -ResourceGroupName $resourceGroup

Azure Automation

hljs powershell
# Azure Automation runbook example param ( [Parameter(Mandatory=$true)] [string]$ResourceGroupName ) # Connect to Azure with managed identity Connect-AzAccount -Identity # Start all stopped VMs in a resource group $vms = Get-AzVM -ResourceGroupName $ResourceGroupName -Status foreach ($vm in $vms) { if ($vm.PowerState -eq "VM deallocated") { Write-Output "Starting VM: $($vm.Name)" Start-AzVM -ResourceGroupName $ResourceGroupName -Name $vm.Name } }

PowerShell in DevOps

CI/CD Integration

hljs powershell
# Example: Deployment script for a web application param ( [string]$Environment = "dev", [string]$Version ) # Configuration for different environments $config = @{ dev = @{ ServerPath = "\\devserver\sites\" AppPoolName = "DevAppPool" } staging = @{ ServerPath = "\\stagingserver\sites\" AppPoolName = "StagingAppPool" } prod = @{ ServerPath = "\\prodserver\sites\" AppPoolName = "ProdAppPool" } } # Environment-specific settings $envConfig = $config[$Environment] $deployPath = Join-Path -Path $envConfig.ServerPath -ChildPath "MyApp" # Stop the application pool Write-Output "Stopping application pool: $($envConfig.AppPoolName)" Invoke-Command -ComputerName "webserver" -ScriptBlock { param($appPoolName) Import-Module WebAdministration Stop-WebAppPool -Name $appPoolName } -ArgumentList $envConfig.AppPoolName # Deploy the application Write-Output "Deploying version $Version to $Environment environment" $sourcePath = ".\build\$Version\*" Copy-Item -Path $sourcePath -Destination $deployPath -Recurse -Force # Start the application pool Write-Output "Starting application pool: $($envConfig.AppPoolName)" Invoke-Command -ComputerName "webserver" -ScriptBlock { param($appPoolName) Import-Module WebAdministration Start-WebAppPool -Name $appPoolName } -ArgumentList $envConfig.AppPoolName Write-Output "Deployment complete"

Infrastructure as Code

hljs powershell
# Example: Creating a testing environment with PowerShell function New-TestEnvironment { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string]$ProjectName, [Parameter(Mandatory=$true)] [string]$BuildNumber ) # Create resource group $resourceGroupName = "$ProjectName-Test-$BuildNumber" $deploymentName = "Deployment-$BuildNumber" $location = "eastus" New-AzResourceGroup -Name $resourceGroupName -Location $location -Force # Deploy ARM template $templateFile = ".\infrastructure\template.json" $templateParameters = @{ projectName = $ProjectName environment = "test" buildNumber = $BuildNumber } $deployment = New-AzResourceGroupDeployment -Name $deploymentName ` -ResourceGroupName $resourceGroupName ` -TemplateFile $templateFile ` -TemplateParameterObject $templateParameters # Return environment information return @{ ResourceGroup = $resourceGroupName Deployment = $deployment Endpoints = @{ WebApp = $deployment.Outputs.webAppUrl.Value API = $deployment.Outputs.apiUrl.Value } } } # Usage $env = New-TestEnvironment -ProjectName "MyProject" -BuildNumber "20250413.1"

Security Best Practices

Secure Credential Handling

hljs powershell
# Never store credentials in plain text in scripts # Use encrypted credentials $securePassword = ConvertTo-SecureString "PlainTextPassword" -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential("username", $securePassword) # Better: Store encrypted credentials in a file (Windows only) $credential = Get-Credential $credential | Export-CliXml -Path "C:\secure\credentials.xml" # Later, retrieve the credentials $credential = Import-CliXml -Path "C:\secure\credentials.xml" # For automation, use managed identities or key vaults

Script Signing

hljs powershell
# Create a self-signed certificate for testing $cert = New-SelfSignedCertificate -Subject "CN=PowerShell Code Signing" -Type CodeSigningCert -CertStoreLocation "Cert:\CurrentUser\My" # Sign a script Set-AuthenticodeSignature -FilePath ".\MyScript.ps1" -Certificate $cert # In production, use certificates from a trusted certification authority

Permission Management

hljs powershell
# Use Just Enough Administration (JEA) # Example: Create a JEA configuration file # PSSC file (session configuration) New-PSSessionConfigurationFile -Path ".\JEAConfig.pssc" ` -SessionType RestrictedRemoteServer ` -VisibleCmdlets "Get-Service", "Restart-Service" ` -VisibleFunctions "Get-SystemInfo" ` -LanguageMode NoLanguage # Register the configuration Register-PSSessionConfiguration -Path ".\JEAConfig.pssc" ` -Name "MaintenanceSession" ` -Force

Performance Optimization

Efficient Coding Practices

hljs powershell
# Bad: Slow string concatenation in a loop $result = "" foreach ($item in 1..10000) { $result += $item.ToString() + "," } # Good: Use StringBuilder for string operations $sb = New-Object System.Text.StringBuilder foreach ($item in 1..10000) { [void]$sb.Append("$item,") } $result = $sb.ToString() # Bad: Filtering objects in the pipeline multiple times Get-Process | Where-Object { $_.CPU -gt 100 } | Where-Object { $_.Name -like "S*" } # Good: Use a single Where-Object with compound conditions Get-Process | Where-Object { $_.CPU -gt 100 -and $_.Name -like "S*" } # Use Jobs for parallel processing $jobs = 1..10 | ForEach-Object { $server = "Server$_" Start-Job -ScriptBlock { param($serverName) Get-WmiObject Win32_OperatingSystem -ComputerName $serverName } -ArgumentList $server } Wait-Job $jobs $results = Receive-Job $jobs # PowerShell 7+: Use parallel foreach $results = 1..10 | ForEach-Object -Parallel { $server = "Server$_" Get-WmiObject Win32_OperatingSystem -ComputerName $server } -ThrottleLimit 5

Common Use Cases

System Administration

hljs powershell
# Get system information function Get-DetailedSystemInfo { [CmdletBinding()] param ( [string]$ComputerName = $env:COMPUTERNAME ) $os = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_OperatingSystem $cs = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_ComputerSystem $proc = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_Processor $disk = Get-CimInstance -ComputerName $ComputerName -ClassName Win32_LogicalDisk -Filter "DriveType=3" [PSCustomObject]@{ ComputerName = $ComputerName OSName = $os.Caption OSVersion = $os.Version Manufacturer = $cs.Manufacturer Model = $cs.Model Processor = $proc.Name PhysicalMemoryGB = [math]::Round($cs.TotalPhysicalMemory / 1GB, 2) Disks = $disk | ForEach-Object { [PSCustomObject]@{ Drive = $_.DeviceID SizeGB = [math]::Round($_.Size / 1GB, 2) FreeSpaceGB = [math]::Round($_.FreeSpace / 1GB, 2) PercentFree = [math]::Round(($_.FreeSpace / $_.Size) * 100, 2) } } } }

Automation Examples

User Account Management

hljs powershell
# Bulk user creation Import-Csv ".\users.csv" | ForEach-Object { $securePassword = ConvertTo-SecureString $_.InitialPassword -AsPlainText -Force $params = @{ Name = $_.Username GivenName = $_.FirstName Surname = $_.LastName SamAccountName = $_.Username UserPrincipalName = "$($_.Username)@domain.com" AccountPassword = $securePassword Enabled = $true Path = "OU=$($_.Department),DC=domain,DC=com" ChangePasswordAtLogon = $true } New-ADUser @params }

System Monitoring

hljs powershell
# Monitor services and restart if necessary $servicesToMonitor = @("MSSQLSERVER", "W3SVC", "BITS") foreach ($service in $servicesToMonitor) { $serviceStatus = Get-Service -Name $service -ErrorAction SilentlyContinue if ($serviceStatus -and $serviceStatus.Status -ne "Running") { Write-Output "$(Get-Date) - Service $service is not running. Attempting to start..." try { Start-Service -Name $service Write-Output "$(Get-Date) - Service $service started successfully." } catch { Write-Error "$(Get-Date) - Failed to start service $service. Error: $_" Send-MailMessage -To "admin@example.com" -From "monitor@example.com" -Subject "Service Failure: $service" -Body "The service $service failed to start. Error: $_" -SmtpServer "smtp.example.com" } } }

Resources

Official Documentation and Learning Resources

Community Resources

Books and Courses

  • "PowerShell in a Month of Lunches" by Don Jones and Jeffrey Hicks
  • "PowerShell for Sysadmins" by Adam Bertram
  • "Learn PowerShell in Y Minutes" - Quick reference guide

Conclusion

PowerShell is a versatile and powerful tool for automation, system administration, and DevOps workflows. By mastering PowerShell, you can significantly improve your productivity, create consistent and reliable processes, and effectively manage complex IT environments.

This guide covers the fundamentals, but PowerShell's capabilities extend far beyond what's documented here. As you continue to work with PowerShell, you'll discover innovative ways to solve problems and automate tasks across your infrastructure.