Classi PowerShell: Iniziare

PowerShell è un linguaggio orientato agli oggetti. Quando si eseguono comandi e si visualizza l’output sullo schermo, si tratta di oggetti. Gli oggetti non vengono creati dal nulla; gli sviluppatori li creano o, più specificamente, li istanziano con classi. Le classi di PowerShell rappresentano le definizioni o gli schemi di tali oggetti.

Anche se potresti essere familiare con la creazione di oggetti tramite comandi come New-Object e l’utilizzo dell’acceleratore di tipo pscustomobject, questi non sono “nuovi” oggetti. I tipi di oggetti prodotti da questi metodi sono di un determinato tipo. Le classi di PowerShell definiscono il tipo.

In questo tutorial, imparerai come iniziare a utilizzare le classi di PowerShell. Creerai la tua prima classe con costruttori, imparerai come creare oggetti dalla tua classe e personalizzerai la tua classe con proprietà e metodi.

Per approfondire i termini come oggetti, proprietà e metodi, consulta l’articolo del blog Tornando alle basi: comprensione degli oggetti di PowerShell.

Prerequisiti

Creazione della tua prima classe e oggetto

Prima di poter imparare tutti i dettagli di una classe di PowerShell, dovresti prima seguire la creazione di una classe semplice. Gli argomenti più avanzati li affronterai più avanti.

La creazione della tua prima classe sarà un po’ simile alla creazione di una funzione. La sintassi di base è la stessa. Una classe viene creata a partire da una definizione come una funzione. A differenza delle funzioni, però, la prima riga non inizia con function seguito dal nome della funzione, ma inizia con class seguito dal nome del tipo di oggetto.

Di seguito vedrai lo scheletro di base di una classe chiamata studente.

class student {

}

Le classi hanno proprietà che assomigliano a parametri che sono attributi che descrivono quella classe. L’esempio qui sotto mostra una classe chiamata studente con due proprietà: Nome e Cognome.

Quando si definisce una proprietà, si dovrebbe sempre definire un tipo che imposta uno specifico “schema” per ciò che i valori della proprietà possono contenere. Nell’esempio qui sotto, entrambe le proprietà sono definite come stringhe.

Si dovrebbero sempre definire i tipi di proprietà. Capirai il motivo più avanti.

class student {
    [string]$FirstName
    [string]$LastName
}

Dopo aver definito una classe, crea un oggetto da essa o istanzia un oggetto. Ci sono diversi modi per istanziare oggetti da classi; un modo comune è utilizzare gli acceleratori di tipo come [studente] che rappresentano la classe, seguito da un metodo predefinito chiamato new() che viene fornito con ogni classe.

Utilizzare la scorciatoia dell’acceleratore di tipo è equivalente alla creazione di un oggetto utilizzando il comando New-Object.

New-Object -TypeName student

Una volta creato un oggetto da quella classe, assegna valori alle proprietà. L’esempio di seguito assegna i valori “Tyler” e “Muir” alle proprietà “FirstName” e “LastName”.

class student {
    [string]$FirstName
    [string]$LastName
}
$student1 = [student]::new()
$student1.FirstName = 'Tyler'
$student1.LastName = 'Muir'
$student1

Una volta creato l’oggetto e assegnati i valori alle proprietà, ispeziona l’oggetto chiamando la variabile a cui hai assegnato l’oggetto, come mostrato di seguito.

Creating an object from the student class.

Ora che hai creato un oggetto da una classe, invia quell’oggetto come qualsiasi altro oggetto in PowerShell al cmdlet “Get-Member” per ispezionarlo. Puoi vedere di seguito che l’oggetto contenuto nella variabile “$student1” è di tipo student.

Il nome della classe corrisponderà sempre al tipo di oggetto.

Notare che “Get-Member” restituisce quattro metodi e due proprietà. Le proprietà probabilmente ti sembrano familiari, ma i metodi no. PowerShell aggiunge alcuni metodi di default, ma puoi aggiungere i tuoi metodi o modificare i metodi di default.

Showing members from custom student object.

Creare Metodi

Nell’esempio precedente hai visto alcuni metodi di default sull’oggetto, ma probabilmente vorrai crearne di propri. Per farlo, devi definire uno o più metodi all’interno della definizione della classe.

A method definition looks like below with an output type that defines what type of object is returned from this method, the name of the method, and the code to execute inside of a scriptblock.

[<output type>]<name>() {
	<code that runs when the method is executed>
}

Notare le parentesi “()” dopo il nome. Qui puoi definire i parametri del metodo (trattati in seguito). I parametri del metodo ti consentono di modificare la funzionalità di un metodo proprio come puoi fare con i parametri di una funzione.

