Guida completa a PowerShell
PowerShell è un ambiente di scripting cross-platform orientato agli oggetti che, tramite l'uso di cmdlet, permette una gestione avanzata e automatizzata dei sistemi complessi. Rispetto alla versione legacy Windows PowerShell 5.1, PowerShell 7+ offre un runtime .NET moderno, maggiore efficienza operativa e piena interoperabilità su sistemi Windows, Linux e macOS.
Introduzione
In questo guida per tutti troverete spiegazioni chiare, esempi pratici e suggerimenti per l'autoapprendimento.
Che cos'è PowerShell?
PowerShell è una shell di scripting e un linguaggio di scripting sviluppato da Microsoft. A differenza delle tradizionali shell a riga di comando che si basano sul testo PowerShell è orientato agli oggetti. Ciò significa che i comandi (chiamati cmdlet) manipolano oggetti strutturati, non solo stringhe di testo. Questa caratteristica lo rende estremamente potente per l'automazione, la gestione di sistemi e la configurazione.
Windows PowerShell vs PowerShell 7+
Distinzione fondamentale che molti ignorano.
| Caratteristica | Windows PowerShell 5.1 | PowerShell 7+ |
|---|---|---|
| Stato | Legacy | Attivo |
| Open Source | ✕ | GitHub |
| Cross-platform | Solo Windows | Windows · Linux · macOS |
| Eseguibile | powershell.exe | pwsh |
| Runtime | .NET Framework | .NET 6 / 7 / 8 |
| Incluso in Windows | Win 10 / 11 | Da installare separatamente |
Raccomandazione: Usa sempre PowerShell 7+ (pwsh) per i nuovi progetti.
Perché usare PowerShell
- Automazione: Elimina attività manuali ripetitive — gestione file, provisioning utenti, deployment applicazioni.
- Gestione dei sistemi: Strumento fondamentale per l'amministrazione Windows, usato sempre più anche su Linux e macOS.
- Efficienza: Operazioni complesse in poche righe grazie alla pipeline orientata agli oggetti.
- Standard enterprise: È lo strumento ufficiale per la gestione di Microsoft Azure e dell'ecosistema Microsoft 365.
Differenze tra PowerShell, CMD e Bash
| Caratteristica | PowerShell | CMD | Bash |
|---|---|---|---|
| Orientamento | Oggetti .NET | Testo | Testo |
| Linguaggio | Powershell (.NET) | Batch | Batch scripting |
| Output pipeline | Oggetti strutturati | Stringhe | Stringhe |
| Cross-platform | Win/Linux/MacOS | Win | Linux/MacOS |
| Potenza | Alta | Bassa | Alta |
| Curva di apprendimento | Media | Bassa | Media |
Installazione e Configurazione
Windows
Windows 10/11 include Windows PowerShell 5.1 (legacy). Per installare PowerShell 7+:
# Metodo 1: Windows Package Manager (winget)
winget install --id Microsoft.Powershell --source winget
# Metodo 2: Download diretto
# https://github.com/PowerShell/PowerShell/releases
Dopo l'installazione, avvia PowerShell 7 con il comando pwsh nel terminale.
macOS
# Installa Homebrew se non presente
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Installa PowerShell
brew install --cask powershell
# Avvia PowerShell
pwsh
Linux (Ubuntu/Debian)
# Importa la chiave Microsoft
curl -sSL https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc
# Aggiungi il repository
sudo add-apt-repository "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -rs)-prod $(lsb_release -cs) main"
# Installa
sudo apt update && sudo apt install -y powershell
# Avvia
pwsh
Per altre distribuzioni (RHEL, Fedora, openSUSE), consulta la documentazione ufficiale.
Editor consigliato: Visual Studio Code
PowerShell ISE è ufficialmente deprecato. Microsoft raccomanda Visual Studio Code con l'estensione PowerShell.
Installa l'estensione direttamente da VS Code:
Ctrl+P → ext install ms-vscode.PowerShell
L'estensione offre: IntelliSense, debugging integrato, esecuzione di selezioni di codice e integrazione con PSScriptAnalyzer.
Configurazione di Base
Profilo PowerShell — script eseguito automaticamente all'avvio:
# Visualizza il percorso del profilo
$PROFILE
# Crea il file di profilo se non esiste
if (-not (Test-Path $PROFILE)) {
New-Item -ItemType File -Path $PROFILE -Force
}
# Apri il profilo in VS Code
code $PROFILE
Execution Policy — controlla quali script possono essere eseguiti:
# Visualizza la policy attuale
Get-ExecutionPolicy
# Imposta la policy per l'utente corrente (scelta comune per sviluppo locale)
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
# Valori possibili:
# Restricted → Nessuno script (default su Windows)
# RemoteSigned → Gli script locali sono OK; quelli scaricati richiedono firma
# Unrestricted → Tutti gli script (non consigliato in produzione)
# AllSigned → Solo script con firma digitale (massima sicurezza)
Concetti Fondamentali
Sintassi: Verb-Noun
Tutti i cmdlet seguono la convenzione Verbo-Sostantivo:
Get-Process # Recupera informazioni sui processi
Stop-Service # Arresta un servizio
New-Item # Crea un nuovo elemento
Remove-Item # Elimina un elemento
Set-Location # Cambia directory
I verbi approvati da Microsoft garantiscono coerenza. Per vederli tutti:
Get-Verb | Sort-Object Verb
Il Sistema di Help
La documentazione integrata è uno dei punti di forza di PowerShell:
# Aggiorna l'help (eseguire come amministratore)
Update-Help
# Help base
Get-Help Get-Process
# Con esempi pratici (molto utile!)
Get-Help Get-Process -Examples
# Help completo con tutti i parametri
Get-Help Get-Process -Full
# Apre la documentazione online
Get-Help Get-Process -Online
Cmdlet Essenziali
Get-Command # Elenca tutti i cmdlet disponibili
Get-Command -Verb Get # Filtra per verbo
Get-Command *process* # Ricerca per nome
Get-Member # Mostra proprietà e metodi di un oggetto
Get-Process | Get-Member # Esempio: scopri cosa puoi fare con un processo
Variabili e Tipi di Dati
Variabili
Le variabili iniziano con $. PowerShell è tipizzato dinamicamente, ma è possibile (e consigliato per script professionali) dichiarare il tipo esplicitamente:
# Tipizzazione implicita
$nome = "Mario"
$eta = 30
$attivo = $true
# Tipizzazione esplicita (best practice per script professionali)
[string]$nome = "Mario"
[int]$eta = 30
[bool]$attivo = $true
[datetime]$oggi = Get-Date
Stringhe
# Virgolette doppie: interpolazione variabili
$nome = "Mario"
$saluto = "Ciao, $nome!" # → "Ciao, Mario!"
# Virgolette singole: stringa letterale (no interpolazione)
$letterale = 'Ciao, $nome!' # → "Ciao, $nome!"
# Stringa multilinea (here-string)
$testo = @"
Questa è una stringa
su più righe con variabili: $nome
"@
# Metodi delle stringhe (PowerShell espone i metodi .NET)
"powershell".ToUpper() # → "POWERSHELL"
" testo ".Trim() # → "testo"
"ciao mondo".Split(" ") # → @("ciao", "mondo")
Array e HashTable
# Array
$frutti = "mela", "banana", "arancia"
$numeri = 1..10 # Range: da 1 a 10
$frutti[0] # → "mela"
$frutti.Count # → 3
# HashTable (dizionario chiave-valore)
$persona = @{
Nome = "Mario"
Cognome = "Rossi"
Eta = 30
}
$persona["Nome"] # → "Mario"
$persona.Eta # → 30
$persona.Keys # → Nome, Cognome, Eta
Variabili Automatiche
PowerShell fornisce variabili speciali predefinite:
$_ # (alias: $PSItem) L'oggetto corrente nella pipeline
$? # True se l'ultimo comando ha avuto successo
$LASTEXITCODE # Codice di uscita dell'ultimo programma esterno
$Error # Array degli ultimi errori
$HOME # Directory home dell'utente
$PSVersionTable # Informazioni sulla versione di PowerShell
$PROFILE # Percorso del profilo utente
Operatori
# Aritmetici
5 + 3 # 8
10 % 3 # 1 (modulo)
# Confronto
"a" -eq "a" # True (equal)
5 -ne 3 # True (not equal)
10 -gt 5 # True (greater than)
3 -lt 5 # True (less than)
5 -ge 5 # True (greater or equal)
"ciao" -like "c*" # True (wildcard match)
"hello" -match "^h" # True (regex match)
# Logici
$true -and $false # False
$true -or $false # True
-not $true # False
La Pipeline
La pipeline (|) è il cuore di PowerShell. Passa oggetti interi (non testo) tra i comandi, preservando tutte le proprietà.
# Esempio base: filtra i processi che usano più di 100MB di RAM
Get-Process | Where-Object { $_.WorkingSet -gt 100MB }
# $_ rappresenta l'oggetto corrente nella pipeline (ogni processo)
# .WorkingSet è una proprietà dell'oggetto Process
# Concatena più operazioni
Get-Process |
Where-Object { $_.CPU -gt 1 } |
Sort-Object CPU -Descending |
Select-Object Name, CPU, Id -First 10 |
Format-Table -AutoSize
Cmdlet Fondamentali per la Pipeline
# Filtra oggetti
Get-Service | Where-Object { $_.Status -eq "Running" }
# Ordina
Get-Process | Sort-Object WorkingSet -Descending
# Seleziona proprietà specifiche
Get-Process | Select-Object Name, Id, CPU
# Aggrega
Get-Process | Measure-Object CPU -Sum -Average
# Raggruppa
Get-Service | Group-Object Status
# Converte output
Get-Process | ConvertTo-Json
Get-Process | ConvertTo-Csv | Out-File processi.csv
# Formatta output (solo per visualizzazione, non usare in pipeline)
Get-Process | Format-Table Name, CPU -AutoSize
Get-Process | Format-List *
Gestione File e Directory
Navigazione
Get-Location # Directory corrente (alias: pwd)
Set-Location C:\Projects # Cambia directory (alias: cd)
Set-Location .. # Vai alla directory padre
Get-PSDrive # Mostra tutti i "drive" disponibili (C:, D:, HKLM:, Env:, ecc.)
Set-Location HKLM: # PowerShell può navigare anche nel Registry!
Operazioni sui File
# Elenca contenuto
Get-ChildItem # (alias: ls, dir)
Get-ChildItem -Recurse # Ricorsivo
Get-ChildItem *.log # Filtra per estensione
# Crea
New-Item -ItemType File -Path .\log.txt
New-Item -ItemType Directory -Path .\backup
# Leggi
Get-Content .\log.txt
Get-Content .\log.txt -Tail 20 # Ultime 20 righe (come tail -n)
Get-Content .\log.txt -Wait # Modalità follow (come tail -f)
# Scrivi
Set-Content .\output.txt "Nuovo contenuto" # Sovrascrive
Add-Content .\output.txt "Riga aggiuntiva" # Appende
# Copia, sposta, elimina
Copy-Item .\source.txt .\dest.txt
Move-Item .\old.txt .\new.txt
Remove-Item .\file.txt
Remove-Item .\cartella -Recurse # Elimina cartella con contenuto
Strutture di Controllo
Condizionali
# If / ElseIf / Else
$temperatura = 25
if ($temperatura -gt 30) {
Write-Host "Caldo"
} elseif ($temperatura -gt 20) {
Write-Host "Piacevole"
} else {
Write-Host "Fresco"
}
# Switch (più efficiente di if/elseif per casi multipli)
$giorno = "Lunedì"
switch ($giorno) {
"Lunedì" { Write-Host "Inizio settimana" }
"Venerdì" { Write-Host "Fine settimana" }
"Sabato" { Write-Host "Weekend!" }
"Domenica" { Write-Host "Weekend!" }
default { Write-Host "Giorno lavorativo" }
}
Loop
# For classico
for ($i = 0; $i -lt 5; $i++) {
Write-Host "Iterazione: $i"
}
# ForEach (il più comune in PowerShell)
$servizi = Get-Service | Where-Object { $_.Status -eq "Stopped" }
foreach ($servizio in $servizi) {
Write-Host "Servizio fermo: $($servizio.Name)"
}
# ForEach-Object (nella pipeline)
1..5 | ForEach-Object { $_ * 2 } # Output: 2 4 6 8 10
# While
$contatore = 0
while ($contatore -lt 3) {
Write-Host "Contatore: $contatore"
$contatore++
}
Gestione Errori
# $ErrorActionPreference controlla il comportamento globale degli errori
$ErrorActionPreference = "Stop" # Trasforma tutti gli errori in eccezioni terminanti
try {
$contenuto = Get-Content "file-inesistente.txt" -ErrorAction Stop
Write-Host "File letto con successo"
}
catch [System.IO.FileNotFoundException] {
Write-Warning "File non trovato: $_"
}
catch {
# Cattura qualsiasi altro errore
Write-Error "Errore imprevisto: $($_.Exception.Message)"
}
finally {
# Eseguito sempre, con o senza errori (utile per cleanup)
Write-Host "Operazione completata."
}
Funzioni e Moduli
Funzioni Base
function Get-Saluto {
param(
[string]$Nome = "Mondo", # Parametro con valore di default
[int]$Ripetizioni = 1
)
for ($i = 0; $i -lt $Ripetizioni; $i++) {
Write-Output "Ciao, $Nome!"
}
}
# Chiamata
Get-Saluto -Nome "Mario" -Ripetizioni 3
Funzioni Avanzate (Advanced Functions)
Per script professionali, usa CmdletBinding per ottenere comportamenti da cmdlet nativi (supporto -Verbose, -WhatIf, -ErrorAction, ecc.):
function Invoke-Backup {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory, ValueFromPipeline)]
[string]$SourcePath,
[Parameter(Mandatory)]
[string]$DestinationPath,
[switch]$Compress
)
process {
if ($PSCmdlet.ShouldProcess($SourcePath, "Backup")) {
Write-Verbose "Backup di '$SourcePath' verso '$DestinationPath'"
Copy-Item -Path $SourcePath -Destination $DestinationPath -Recurse
Write-Output "Backup completato."
}
}
}
# Uso con -WhatIf per simulare senza eseguire
Invoke-Backup -SourcePath "C:\dati" -DestinationPath "D:\backup" -WhatIf
# Uso con -Verbose per logging dettagliato
Invoke-Backup -SourcePath "C:\dati" -DestinationPath "D:\backup" -Verbose
Gestione Moduli
# Trova moduli disponibili nel repository PSGallery
Find-Module -Name *Azure*
# Installa un modulo
Install-Module -Name Az -Scope CurrentUser
# Importa un modulo nella sessione corrente
Import-Module Az
# Elenca i moduli installati
Get-Module -ListAvailable
# Elenca i cmdlet di un modulo specifico
Get-Command -Module Az.Compute
Amministrazione di Sistema
Utenti Locali
Get-LocalUser
New-LocalUser -Name "mario" -Password (ConvertTo-SecureString "P@ss!" -AsPlainText -Force) -FullName "Mario Rossi"
Add-LocalGroupMember -Group "Administrators" -Member "mario"
Remove-LocalUser -Name "mario"
Servizi
Get-Service
Get-Service -Name "wuauserv" # Windows Update
Start-Service -Name "wuauserv"
Stop-Service -Name "wuauserv"
Restart-Service -Name "wuauserv"
Set-Service -Name "wuauserv" -StartupType Disabled
Processi
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
Stop-Process -Name "notepad" -Confirm
Start-Process "notepad.exe"
Registro di Sistema
# Naviga nel registro come se fosse un filesystem
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name "ProductName"
Set-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Debug" -Value 1
New-Item -Path "HKCU:\Software\MyApp"
Remove-Item -Path "HKCU:\Software\MyApp" -Recurse
PowerShell Remoting
PowerShell Remoting consente di eseguire comandi su computer remoti.
Tramite WinRM (Windows)
# Abilita il remoting (da eseguire come amministratore)
Enable-PSRemoting -Force
# Sessione interattiva
Enter-PSSession -ComputerName Server01 -Credential (Get-Credential)
# Esegui un comando su un computer remoto
Invoke-Command -ComputerName Server01 -ScriptBlock {
Get-Service | Where-Object { $_.Status -eq "Stopped" }
}
# Esegui uno script locale su computer remoti
Invoke-Command -ComputerName Server01, Server02 -FilePath .\script.ps1
# Gestione sessioni persistenti
$sessione = New-PSSession -ComputerName Server01 -Credential (Get-Credential)
Invoke-Command -Session $sessione -ScriptBlock { Get-Process }
Remove-PSSession $sessione
Tramite SSH (Cross-Platform, PowerShell 7+)
# Connessione SSH a un server Linux
Enter-PSSession -HostName ubuntu-server -UserName admin -SSHTransport
# Esegui comandi remoti via SSH
Invoke-Command -HostName ubuntu-server -UserName admin -ScriptBlock { uname -a }
Sicurezza in PowerShell
La sicurezza è una priorità per qualsiasi script destinato a produzione o ambienti aziendali.
Firma Digitale degli Script (Code Signing)
In ambienti con policy AllSigned, gli script devono essere firmati:
# Ottieni il certificato di firma (da un'autorità di certificazione aziendale o auto-firmato)
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
# Firma lo script
Set-AuthenticodeSignature -FilePath .\script.ps1 -Certificate $cert
# Verifica la firma
Get-AuthenticodeSignature .\script.ps1
Gestione Sicura delle Credenziali
Non inserire mai password in chiaro negli script!
# Chiedi le credenziali in modo sicuro
$cred = Get-Credential
# Salva una password come SecureString (cifrata, leggibile solo dall'utente corrente)
$password = Read-Host -Prompt "Inserisci password" -AsSecureString
$passwordCifrata = ConvertFrom-SecureString $password
$passwordCifrata | Out-File .\password.enc # Salva cifrata su disco
# Ricarica la password
$passwordCifrata = Get-Content .\password.enc | ConvertTo-SecureString
Script Block Logging e Auditing
Per ambienti aziendali, abilita la registrazione degli script tramite Group Policy:
Computer Configuration → Administrative Templates → Windows Components →
Windows PowerShell → Turn on Script Block Logging → Enabled
Gli script eseguiti vengono registrati nel Windows Event Log (Event ID 4104), fondamentale per audit e incident response.
Constrained Language Mode
Limita le funzionalità di PowerShell per ridurre la superficie d'attacco:
# Verifica la modalità corrente
$ExecutionContext.SessionState.LanguageMode
# In CLM, tipi .NET arbitrari e COM objects sono bloccati
# Viene tipicamente applicato tramite AppLocker o WDAC
PowerShell e il Cloud
PowerShell è lo strumento ufficiale per gestire Microsoft Azure:
# Installa il modulo Az
Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force
# Autenticazione ad Azure
Connect-AzAccount
# Operazioni comuni
Get-AzResourceGroup # Elenca i Resource Group
Get-AzVM -ResourceGroupName "MyRG" # Elenca le VM
# Esempio: avvia tutte le VM ferme in un Resource Group
Get-AzVM -ResourceGroupName "MyRG" -Status |
Where-Object { $_.PowerState -eq "VM deallocated" } |
ForEach-Object { Start-AzVM -ResourceGroupName "MyRG" -Name $_.Name }
Best Practice per Script Professionali
Qualità del Codice con PSScriptAnalyzer
PSScriptAnalyzer è il linter ufficiale per PowerShell:
# Installa
Install-Module -Name PSScriptAnalyzer -Scope CurrentUser
# Analizza uno script
Invoke-ScriptAnalyzer -Path .\script.ps1
# Analizza una directory intera
Invoke-ScriptAnalyzer -Path .\scripts\ -Recurse
Testing con Pester
Pester è il framework di testing standard per PowerShell:
# Installa Pester
Install-Module -Name Pester -Scope CurrentUser -Force
# Esempio di test (file: Get-Saluto.Tests.ps1)
Describe "Get-Saluto" {
It "Restituisce il saluto corretto" {
$risultato = Get-Saluto -Nome "Mario"
$risultato | Should -Be "Ciao, Mario!"
}
It "Usa 'Mondo' come default se nessun nome è fornito" {
Get-Saluto | Should -Be "Ciao, Mondo!"
}
}
# Esegui i test
Invoke-Pester .\Get-Saluto.Tests.ps1
Checklist Best Practice
- Usa
CmdletBindingnelle funzioni per supportare-Verbose,-WhatIf,-ErrorAction - Tipizza i parametri esplicitamente (
[string],[int],[Parameter(Mandatory)]) - Usa
$ErrorActionPreference = "Stop"all'inizio degli script critici - Commenta il codice con
#per riga e<# ... #>per blocchi - Non usare alias negli script (
ls,cd,?) — usa i nomi completi per leggibilità - Gestisci sempre le credenziali con
SecureStringoGet-Credential - Usa
Write-Verboseper logging, nonWrite-Host(che bypassa la pipeline) - Analizza con PSScriptAnalyzer prima di distribuire uno script
- Scrivi test con Pester per gli script riutilizzati in produzione
- Controlla la Execution Policy prima del deployment
Risorse Utili
Documentazione ufficiale:
- Microsoft Learn – PowerShell
- PowerShell Gallery — repository di moduli e script
- GitHub – PowerShell
Community:
Conclusione
Hai ora una base teorica e pratica solida per iniziare a usare PowerShell in contesti reali. Gli argomenti coperti — dalla pipeline alla gestione remota, dalla sicurezza al cloud — ti posizionano bene per l'uso professionale di questo strumento.
La competenza reale arriva con la pratica costante: automatizza le tue attività quotidiane, analizza i tuoi script con PSScriptAnalyzer e, quando sei pronto, scrivi i tuoi primi test con Pester.