Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Krátký popis
Popisuje, jak můžete pomocí tříd vyvíjet v PowerShellu pomocí DSC (Desired State Configuration).
Dlouhý popis
Počínaje windows PowerShellem 5.0 byl jazyk přidán k definování tříd a dalších uživatelsky definovaných typů pomocí formální syntaxe a sémantiky, které jsou podobné jiným programovacím jazykům orientovaným na objekty. Cílem je umožnit vývojářům a IT odborníkům využívat PowerShell pro širší škálu případů použití, zjednodušit vývoj artefaktů PowerShellu, jako jsou prostředky DSC, a zrychlit pokrytí povrchů správy.
Podporované scénáře
Podporují se následující scénáře:
- Definujte prostředky DSC a jejich přidružené typy pomocí jazyka PowerShell.
- Definujte vlastní typy v PowerShellu pomocí známých konstruktorů objektově orientovaného programování, jako jsou třídy, vlastnosti, metody a dědičnost.
- Ladicí typy pomocí jazyka PowerShellu
- Generování a zpracování výjimek pomocí formálních mechanismů a na správné úrovni.
Definování prostředků DSC pomocí tříd
Kromě změn syntaxe jsou hlavní rozdíly mezi prostředkem DSC definovaným třídou a poskytovatelem prostředků DSC rutiny následující položky:
- Soubor MOF (Management Object Format) není povinný.
- Podsložka DSCResource ve složce modulu není nutná.
- Soubor modulu PowerShellu může obsahovat více tříd prostředků DSC.
Vytvoření poskytovatele prostředků DSC definovaného třídou
Následující příklad je zprostředkovatel prostředků DSC definovaný třídou, který je uložen jako modul MyDSCResource.psm1. V poskytovateli prostředků DSC definovaném třídou musíte vždy zahrnout klíčovou vlastnost.
enum Ensure
{
Absent
Present
}
<#
This resource manages the file in a specific path.
[DscResource()] indicates the class is a DSC resource
#>
[DscResource()]
class FileResource
{
<#
This property is the fully qualified path to the file that is
expected to be present or absent.
The [DscProperty(Key)] attribute indicates the property is a
key and its value uniquely identifies a resource instance.
Defining this attribute also means the property is required
and DSC will ensure a value is set before calling the resource.
A DSC resource must define at least one key property.
#>
[DscProperty(Key)]
[string]$Path
<#
This property indicates if the settings should be present or absent
on the system. For present, the resource ensures the file pointed
to by $Path exists. For absent, it ensures the file point to by
$Path does not exist.
The [DscProperty(Mandatory)] attribute indicates the property is
required and DSC will guarantee it is set.
If Mandatory is not specified or if it is defined as
Mandatory=$false, the value is not guaranteed to be set when DSC
calls the resource. This is appropriate for optional properties.
#>
[DscProperty(Mandatory)]
[Ensure] $Ensure
<#
This property defines the fully qualified path to a file that will
be placed on the system if $Ensure = Present and $Path does not
exist.
NOTE: This property is required because [DscProperty(Mandatory)] is
set.
#>
[DscProperty(Mandatory)]
[string] $SourcePath
<#
This property reports the file's create timestamp.
[DscProperty(NotConfigurable)] attribute indicates the property is
not configurable in DSC configuration. Properties marked this way
are populated by the Get() method to report additional details
about the resource when it is present.
#>
[DscProperty(NotConfigurable)]
[Nullable[datetime]] $CreationTime
<#
This method is equivalent of the Set-TargetResource script function.
It sets the resource to the desired state.
#>
[void] Set()
{
$fileExists = $this.TestFilePath($this.Path)
if($this.ensure -eq [Ensure]::Present)
{
if(-not $fileExists)
{
$this.CopyFile()
}
}
else
{
if($fileExists)
{
Write-Verbose -Message "Deleting the file $($this.Path)"
Remove-Item -LiteralPath $this.Path -Force
}
}
}
<#
This method is equivalent of the Test-TargetResource script
function. It should return True or False, showing whether the
resource is in a desired state.
#>
[bool] Test()
{
$present = $this.TestFilePath($this.Path)
if($this.Ensure -eq [Ensure]::Present)
{
return $present
}
else
{
return -not $present
}
}
<#
This method is equivalent of the Get-TargetResource script function.
The implementation should use the keys to find appropriate
resources. This method returns an instance of this class with the
updated key properties.
#>
[FileResource] Get()
{
$present = $this.TestFilePath($this.Path)
if ($present)
{
$file = Get-ChildItem -LiteralPath $this.Path
$this.CreationTime = $file.CreationTime
$this.Ensure = [Ensure]::Present
}
else
{
$this.CreationTime = $null
$this.Ensure = [Ensure]::Absent
}
return $this
}
<#
Helper method to check if the file exists and it is correct file
#>
[bool] TestFilePath([string] $location)
{
$present = $true
$item = Get-ChildItem -LiteralPath $location -ea Ignore
if ($null -eq $item)
{
$present = $false
}
elseif( $item.PSProvider.Name -ne "FileSystem")
{
throw "Path $($location) is not a file path."
}
elseif($item.PSIsContainer)
{
throw "Path $($location) is a directory path."
}
return $present
}
<#
Helper method to copy file from source to path
#>
[void] CopyFile()
{
if(-not $this.TestFilePath($this.SourcePath))
{
throw "SourcePath $($this.SourcePath) is not found."
}
[System.IO.FileInfo]
$destFileInfo = new-object System.IO.FileInfo($this.Path)
if (-not $destFileInfo.Directory.Exists)
{
$FullName = $destFileInfo.Directory.FullName
$Message = "Creating directory $FullName"
Write-Verbose -Message $Message
#use CreateDirectory instead of New-Item to avoid code
# to handle the non-terminating error
[System.IO.Directory]::CreateDirectory($FullName)
}
if(Test-Path -LiteralPath $this.Path -PathType Container)
{
throw "Path $($this.Path) is a directory path"
}
Write-Verbose -Message "Copying $this.SourcePath to $this.Path"
#DSC engine catches and reports any error that occurs
Copy-Item -Path $this.SourcePath -Destination $this.Path -Force
}
}
Vytvoření manifestu modulu
Po vytvoření poskytovatele prostředků DSC definovaného třídou a jeho uložení jako modulu vytvořte manifest modulu. Chcete-li zpřístupnit prostředek založený na třídě pro modul DSC, musíte do souboru manifestu zahrnout DscResourcesToExport příkaz, který dává modulu pokyn k exportu prostředku. V tomto příkladu se následující manifest modulu uloží jako MyDscResource.psd1.
@{
# Script module or binary module file associated with this manifest.
RootModule = 'MyDscResource.psm1'
DscResourcesToExport = 'FileResource'
# Version number of this module.
ModuleVersion = '1.0'
# ID used to uniquely identify this module
GUID = '81624038-5e71-40f8-8905-b1a87afe22d7'
# Author of this module
Author = 'Microsoft Corporation'
# Company or vendor of this module
CompanyName = 'Microsoft Corporation'
# Copyright statement for this module
Copyright = '(c) 2014 Microsoft. All rights reserved.'
# Description of the functionality provided by this module
# Description = ''
# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '5.0'
# Name of the PowerShell host required by this module
# PowerShellHostName = ''
}
Nasazení poskytovatele prostředků DSC
Nasaďte nového poskytovatele prostředků DSC vytvořením složky MyDscResource v $pshome\Modules nebo $env:SystemDrive\ProgramFiles\WindowsPowerShell\Modules.
Není nutné vytvořit podsložku DSCResource. Zkopírujte soubory manifestu modulu a modulu (MyDscResource.psm1 a MyDscResource.psd1) do složky MyDscResource.
Od tohoto okamžiku vytvoříte a spustíte konfigurační skript stejně jako u jakéhokoli prostředku DSC.
Vytvoření konfiguračního skriptu DSC
Po uložení souborů třídy a manifestu ve struktuře složek, jak je popsáno výše, můžete vytvořit konfiguraci, která používá nový prostředek. Následující konfigurace odkazuje na modul MyDSCResource. Uložte konfiguraci jako skript, MyResource.ps1.
Informace o tom, jak spustit konfiguraci DSC, najdete v tématu Přehled konfigurace požadovaného stavu Windows PowerShell.
Před spuštěním konfigurace vytvořte C:\test.txtsoubor . Konfigurace zkontroluje, zda soubor existuje v .c:\test\test.txt Pokud soubor neexistuje, konfigurace zkopíruje soubor z C:\test.txt.
Configuration Test
{
Import-DSCResource -ModuleName MyDscResource
FileResource file
{
Path = "C:\test\test.txt"
SourcePath = "C:\test.txt"
Ensure = "Present"
}
}
Test
Start-DscConfiguration -Wait -Force Test
Spusťte tento skript stejně jako jakýkoli konfigurační skript DSC. Konfiguraci spustíte tak, že v konzole PowerShellu se zvýšenými oprávněními spustíte následující příkaz:
PS C:\test> .\MyResource.ps1
Dědičnost ve třídách PowerShell
Deklarace základních tříd pro třídy PowerShellu
Třídu PowerShell můžete deklarovat jako základní typ pro jinou třídu PowerShellu, jak je znázorněno v následujícím příkladu, ve kterém je fruit základním typem pro apple.
class fruit
{
[int]sold() {return 100500}
}
class apple : fruit {}
[apple]::new().sold() # return 100500
Deklarace implementovaných rozhraní pro třídy PowerShellu
Implementovaná rozhraní můžete deklarovat za základními typy nebo bezprostředně za dvojtečkou (:), pokud není zadán žádný základní typ. Všechny názvy typů oddělte čárkami. Podobá se syntaxi jazyka C#.
class MyComparable : system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
class MyComparableTest : test, system.IComparable
{
[int] CompareTo([object] $obj)
{
return 0;
}
}
Volání konstruktorů základní třídy
Chcete-li volat konstruktor základní třídy z podtřídy, přidejte base klíčové slovo, jak je znázorněno v následujícím příkladu:
class A {
[int]$a
A([int]$a)
{
$this.a = $a
}
}
class B : A
{
B() : base(103) {}
}
[B]::new().a # return 103
Pokud má základní třída výchozí konstruktor (bez parametrů), můžete vynechat explicitní volání konstruktoru, jak je znázorněno.
class C : B
{
C([int]$c) {}
}
Volání metod základní třídy
Existující metody můžete přepsat v podtřídách. Chcete-li provést přepsání, deklarujte metody pomocí stejného názvu a podpisu.
class baseClass
{
[int]days() {return 100500}
}
class childClass1 : baseClass
{
[int]days () {return 200600}
}
[childClass1]::new().days() # return 200600
Chcete-li volat metody základní třídy z přepsaných implementací, přetypujte na základní třídu ([baseclass]$this) při vyvolání.
class childClass2 : baseClass
{
[int]days()
{
return 3 * ([baseClass]$this).days()
}
}
[childClass2]::new().days() # return 301500
Všechny metody PowerShellu jsou virtuální. V podtřídě můžete skrýt jiné než virtuální metody .NET pomocí stejné syntaxe jako u přepsání: deklarujte metody se stejným názvem a podpisem.
class MyIntList : system.collections.generic.list[int]
{
# Add is final in system.collections.generic.list
[void] Add([int]$arg)
{
([system.collections.generic.list[int]]$this).Add($arg * 2)
}
}
$list = [MyIntList]::new()
$list.Add(100)
$list[0] # return 200
Aktuální omezení dědičnosti tříd
Omezení dědičnosti tříd spočívá v tom, že v PowerShellu není žádná syntaxe deklarovat rozhraní.
Definování vlastních typů v PowerShellu
Windows PowerShell 5.0 zavedl několik jazykových prvků.
Klíčové slovo třídy
Definuje novou třídu.
Klíčové class slovo je skutečný typ rozhraní .NET Framework.
Členové třídy jsou veřejné.
class MyClass
{
}
Klíčové slovo výčtu a výčty
Byla přidána podpora pro klíčové enum slovo a jedná se o zásadní změnu. Oddělovač enum je v současné době nový řádek. Řešením pro ty, kteří již používají enum , je vložit před slovo ampersand (&). Současná omezení: nemůžete definovat enumerátor z hlediska sebe sama, ale můžete inicializovat enum z hlediska jiného enum, jak je znázorněno v následujícím příkladu:
Základní typ nelze nyní zadat. Základní typ je vždy [int].
enum Color2
{
Yellow = [Color]::Blue
}
Hodnota enumerátoru musí být parsovat časová konstanta. Hodnotu enumerátoru nelze nastavit na výsledek vyvolaného příkazu.
enum MyEnum
{
Enum1
Enum2
Enum3 = 42
Enum4 = [int]::MaxValue
}
Enum Podporuje aritmetické operace, jak je znázorněno v následujícím příkladu:
enum SomeEnum { Max = 42 }
enum OtherEnum { Max = [SomeEnum]::Max + 1 }
Skryté klíčové slovo
Klíčové hidden slovo, zavedené v Windows PowerShell 5.0, skrývá členy třídy před výchozími Get-Member výsledky. Zadejte skrytou vlastnost, jak je znázorněno na následujícím řádku:
hidden [type] $classmember = <value>
Skryté členy nejsou zobrazeny pomocí dokončování tabulátoru nebo IntelliSense, pokud nedojde k dokončení ve třídě, která definuje skrytý člen.
Byl přidán nový atribut System.Management.Automation.HiddenAttribute, aby kód jazyka C# mohl mít stejnou sémantiku v rámci PowerShellu.
Další informace najdete v tématu [about_Hidden[(/powershell/module/microsoft.powershell.core/about/about_hidden).
Import-DscResource
Import-DscResource je nyní skutečně dynamické klíčové slovo. PowerShell analyzuje kořenový modul zadaného modulu a vyhledá třídy, které obsahují atribut DscResource.
Vlastnosti
Do ImplementingAssemblyModuleInfosouboru . Pokud skript definuje třídy, nebo je načtené sestavení pro binární moduly ImplementingAssembly nastaveno na dynamické sestavení vytvořené pro modul skriptu. Není nastavena, když ModuleType = Manifest.
Reflexe ImplementingAssembly pole objevuje zdroje v modulu. To znamená, že můžete zjistit prostředky napsané v PowerShellu nebo v jiných spravovaných jazycích.
Pole s inicializátory.
[int] $i = 5
Statická je podporovaná a funguje jako atribut, podobně jako omezení typu, takže ho můžete zadat v libovolném pořadí.
static [int] $count = 0
Typ je volitelný.
$s = "hello"
Všichni členové jsou veřejná. Vlastnosti vyžadují buď nový řádek, nebo středník. Pokud není zadán žádný typ objektu, typ vlastnosti je Object.
Konstruktory a vytváření instancí
Třídy PowerShellu můžou mít konstruktory, které mají stejný název jako jejich třída. Konstruktory mohou být přetíženy. Podporují se statické konstruktory.
Vlastnosti s inicializačními výrazy se inicializují před spuštěním jakéhokoli kódu v konstruktoru. Statické vlastnosti se inicializují před tělem statického konstruktoru a vlastnosti instance se inicializují před textem nestatického konstruktoru. V současné době neexistuje žádná syntaxe pro volání konstruktoru z jiného konstruktoru, jako je například syntaxe jazyka C#: ": this()"). Alternativním řešením je definovat společnou inicializační metodu.
Následující způsoby vytváření instancí tříd:
Vytvoření instance pomocí výchozího konstruktoru Upozorňujeme, že
New-Objecttato verze není podporována.$a = [MyClass]::new()Volání konstruktoru s parametrem
$b = [MyClass]::new(42)Předání pole konstruktoru s více parametry
$c = [MyClass]::new(@(42,43,44), "Hello")
V této verzi je název typu viditelný pouze lexiky, což znamená, že není viditelný mimo modul nebo skript, který definuje třídu. Funkce můžou vracet instance třídy definované v PowerShellu a instance fungují dobře mimo modul nebo skript.
Parametr Get-MemberStatic uvádí konstruktory, takže můžete zobrazit přetížení jako jakoukoli jinou metodu. Výkon této syntaxe je také podstatně rychlejší než New-Object.
Pseudostatická metoda s názvem new pracuje s typy .NET, jak je znázorněno v následujícím příkladu. [hashtable]::new()
Nyní můžete vidět přetížení konstruktoru pomocí Get-Member, nebo jak je znázorněno v tomto příkladu:
[hashtable]::new
OverloadDefinitions
-------------------
hashtable new()
hashtable new(int capacity)
hashtable new(int capacity, float loadFactor)
Metody
Metoda třídy PowerShell je implementována jako ScriptBlock , který má pouze koncový blok. Všechny metody jsou veřejné. Následující příklad ukazuje příklad definování metody s názvem DoSomething.
class MyClass
{
DoSomething($x)
{
$this._doSomething($x) # method syntax
}
private _doSomething($a) {}
}
Vyvolání metody
Podporované jsou přetížené metody. Přetížené metody jsou pojmenovány stejně jako existující metoda, ale rozlišují se podle jejich zadaných hodnot.
$b = [MyClass]::new()
$b.DoSomething(42)
Vyvolání
Viz Vyvolání metody.
Atributy
Byly přidány tři nové atributy: DscResource, DscResourceKey, a DscResourceMandatory.
Návratové typy
Návratový typ je kontrakt. Vrácená hodnota se převede na očekávaný typ. Pokud není zadán žádný návratový typ, návratový typ je neplatný. Do kanálu se nedají zapsat žádné streamování objektů a objekty buď záměrně, nebo omylem.
Lexikální obor proměnných
Následující příklad ukazuje, jak v této verzi funguje lexikální obory.
$d = 42 # Script scope
function bar
{
$d = 0 # Function scope
[MyClass]::DoSomething()
}
class MyClass
{
static [object] DoSomething()
{
return $d # error, not found dynamically
return $script:d # no error
$d = $script:d
return $d # no error, found lexically
}
}
$v = bar
$v -eq $d # true
Příklad: Vytvoření vlastních tříd
Následující příklad vytvoří několik nových vlastních tříd pro implementaci HTML Dynamic Stylesheet Language (DSL). Příklad přidá pomocné funkce pro vytvoření konkrétních typů elementů jako součást třídy elementu, jako jsou styly nadpisů a tabulky, protože typy nelze použít mimo rozsah modulu.
# Classes that define the structure of the document
#
class Html
{
[string] $docType
[HtmlHead] $Head
[Element[]] $Body
[string] Render()
{
$text = "<html>`n<head>`n"
$text += $Head
$text += "`n</head>`n<body>`n"
$text += $Body -join "`n" # Render all of the body elements
$text += "</body>`n</html>"
return $text
}
[string] ToString() { return $this.Render() }
}
class HtmlHead
{
$Title
$Base
$Link
$Style
$Meta
$Script
[string] Render() { return "<title>$Title</title>" }
[string] ToString() { return $this.Render() }
}
class Element
{
[string] $Tag
[string] $Text
[hashtable] $Attributes
[string] Render() {
$attributesText= ""
if ($Attributes)
{
foreach ($attr in $Attributes.Keys)
{
$attributesText = " $attr=`"$($Attributes[$attr])`""
}
}
return "<${tag}${attributesText}>$text</$tag>`n"
}
[string] ToString() { return $this.Render() }
}
#
# Helper functions for creating specific element types on top of the classes.
# These are required because types aren't visible outside of the module.
#
function H1 {[Element] @{Tag = "H1"; Text = $args.foreach{$_} -join " "}}
function H2 {[Element] @{Tag = "H2"; Text = $args.foreach{$_} -join " "}}
function H3 {[Element] @{Tag = "H3"; Text = $args.foreach{$_} -join " "}}
function P {[Element] @{Tag = "P" ; Text = $args.foreach{$_} -join " "}}
function B {[Element] @{Tag = "B" ; Text = $args.foreach{$_} -join " "}}
function I {[Element] @{Tag = "I" ; Text = $args.foreach{$_} -join " "}}
function HREF
{
param (
$Name,
$Link
)
return [Element] @{
Tag = "A"
Attributes = @{ HREF = $link }
Text = $name
}
}
function Table
{
param (
[Parameter(Mandatory)]
[object[]]
$Data,
[Parameter()]
[string[]]
$Properties = "*",
[Parameter()]
[hashtable]
$Attributes = @{ border=2; cellpadding=2; cellspacing=2 }
)
$bodyText = ""
# Add the header tags
$bodyText += $Properties.foreach{TH $_}
# Add the rows
$bodyText += foreach ($row in $Data)
{
TR (-join $Properties.Foreach{ TD ($row.$_) } )
}
$table = [Element] @{
Tag = "Table"
Attributes = $Attributes
Text = $bodyText
}
$table
}
function TH {([Element] @{Tag="TH"; Text=$args.foreach{$_} -join " "})}
function TR {([Element] @{Tag="TR"; Text=$args.foreach{$_} -join " "})}
function TD {([Element] @{Tag="TD"; Text=$args.foreach{$_} -join " "})}
function Style
{
return [Element] @{
Tag = "style"
Text = "$args"
}
}
# Takes a hash table, casts it to and HTML document
# and then returns the resulting type.
#
function Html ([HTML] $doc) { return $doc }
Viz také
Sestavení vlastních prostředků konfigurace požadovaného stavu PowerShellu