Se hai già scritto ed eseguito funzioni PowerShell in precedenza, il metodo scriptblock dovrebbe risultarti familiare, ma ci sono un paio di regole speciali per i metodi che dovresti conoscere.

Il comando return è obbligatorio

Le funzioni PowerShell restituiscono oggetti semplicemente inserendo l’oggetto ovunque nella funzione, come nell’esempio seguente.

function foo {
	$object = Get-Service
	$object ## Invio semplicemente l'oggetto al flusso di processo
}

Tuttavia, a differenza delle funzioni, se un metodo restituisce un oggetto, devi utilizzare il costrutto return come mostrato di seguito.

[string]GetName() {
	return 'foo'
}

Utilizzo della variabile $this

Un’altra differenza tra i metodi e le funzioni è la variabile $this. La variabile $this, definita all’interno di un metodo, fa riferimento alle proprietà o ad altri metodi dell’oggetto corrente.

Di seguito è riportato un esempio di un metodo chiamato GetName() aggiunto alla classe student che concatena il valore delle proprietà FirstName e LastName e le restituisce.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
}

Ora puoi chiamare il metodo GetName() utilizzando la notazione del punto come mostrato di seguito. Se hai precedentemente assegnato valori a FirstName e LastName, GetName() li restituirà.

Creating a class with a method and showing to output.

Aggiunta di parametri ai metodi

Nell’esempio precedente, quando hai eseguito il comando $student1.GetName(), hai chiamato il metodo GetName() così com’è. All’interno delle parentesi, puoi definire parametri come nelle funzioni.

Il metodo GetName() restituiva semplicemente i valori impostati per le proprietà FirstName e LastName. Ma cosa succede se preferisci avere un metodo per impostare le proprietà che GetName() può quindi ottenere? In tal caso, è necessario definire i parametri del metodo.

Definisci i parametri del metodo includendo uno o più parametri separati da una virgola tra parentesi, come mostrato di seguito.

Nota il tipo di output [void]. Quando un metodo non restituisce nulla, non è necessario un costrutto return, e devi definire il tipo di output come [void] per indicare a PowerShell che il metodo non restituisce nulla.

[void]SetName([string]$Name) {

}

Ad esempio, forse il metodo SetName() accetta un nome completo (nome e cognome). In tal caso, nella scriptblock, puoi dividere questa stringa e assegnare il nome e il cognome in questo modo.

Inserendo il metodo SetName() nella classe student, ecco come appare ora.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

Ora puoi passare un nome completo come parametro al metodo SetName(), che imposta le proprietà FirstName e LastName dell’oggetto corrente.

Creating a class with a void method and showing the output when it is run.

Overload dei metodi

Forse desideri definire diversi set di parametri per un metodo. Similmente a come funzionano i set di parametri nelle funzioni e nei cmdlet, puoi definire diversi “contesti” o firme del metodo.

Forse ti piacerebbe impostare i parametri FirstName e LastName passando un nome completo al metodo SetName() o passando il nome e cognome separatamente. Non è necessario scegliere; puoi definirli entrambi con le firme dei metodi.

Quando si definiscono più firme di metodi in una classe, ciò viene chiamato overload.

Riutilizzando l’esempio della sezione precedente, è possibile creare un overload per il metodo SetName() per accettare due stringhe anziché una. Quando si passano due stringhe anziché una, il metodo SetName() assume che la prima stringa sia il FirstName e la seconda stringa sia il LastName. Con quell’overload, la classe avrebbe l’aspetto seguente.

class student {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
    
    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}
Showing that the method overload works by providing either one or two strings.

Costruttori di classe

Ogni volta che si istanzia un oggetto con il metodo new() o in altro modo, è possibile indicare a PowerShell di eseguire del codice definito dall’utente chiamato costruttore. I costruttori sono simili ai metodi, ma vengono eseguiti automaticamente quando PowerShell istanzia un oggetto.

Ogni classe ha un costruttore predefinito. Questo costruttore predefinito non fa molto; si occupa solo di istanziare l’oggetto. È possibile visualizzare il costruttore predefinito visualizzando l’output del metodo New. È possibile vedere di seguito che questa riga restituisce un singolo metodo new().

[student]::New
Default PowerShell constructor

Overload del costruttore

Forse desideri impostare un valore per le proprietà FirstName e LastName non appena crei l’oggetto, anziché utilizzando la notazione punto tipica. In tal caso, puoi creare un costruttore con un parametro che chiama quindi SetName().

Di seguito è riportato un esempio di un costruttore per la classe student. Nota che il costruttore non ha un nome specifico o è preceduto da un tipo di output. I costruttori utilizzano sempre lo stesso nome della classe.

