Skip to content
Learni
View all tutorials
Automatisation

How to Automate Tasks with PowerShell in 2026

Lire en français

Introduction

PowerShell, Microsoft's object-oriented shell, is revolutionizing automation on Windows and cross-platform since PowerShell 7. In 2026, with the rise of AI and hybrid environments, mastering its advanced cmdlets, object pipelines, and parallel jobs is essential for DevOps and sysadmins. This intermediate tutorial guides you step-by-step to build robust scripts: from service management to data export via WMI, including parameterized functions and error handling.

Why it matters: A well-written PowerShell script can replace hours of manual clicks, scale on Azure or AWS, and integrate into CI/CD pipelines. Imagine monitoring 100 servers in parallel effortlessly. We start with basic functional scripts and build to complex automations, with 100% copy-paste code. By the end, you'll bookmark this as your go-to pro reference.

Prerequisites

  • PowerShell 7.4+ installed (via winget or Microsoft Store)
  • Basic scripting knowledge (variables, loops)
  • Windows 10/11 or Server 2022 (cross-platform compatible)
  • Editor: VS Code with PowerShell extension
  • Admin rights for some examples (services, WMI)

Basic Script: List and Filter Processes

list-processus.ps1
param(
    [string]$NomProcessus = '*'
)

$processus = Get-Process | Where-Object { $_.ProcessName -like $NomProcessus }

if ($processus.Count -eq 0) {
    Write-Warning "Aucun processus trouvé pour '$NomProcessus'"
} else {
    $processus | Select-Object Name, Id, CPU, WorkingSet | Format-Table -AutoSize
    Write-Output "Trouvé $($processus.Count) processus."
}

This parameterized script uses Get-Process and Where-Object to dynamically filter processes. PowerShell's object pipeline allows chaining without string parsing, unlike bash. Pitfall: Always check Count to avoid false positives; use Format-Table for readable output.

Understanding Object Pipelines

Unlike text-based shells, PowerShell passes .NET objects through pipelines, preserving metadata (properties like CPU). This enables smart filtering with Where-Object and Select-Object. Analogy: Like a conveyor belt of manufactured objects, not text strings to parse.

Advanced Function: Manage Windows Services

gerer-services.ps1
function Invoke-ServiceAction {
    param(
        [Parameter(Mandatory=$true)]
        [string]$NomService,
        [ValidateSet('Start', 'Stop', 'Restart')]
        [string]$Action
    )

    $service = Get-Service -Name $NomService -ErrorAction SilentlyContinue
    if (-not $service) {
        throw "Service '$NomService' introuvable."
    }

    switch ($Action) {
        'Start' { $service | Start-Service }
        'Stop' { $service | Stop-Service }
        'Restart' { $service | Restart-Service }
    }
    Write-Output "Service '$NomService' $Action avec succès. Statut : $($service.Status)."
}

# Exemple d'usage
Invoke-ServiceAction -NomService 'Spooler' -Action 'Restart'

This function wraps Get-Service/Start-Service cmdlets with strict validation via ValidateSet. The switch statement optimizes actions. Pitfall: Use -ErrorAction to avoid crashes; Mandatory enforces essential params, making the script reusable as a module.

Parameter Handling and Validation

param() blocks with attributes like Mandatory and ValidateSet make scripts professional. They prevent runtime errors and improve VS Code autocompletion.

Error Handling with Try-Catch

gestion-erreurs.ps1
try {
    $fichier = Get-Content 'C:\non-existent.txt' -ErrorAction Stop
} catch [System.Management.Automation.ItemNotFoundException] {
    Write-Error "Fichier non trouvé. Création automatique..."
    New-Item -Path 'C:\non-existent.txt' -ItemType File -Force | Out-Null
} catch {
    Write-Error "Erreur inattendue : $($_.Exception.Message)"
    exit 1
} finally {
    Write-Output "Nettoyage terminé."
}

# Test spécifique
$user = Get-LocalUser 'NonExistant' -ErrorAction Stop
Write-Output $user.Name

Try-Catch-Finally handles specific exceptions (.NET types) for pro-level resilience. -ErrorAction Stop converts non-terminating errors to exceptions. Pitfall: Always include a generic catch; finally ensures cleanup, critical in production.

Parallel Jobs for Scalability

Start-Job runs tasks in the background, perfect for monitoring multiple machines. Receive-Job retrieves results. Analogy: Like asynchronous threads without blocking.

Asynchronous Jobs: Monitor Multiple Disks

monitor-disques.ps1
$jobs = @()

1..3 | ForEach-Object {
    $job = Start-Job -ScriptBlock {
        param($drive)
        Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='$drive'" | Select-Object DeviceID, Size, FreeSpace
    } -ArgumentList "C:`$"
    $jobs += $job
}

$jobs | Wait-Job | Receive-Job
$jobs | Remove-Job
Write-Output "Monitoring terminé."

ForEach-Object loop launches 3 parallel WMI jobs for disks. Wait-Job synchronizes, Receive-Job extracts objects. Pitfall: Pass args via -ArgumentList; clean up with Remove-Job to avoid memory leaks in loops.

Custom Module: Export CSV Reports

export-rapport.ps1
function Export-SystemReport {
    param([string]$CheminSortie = 'rapport.csv')

    $rapport = [PSCustomObject]@{
        HostName = $env:COMPUTERNAME
        OS = (Get-CimInstance Win32_OperatingSystem).Caption
        Processes = (Get-Process).Count
        Disques = (Get-WmiObject Win32_LogicalDisk).Count
    }

    $rapport | Export-Csv -Path $CheminSortie -NoTypeInformation -Encoding UTF8
    Write-Output "Rapport exporté vers $CheminSortie"
}

Export-SystemReport -CheminSortie 'C:\rapport-$(Get-Date -Format "yyyyMMdd").csv'

PSCustomObject creates structured objects for clean Export-Csv. CimInstance/WMI fetches system info. Pitfall: -NoTypeInformation avoids junk headers; UTF8 for special characters; dynamic filename with Get-Date.

Best Practices

  • Always use objects: Avoid Out-String except for logs.
  • Validate params: Mandatory, ValidateSet for pro UX.
  • Full error handling: Try-Catch + ErrorAction Stop.
  • Modularize: Functions over linear scripts; publish as modules.
  • Secure it: ExecutionPolicy RemoteSigned; don't hardcode creds.

Common Errors to Avoid

  • Forgetting -ErrorAction Stop: Silent errors in try-catch.
  • String vs object pipelines: Lose properties with | Out-String.
  • Orphaned jobs: Memory leaks without Remove-Job.
  • Ignoring ExecutionPolicy: Blocks scripts; set via Set-ExecutionPolicy.

Next Steps

Dive into Desired State Configuration (DSC) for infrastructure as code, or PSGraph to visualize pipelines. Integrate with Azure DevOps. Check out our Learni trainings on PowerShell and DevOps. Official docs: PowerShell Gallery.