Cosa è PowerShell
PowerShell è una shell, ovvero un’interfaccia a linea di comando verso il sistema operativo, nato intorno al 2005. Il nome originale era WSH, poi diventò Microsoft PowerShell per abbandonare infine il marchio e restare solo come PowerShell, appunto.
Esempio di shell (Linux Mint)
Si utilizza come mezzo per interagire con i vari componenti del sistema operativo senza utilizzare la GUI (ovvero l’interfaccia grafica), oppure per automatizzare operazioni ripetitive, ottenere informazioni dal sistema stesso, ecc…
La shell di PowerShell su Windows Terminal
L’interfaccia a linea di comando non è la sola. Infatti, si possono anche creare script che potranno poi essere eseguiti al bisogno, oppure per creare dei moduli che potranno contenere funzioni personalizzate da utilizzare in caso di necessità.
Per lo sviluppo di script, a partire dalla versione di PowerShell 2.0 è disponibile PowerShell ISE (Integrated Scripting Environment), che sarà supportato fino a Windows Server 2016. Per lo sviluppo può essere utilizzato anche Visual Studio Code.
Come funziona
PowerShell è basato su cmdlets, ovvero moduli .NET che si adattano all’ambiente. Di base contiene tutte le funzioni destinate all’amministrazione del sistema operativo, ma moduli aggiuntivi possono essere aggiunti per gestire l’amministrazione di applicativi, sistemi e hardware.
Tutti i comandi dispongono di un help interno, che può essere invocato col comando:
get-help nomecomando
per esempio:
get-help get-date
darà questo output:
NAME
Get-Date
SYNTAX
Get-Date [[-Date] ] [-Year ] [-Month ] [-Day ] [-Hour ] [-Minute
] [-Second ] [-Millisecond ] [-DisplayHint {Date | Time | DateTime}] [-Format
] [-AsUTC] []
Get-Date [[-Date] <datetime>] -UFormat <string> [-Year <int>] [-Month <int>] [-Day <int>] [-Hour
<int>] [-Minute <int>] [-Second <int>] [-Millisecond <int>] [-DisplayHint {Date | Time |
DateTime}] [-AsUTC] [<CommonParameters>]
Get-Date -UnixTimeSeconds <long> [-Year <int>] [-Month <int>] [-Day <int>] [-Hour <int>]
[-Minute <int>] [-Second <int>] [-Millisecond <int>] [-DisplayHint {Date | Time | DateTime}]
[-Format <string>] [-AsUTC] [<CommonParameters>]
Get-Date -UnixTimeSeconds <long> -UFormat <string> [-Year <int>] [-Month <int>] [-Day <int>]
[-Hour <int>] [-Minute <int>] [-Second <int>] [-Millisecond <int>] [-DisplayHint {Date | Time |
DateTime}] [-AsUTC] [<CommonParameters>]
ALIASES
None
REMARKS
Get-Help cannot find the Help files for this cmdlet on this computer. It is displaying only
partial help.
-- To download and install Help files for the module that includes this cmdlet, use
Update-Help.
-- To view the Help topic for this cmdlet online, type: "Get-Help Get-Date -Online" or
go to https://go.microsoft.com/fwlink/?LinkID=2096615.
Più avanti vedremo che anche il comando get-help dispone di parametri per estendere le informazioni visualizzate.
L’interfaccia a linea di comando, così come anche PowerShell ISE, dispongono di una funzione di auto-completamento dei comandi, analogamente alle shell *nix-like, come Linux per esempio. Ciò significa che nella console potremo scrivere solo il comando get-he e poi premendo il tasto TAB il comando verrà automaticamente completato in get-help. Più comandi con parti in comune potranno essere visualizzati ad ogni pressione del tasto TAB.
Iniziamo con una botta di vita (ma non spaventatevi che rivedremo tutto con calma dopo)
Cominciamo ora a prendere confidenza con la shell. Per aprirla, basta premere la combinazione di tasti Win + R e digitare powershell seguito da invio.
Ecco quindi come si presenta (di solito):
Come vedete, è simile alla vecchia shell CMD (che tra l’altro per motivi di compatibilità è sempre disponibile). Infatti, tutti i comandi che conoscete funzionano anche qui (ad esempio DIR, CD, ecc…).
Ma questo ambiente, ovvio, nasce principalmente per la gestione tramite comandi PowerShell. Iniziamo quindi a vedere qualche semplice comando, tanto per scaldarci un po’.
Inseriamo quindi il comando:
write-host "Hello World!"
e premiamo Invio.
Ecco cosa succede:
Il comando write-host visualizza un testo sulla console. Facile no ?
Adesso iniziamo con qualcosa di più serio. Inseriamo questi comandi:
write-host "Buongiorno $(Read-Host "Inserisci il tuo nome")"
Ecco il risultato:
Cosa abbiamo fatto qui ? Non spaventatevi In realtà abbiamo passato all’istruzione write-host il nome inserito tramite read-host (che legge l’input da tastiera). Vedremo più avanti come fare questi giochini.
La versione più semplice è questa:
$Nome = Read-Host "Inserisci il tuo nome"
seguito da
write-host "Buongiorno $Nome"
Per il momento, abbiamo visto queste due istruzioni:
write-host – per visualizzare un testo sulla console
read-host – per leggere un input da tastiera
Ora passiamo a qualche comando per visualizzare le informazioni del sistema. Supponiamo, per esempio, di volere controllare i servizi che sono attivi. Il comando da usare è get-service:
PS C:\WINDOWS\system32> Get-Service
Status Name DisplayName
------ ---- -----------
Stopped AarSvc_81417 Agent Activation Runtime_81417
Running AdobeARMservice Adobe Acrobat Update Service
Stopped AJRouter AllJoyn Router Service
Stopped ALG Application Layer Gateway Service
Running AMD Crash Defen… AMD Crash Defender Service
Running AMD External Ev… AMD External Events Utility
Stopped AppIDSvc Application Identity
Running Appinfo Application Information
Stopped AppMgmt Application Management
Stopped AppReadiness App Readiness
Stopped AppVClient Microsoft App-V Client
Running AppXSvc AppX Deployment Service (AppXSVC)
Running ArmouryCrateSer… ARMOURY CRATE Service
Stopped ArmouryLiveUpdate Armoury Live Update
Running asComSvc ASUS Com Service
Stopped AssignedAccessM… AssignedAccessManager Service
Stopped asus ASUS Update Service (asus)
Running AsusCertService AsusCertService
Stopped asusm ASUS Update Service (asusm)
Running AudioEndpointBu… Windows Audio Endpoint Builder
Running Audiosrv Windows Audio
Running AUEPLauncher AMD User Experience Program Data Up…
Stopped autotimesvc Cellular Time
Stopped AxInstSV ActiveX Installer (AxInstSV)
Stopped BcastDVRUserSer… GameDVR and Broadcast User Service_…
Stopped BDESVC BitLocker Drive Encryption Service
Stopped BEService BattlEye Service
Running BFE Base Filtering Engine
Running BITS Background Intelligent Transfer Ser…
Stopped BluetoothUserSe… Bluetooth User Support Service_81417
Running BrokerInfrastru… Background Tasks Infrastructure Ser…
Questa lunga lista in realtà non è molto leggibile, e poi mescola servizi in stato running con quelli stopped, e noi vogliamo vedere solo i servizi attivi (Running). Proviamo a filtrare i risultati. Inseriamo questo comando:
Get-Service | Where-Object { $_.Status -eq "Running" }
Niente paura: è più semplice di quello che sembra. Iniziamo dal carattere | (in gergo pipe). Questo carattere significa semplicemente “prendi tutto quello che il comando precedente restituisce“.
Un doveroso chiarimento: dovete sapere che tutti i comandi PowerShell restituiscono un oggetto .NET, o per chiarire una struttura dati. La struttura può variare a seconda del comando, ma ha sempre almeno un oggetto all’interno.
Nel nostro caso, proviamo a inserire questo comando:
$list = Get-Service
Ecco cosa succede:
PS C:\WINDOWS\system32> $list = Get-Service
PS C:\WINDOWS\system32>
Come vedete non succede nulla, però ora in $list abbiamo la stessa lista che abbiamo visto all’inizio, con tutti i servizi.
Provate a inserire:
$list
e premete invio. Ecco il risultato:
Esattamento lo stesso elenco di prima. In pratica $list contiene tutto l’output del comando Get-Services. Per comprendere quello che dicevo prima, cioè che i comandi PowerShell restituiscono un oggetto, inserite questo e premete invio:
$list[0]
Ecco il risultato:
Esatto ! $list è un array, e ogni riga contiene uno dei servizi visualizzati. Per averne conferma, inserite questo comando e premete invio:
$list.GetType()
Avrete questo risultato:
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Nota: un array è una matrice. $list[0] è la prima riga della matrice. Ogni matrice poi è suddivisa in colonne (fields) che contengono i dati relativi all’oggetto.
Ma non è finita qui: la riga contiene molte più informazioni, che però per default vengono limitate a quelle essenziali. Per vederle tutte, inserite questo:
$list[0] | Select-Object *
Poi premete invio. Ecco cosa verrà visualizzato:
Come vedete, queste sono tutte le informazioni relative ad un servizio, il primo della lista.
Nota: in PowerShell gli array iniziano con l’indice 0. Quindi $list[0] è il primo elemento, $list[1] il secondo, e così via.
Ora, esaminiamo più in profondità questo array. Come vedete vi sono vari dati all’interno del singolo elemento. Quindi, per trovare lo stato del servizio (se in esecuzione o stopped) dobbiamo utilizzare il campo Status. Per visualizzarlo, quindi, basterà inserire:
$list[0].Status
e premere invio:
Ecco fatto. Quindi adesso forse è più chiaro quello che abbiamo fatto in precedenza:
Get-Service | Where-Object { $_.Status -eq "Running" }
Il comando esegue le seguenti operazioni:
Ottiene una lista di tutti i dati sui servizi
Passa tutti i dati all’operazione seguente il carattere |
Where-object filtra tutti gli elementi dell’array dove il campo Status equivale (-eq) a “Running” e ne restituisce l’elenco.
Sì, direte voi, ma cos’è $_. ? $_. è la pipeline variable, e semplicemente identifica “qualunque riga dell’array restituito dal comando precedente“. Quindi, in $_.Status, la parte $_. sarebbe $rigaarray[0], $rigaarray[1] e così via.
Confusi ? No problem Questo era soltanto un assaggio del modo in cui PowerShell opera. Più avanti chiariremo meglio tutti questi concetti.
Continuiamo con le cose semplici
Ora che abbiamo avuto un terribile impatto, vediamo i concetti basilari di PowerShell. Mi sono divertito a spaventarvi un po’ prima
Dunque ecco qui le basi:
La variabili sono identificate dal carattere $, quindi $list, $elenco, $listadellaspesa sono tutte variabili.
Per i test, abbiamo gli operatori che sono -eq per uguaglianza, -ne per differenza. Poi ci sono altri operatori, come -like (per i pattern, che vedremo).
I test usano il classico if seguito dalle condizioni, tra parentesi, quindi if ($variabile -eq 0) seguito dalle graffe che racchiudono il corpo dell’if { #qualsiasi_operazione }
I commenti inziano con il carattere # per esempio: #questo è un commento
I cicli for, while, ecc… usano sempre le graffe {} per racchiudere il corpo delle operazioni.
Nota: le variabili in PowerShell sono identificate dal carattere $ seguito dal nome della variabile stessa. I tipi non sono espliciti: una variabile può contenere qualsiasi valore (numero, stringa, $null, valori booleani, ecc…)
Qualche esempio:
$Nome = Read-Host "Inserisci il tuo nome"
If ( $Nome -eq "TechCorsair" )
{
write-host "Ma tu sei il grande $Nome !"
}
else
{
write-host "Buongiorno $Nome"
}
Per visualizzare del testo, si usano i doppi apici ” oppure i singoli ‘. La differenza sta nel fatto che usando i doppi apici ” si possono inserire nelle stringhe i nomi delle variabili, e queste restituiranno il loro valore nella visualizzazione:
$Testo = "TechCorsair"
write-host "Ciao $Testo"
risultato:
Ciao TechCorsair
Usando i singoli apici:
write-host 'Ciao $Testo'
risultato:
Ciao $Testo
Quindi ricordatevi che se volete vedere il valore di una variabile, dovete usare i doppi apici.
Qui ormai siamo arrivati allo scripting con PowerShell, e forse è il caso di iniziare ad utilizzare PowerShell ISE.
Per aprirlo, aprite il menu start e iniziate a scrivere powersh. A questo punto dovrebbe comparirvi in elenco:
Cliccateci per aprirlo:
Così è come si presenta. Nella parte alta potete editare lo script, la parte bassa è l’output e a destra abbiamo il command reference, un aiuto per cercare i comandi.
Se non vi piace l’aspetto, PowerShell ISE è personalizzabile utilizzando dei temi. QUI potete trovare una bellissima raccolta. Questo per esempio è il mio tema (si chiama Ambients per i più curiosi):
Perchè non iniziare subito con lo script che abbiamo visto prima ? Copiatelo da questa pagina e incollate nell’area dello script.
Per eseguire lo script, basta premere il pulsante verde, oppure premere F5:
Seguiamo quindi lo script:
Inseriamo il nome TechCorsair e premiamo invio. Ecco il risultato:
Riproviamo con un altro nome. premiamo di nuovo F5, inseriamo un altro nome, e premiamo invio:
Come vedete quando il nome è diverso da TechCorsair, il messaggio è differente (ramo else del blocco if).
Note: -eq e -ieq sono equivalenti. Sono operatori di uguaglianza “case insensitive” (non differenziano tra minuscole e maiuscole). Se volete che il sistema riconosca le differenze tra maiuscole e minuscole dovete usare -ceq (che è case sensitive).
Avete anche visto che i colori dell’output sono diversi. Questo si ottiene aggiungendo il parametro -foregroundcolor al comando write-host.
Tutti i parametri li potete vedere dal “command pane” a destra. Per cercare uno specifico comando, basta inserire il nome nel campo name:
Quindi cliccare sul risultato della ricerca:
Premendo poi sul pulsante help (indicato dalla freccia) comparirà l’help completo per quel comando, inclusi gli esempi di utilizzo:
Questo è un sistema molto comodo, soprattutto agli inizi, per avere un rapido riferimento. Se lo chiudete per errore, basta selezionare dal menu View la voce Show Command Add-on:
Come funzionano i test
I test funzionano nello stesso modo di altri linguaggi. Quindi abbiamo una direttiva if seguita dal test e quindi dai rami di condizione vera o falsa. Schematicamente:
if (condizione è vera)
{
#esegui questa parte di codice se la condizione è vera
}
else
{
#esegui questa parte di codice se la condizione è falsa
}
se abbiamo più condizioni da testare, possiamo usare elseif:
if (condizione 1 è vera)
{
#esegui questa parte di codice se la condizione 1 è vera
}
elseif (condizione 2 è vera)
{
#esegui questa parte di codice se la condizione 2 è vera
}
elseif (condizione n è vera)
{
#esegui questa parte di codice se la condizione n è vera
}
else
{
#esegui questa parte di codice se nessuna delle precedenti condizioni è vera
}
Niente di trascendentale insomma. Si possono anche fare test sul valore di una variabile con varie azioni basate sul valore stesso, usando il comando switch. Per esempio:
switch (valore-da-testare)
{
1 {"E' uno.";break}
2 {"E' due.";break}
3 {"E' tre.";break}
4 {"E' quattro.";break}
Default {"E' un altro valore";break}
}
I cicli for…next
Facile, anche qui. E molto simile ad altri linguaggi:
for ($num = 1 ; $num -le 10 ; $num++){ "I count $num"}
Quindi, valore iniziale, limite, incremento e blocco operazioni. Nell’esempio num$ da 1 a 10 con incrementi di 1. Il blocco visualizzerà i valori da 1 a 10.
Nota curiosa: io non ho mai utilizzato i cicli for nei miei script di PowerShell. Eppure lo uso per lavoro tutti i giorni.
I cicli While
Stesso discorso qui per il ciclo while. Il loop continuerà finchè la condizione sarà vera, dopodichè si interromperà. Segue questo schema:
while (<condition>){<statement list>}
Quindi, per fare un esempio:
$i = 0
while ($i -le 10)
{
Write-Host $i
$i++
}
Qui il ciclo continuerà finche $i raggiungerà il valore 10. Al raggiungimento del valore 11 il ciclo si interromperà.
I cicli do…while e do…until
Anche in questo caso, i cicli sono due, e il test viene effettuato a fine ciclo, invece che all’inizio come nella direttiva while.
do {<statement list>} while (<condition>)
e
do {<statement list>} until (<condition>)
La differenza tra i due cicli è puramente semantica. While testerà il permanere di una condizione vera, mentre Until il permanere di una condizione falsa.
Il ciclo Foreach
Questo è il ciclo forse più interessante, perchè è quello che analizza un elemento in un gruppo di oggetti. Possiamo tranquillamente utilizzare l’esempio fatto in precedenza, quello dei servizi in esecuzione, per spiegare questo ciclo.
Come dicevamo, eravamo stati in grado di ottenere la lista dei servizi in esecuzione da questo comando:
$list = Get-Service
Bene, ora per spiegare come funziona il ciclo Foreach, useremo la lista appena ottenuta:
$list = Get-Service
foreach ($item in $list)
{
if($item.Status -eq "Running")
{
Write-Host "$($item.DisplayName) is Running" -ForegroundColor Green
}
else
{
Write-Host "$($item.DisplayName) is $($item.Status)" -ForegroundColor Red
}
}
Il ciclo foreach preleverà una singola riga dell’array ($item) alla volta e la testerà per verificare se il servizio è in stato Running oppure in un altro stato. Se è Running verrà visualizzato in verde, altrimenti verrà visualizzato lo stato in rosso:
Se vi chiedete perchè è stata usata questa strana sintassi per l’elemento dell’array all’interno della stringa write-host:
$Write-Host "$($item.DisplayName) is Running"
Il motivo è semplice: gli elementi dell’array per essere visualizzati correttamente vanno convertiti in stringa. Racchiuderlo tra parentesi con il $ davanti ottiene questo effetto. Se si utilizza il solo elemento dell’array, la visualizzazione non è corretta, poichè viene visualizzato il tipo di elemento, e non il valore:
System.ServiceProcess.ServiceController.DisplayName is Running
Bellissimo, vero ?
Prima di salutarci
Questa è solo la prima parte. Abbiamo visto cosa è PowerShell, qualche comando base, l’interfaccia ISE, i cicli e qualche esempio di script. Credo che per oggi possa bastare.
Non vi spaventate se qualcosa non vi è ancora chiaro. E’ roba difficile, però affrontata nel giusto modo dopo un po’ diventerà automatico apprendere i concetti.
Nei prossimi articoli cercheremo di addentrarci ancora di più nel meraviglioso mondo dello scripting, e inizieremo a mettere in pratica qualche tecnica di programmazione, unita a nuovi comandi.
A presto !
Comments