Chiamare un metodo esistente nel costruttore ci consente di riutilizzare il metodo che abbiamo già scritto per gestire l’impostazione delle variabili.

student([string]$Name) {
	$this.SetName($Name)
}

E di seguito vedrai che il costruttore è stato aggiunto alla classe student.

class student {
    [string]$FirstName
    [string]$LastName
    
    student([string]$Name) {
        $this.SetName($Name)
    }

    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

Quando istanzi un nuovo oggetto student e passi un parametro di tipo stringa, le proprietà dell’oggetto avranno immediatamente i valori attesi.

Showing the output from using the constructor with a string

Ora puoi vedere nuovamente il costruttore sovraccaricato con [student]::New. Nota che il nuovo costruttore sovraccaricato è definito con un parametro Name.

Overloaded constructor

Definire un costruttore predefinito e sovraccaricato

Ora che hai un costruttore sovraccaricato nella tua classe student, PowerShell sovrascrive il costruttore predefinito. Ma puoi ottenerlo nuovamente creandone uno manualmente senza parametri.

student() {}

Puoi vedere come appare nella classe student qui sotto.

class student {
    [string]$FirstName
    [string]$LastName

    student([string]$Name) {
        $this.SetName($Name)
    }

    student() {}

    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }
}

Ora controlla nuovamente i costruttori. Ora vedrai entrambi i costruttori.

[student]::New
Creating a default and custom constructor

Ereditarietà di classe

Come tutte le altre lingue orientate agli oggetti, è possibile costruire classi PowerShell in modo gerarchico con più classi. Ogni classe può avere classi “genitore” e “figlio” che partono da scopi meno specifici e più generici e aumentano la specificità.

Ad esempio, la nostra classe student rappresenta uno studente universitario (figlio/specifico). Quello studente universitario è una persona (genitore/generico). Questi due concetti sono correlati e formano una gerarchia.

A child class can inherit a parent class which means it can hold all properties and methods (members) defined via a parent class. We know that a person class may have properties like eye_color, height, and weight and perhaps a method called SetHeight().

Se uno studente è una persona, quello studente ha comunque quelle proprietà e metodi. Sarebbe duplicare lo sforzo implementare gli stessi membri sulla classe student che la classe person già ha. È possibile definire l’ereditarietà di classe per definire automaticamente tutti i membri della classe person sulla classe student.

Se questo non ha senso ora, avrà senso mentre procediamo con una demo.

Demo di Ereditarietà di Classe

Innanzitutto, fai una copia della classe student che hai creato in precedenza, rimuovi i costruttori e rinominala come classe person. La tua classe person dovrebbe apparire come la seguente classe.

A student, of course, has a first name and last name, but the class can be described more accurately by labeling it as a person. When creating a more “generic” class like this, you can create more specific “child” classes from it.

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

Ora, crea un paio di classi che rappresentano una persona ma hanno un ruolo più specifico. Ad esempio, nel frammento di codice sottostante, hai ora una classe teacher e student.

class teacher {
    [int]$EmployeeId
}

class student {
    [int]$StudentId
}

Così come sono, la classe teacher e student sono mutualmente esclusive rispetto alla classe person. Non hanno alcuna relazione ma non possono ereditare alcun membro di classe della classe person. Cambiamo questo.

Ora definisci quella gerarchia definendo la classe “teacher” e “student” come classi “child” della classe “person” con l’ereditarietà. Puoi definire l’ereditarietà aggiungendo due punti (:) dopo il nome della classe seguito dal nome della classe genitore come mostrato di seguito.

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

L’intero script della classe dovrebbe ora apparire così:

class person {
    [string]$FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }
}

class teacher : person {
    [int]$EmployeeId
}

class student : person {
    [int]$StudentId
}

A questo punto, quando istanzi un oggetto dalla classe “teacher” o “student”, entrambe le classi avranno gli stessi membri della classe “person”.

Class Inheritance Demo

Ereditarietà con costruttori

Come hai visto sopra, i metodi di classe vengono ereditati tramite l’ereditarietà di classe. Questo comportamento potrebbe portarti a pensare che i costruttori seguirebbero la stessa logica, ma ti sbagli. I costruttori non vengono ereditati e i costruttori per tutte le classi figlie devono essere definiti separatamente in ciascuna classe figlia.

Ad esempio, forse hai appena definito un costruttore sovraccaricato per la classe “person”, ma non hai definito un costruttore per la classe “teacher”, come mostrato di seguito.

class person {
    [string]hidden $FirstName
    [string]$LastName
    
    [string]GetName() {
        return "$($this.FirstName) $($this.LastName)"
    }
    
    [void]SetName([string]$Name) {
        $this.FirstName = ($Name -split ' ')[0]
        $this.LastName = ($Name -split ' ')[1]
    }

    [void]SetName([string]$FirstName,[string]$LastName) {
        $this.FirstName = $FirstName
        $this.LastName = $LastName
    }

		person([string]$Name) {
			$this.SetName($Name)
		}
}

Poi definisci una classe figlia, “teacher” ad esempio, e provi a creare un oggetto senza parametri da essa, come mostrato di seguito. Nota che PowerShell restituisce un errore perché un costruttore senza parametri non è stato definito all’interno della classe “teacher”.

No class defined for child class

A constructor is not necessary in a child class if you’re only using it as a template. Alternatively, if you want to use the parent class as its own standalone class and as a parent class you can include constructors. But you have to make sure that the parent class has a constructor that matches the ones in the child classes.

Attributi dei membri della classe

Come i parametri dei comandi PowerShell, le classi possono avere attributi dei membri. Questi attributi modificano il comportamento di ciascun membro.

Membri nascosti

Se stai utilizzando un membro di classe solo per scopi interni e non desideri che l’utente lo legga o lo scriva, è possibile impostare un membro come nascosto. Ad esempio, forse hai un metodo che viene utilizzato solo da altri metodi. Non c’è bisogno di esporre quel metodo all’utente.

Per definire un membro nascosto, utilizza l’attributo hidden come mostrato di seguito.

class teacher {
    [int]hidden $EmployeeId
}

Ora, quando utilizzi Get-Member per ispezionare tutti i membri dell’oggetto, quella proprietà non viene visualizzata.

Class Member Attributes

Impostare un membro di classe come nascosto non limita l’accesso al valore; lo nasconde solo dalla vista. Non dovresti nascondere le proprietà per memorizzare dati sensibili.

Membri statici

Ricorda, in precedenza questo tutorial ha utilizzato il termine “istanziare” per descrivere la creazione di un oggetto da una classe. Quando istanzi un oggetto, quell’oggetto assume tutte le proprietà e i metodi definiti dalla classe. Ma non è sempre così.

A volte, non hai bisogno del peso di istanziare un intero oggetto. Invece, devi fare riferimento rapidamente a un singolo membro di classe. In tal caso, puoi impostare un membro di classe come statico.

Come per l’attributo hidden, definisci un membro di classe come statico utilizzando la parola chiave static come mostrato di seguito.

class student {
	[int]static $MaxClassCount = 7
}

A differenza dei membri di classe tipici, PowerShell non crea proprietà e metodi dai membri di classe statici. Quando si definisce un membro di classe come statico, come i membri nascosti, non viene visualizzato quando si utilizza Get-Member.

Static Members

Per esempio, potresti voler associare i nomi delle classi universitarie alla classe “student” e definire il numero massimo di classi universitarie in cui uno studente può partecipare. Per fare ciò, crei un membro di array “Classes” e un membro “MaxClassCount”.

Dato che l’utente raramente ha bisogno di modificare il membro “MaxClassCount”, decidi di definirlo come statico.

Infine, crei un metodo “AddClass()” per aggiungere una classe all’orario dello studente, ma solo se è inferiore a “MaxClassCount”.

class student {
    [string[]]$Classes = @()
    [int]static $MaxClassCount = 7
    
    [void]AddClass ([string]$Name) {
        if ($this.Classes.Count -lt [student]::MaxClassCount) {
            $this.Classes += $Name
        }
    }
}

Ora, quando cerchi di creare un nuovo oggetto “student” e assegnargli troppe classi universitarie, PowerShell assegnerà solo il numero massimo che sarebbe sette.

$student1 = [student]::new()
'PE','English','Math','History','Computer Science','French','Wood Working','Cooking' | ForEach-Object {
	$student1.AddClass($_)
}
$student1.Classes
Class Count

Puoi cambiare i valori dei membri statici in qualsiasi momento. Ad esempio, se volessi impostare il membro “MaxClassCount” su 5 invece di 7, cambieresti il valore utilizzando “[student]::MaxClassCount = 5”. Cambiare il valore non rimuoverebbe retroattivamente le classi che superano il limite in questo esempio.

Conclusioni

Le classi di PowerShell offuscano il confine tra un linguaggio di scripting e un linguaggio di programmazione. Le classi sono un ottimo modo per definire le relazioni tra gli oggetti, aggiungere modi di interagire e formattare gli oggetti che normalmente sarebbero possibili solo scrivendo funzioni specializzate.

Source:
https://adamtheautomator.com/powershell-classes/