about_Classes_and_DSC

Rövid leírás

Ismerteti, hogyan fejleszthet osztályokat a PowerShellben a Desired State Configuration (DSC) használatával.

Hosszú leírás

A Windows PowerShell 5.0-s verziótól kezdődően a rendszer hozzáadta a nyelvet az osztályok és más, felhasználó által definiált típusok meghatározásához más objektumorientált programozási nyelvekhez hasonló formális szintaxis és szemantikák használatával. A cél az, hogy a fejlesztők és az informatikai szakemberek szélesebb körű használati esetekhez használhassák a PowerShellt, egyszerűbbé tegyék a PowerShell-összetevők, például a DSC-erőforrások fejlesztését, és felgyorsítsák a felügyeleti felületek lefedettségét.

Támogatott esetek

A következő forgatókönyvek támogatottak:

  • A PowerShell-nyelv használatával definiálhatja a DSC-erőforrásokat és azok társított típusait.
  • Egyéni típusok definiálása a PowerShellben ismerős objektumorientált programozási szerkezetek, például osztályok, tulajdonságok, metódusok és öröklés használatával.
  • Típusok hibakeresése a PowerShell-nyelv használatával.
  • A kivételek létrehozása és kezelése formális mechanizmusokkal és a megfelelő szinten.

DSC-erőforrások definiálása osztályokkal

A szintaxisváltozásokon kívül az osztály által definiált DSC-erőforrások és a DSC-erőforrás-szolgáltató parancsmagok közötti fő különbségek a következő elemek:

  • Nincs szükség felügyeleti objektumformátumú (MOF) fájlra.
  • A modulmappában nincs szükség DSCResource almappára.
  • Egy PowerShell-modulfájl több DSC-erőforrásosztályt is tartalmazhat.

Osztályalapú DSC-erőforrás-szolgáltató létrehozása

Az alábbi példa egy osztály által definiált DSC-erőforrás-szolgáltató, amely a MyDSCResource.psm1 modulként van mentve. Mindig tartalmaznia kell egy kulcstulajdonságot egy osztály által definiált DSC-erőforrás-szolgáltatóban.

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
    }
}

Moduljegyzék létrehozása

Az osztály által definiált DSC-erőforrás-szolgáltató létrehozása és modulként való mentése után hozzon létre egy moduljegyzéket a modulhoz. Ha elérhetővé szeretne tenni egy osztályalapú erőforrást a DSC-motor számára, fel kell vennie egy DscResourcesToExport utasítást a jegyzékfájlba, amely arra utasítja a modult, hogy exportálja az erőforrást. Ebben a példában a következő moduljegyzéket a rendszer MyDscResource.psd1 néven menti.

@{

# 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 = ''

}

DSC-erőforrás-szolgáltató üzembe helyezése

Helyezze üzembe az új DSC-erőforrás-szolgáltatót egy MyDscResource mappa létrehozásával a vagy $env:SystemDrive\ProgramFiles\WindowsPowerShell\Modulesa $pshome\Modules .

Nem kell DSCResource almappát létrehoznia. Másolja a modul- és moduljegyzékfájlokat (MyDscResource.psm1 és MyDscResource.psd1) a MyDscResource mappába.

Ettől a ponttól kezdve ugyanúgy hozhat létre és futtathat konfigurációs szkriptet, mint bármely DSC-erőforrás esetében.

DSC-konfigurációs szkript létrehozása

Miután mentette az osztály- és jegyzékfájlokat a mappastruktúrában a korábban leírtak szerint, létrehozhat egy konfigurációt, amely az új erőforrást használja. Az alábbi konfiguráció a MyDSCResource modulra hivatkozik. Mentse a konfigurációt szkriptként, MyResource.ps1.

A DSC-konfiguráció futtatásával kapcsolatos információkért lásd Windows PowerShell Desired State Configuration áttekintését.

A konfiguráció futtatása előtt hozza létre a következőt C:\test.txt: . A konfiguráció ellenőrzi, hogy a fájl létezik-e a következő helyen c:\test\test.txt: . Ha a fájl nem létezik, a konfiguráció innen másolja a fájlt C:\test.txt.

Configuration Test
{
    Import-DSCResource -module MyDscResource
    FileResource file
    {
        Path = "C:\test\test.txt"
        SourcePath = "C:\test.txt"
        Ensure = "Present"
    }
}
Test
Start-DscConfiguration -Wait -Force Test

Futtassa ezt a szkriptet ugyanúgy, mint bármely DSC-konfigurációs szkriptet. A konfiguráció elindításához futtassa a következőt egy emelt szintű PowerShell-konzolon:

PS C:\test> .\MyResource.ps1

Öröklés PowerShell-osztályokban

Alaposztályok deklarálása PowerShell-osztályokhoz

A PowerShell-osztályokat egy másik PowerShell-osztály alaptípusaként deklarálhatja, ahogy az alábbi példában látható, amelyben a gyümölcs az alma alaptípusa.

class fruit
{
    [int]sold() {return 100500}
}

class apple : fruit {}
    [apple]::new().sold() # return 100500

Implementált felületek deklarálása PowerShell-osztályokhoz

A implementált illesztőket alaptípusok után, vagy közvetlenül kettőspont (:) után deklarálhatja, ha nincs megadva alaptípus. Az összes típusnevet vesszővel válassza el egymástól. Ez hasonló a C#-szintaxishoz.

class MyComparable : system.IComparable
{
    [int] CompareTo([object] $obj)
    {
        return 0;
    }
}

class MyComparableTest : test, system.IComparable
{
    [int] CompareTo([object] $obj)
    {
        return 0;
    }
}

Alaposztály konstruktorok hívása

Ha egy alosztályból szeretné meghívni az alaposztály konstruktorát, adja hozzá a base kulcsszót az alábbi példában látható módon:

class A {
    [int]$a
    A([int]$a)
    {
        $this.a = $a
    }
}

class B : A
{
    B() : base(103) {}
}

    [B]::new().a # return 103

Ha egy alaposztály alapértelmezett konstruktorsal rendelkezik (paraméterek nélkül), kihagyhat egy explicit konstruktorhívást az ábrán látható módon.

class C : B
{
    C([int]$c) {}
}

Alaposztály metódusának hívása

Az alosztályokban meglévő metódusokat felülbírálhatja. A felülbíráláshoz deklaráljon metódusokat ugyanazzal a névvel és aláírással.

class baseClass
{
    [int]days() {return 100500}
}
class childClass1 : baseClass
{
    [int]days () {return 200600}
}

    [childClass1]::new().days() # return 200600

Ha az alaposztály metódusait felül bírált implementációkból szeretné meghívni, a meghívás alapján az alaposztályba ([baseclass]$this) kell állítva.

class childClass2 : baseClass
{
    [int]days()
    {
        return 3 * ([baseClass]$this).days()
    }
}

    [childClass2]::new().days() # return 301500

Minden PowerShell-metódus virtuális. A nem virtuális .NET-metódusokat úgy rejtheti el egy alosztályban, hogy ugyanazt a szintaxist használja, mint a felülbírálás esetén: azonos nevű és aláírású metódusokat deklarálhat.

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

Az osztályörökléssel kapcsolatos jelenlegi korlátozások

Az osztályörökléssel kapcsolatos korlátozás az, hogy a PowerShellben nincs szintaxis a felületek deklarálásához.

Egyéni típusok definiálása a PowerShellben

Windows PowerShell 5.0 számos nyelvi elemet vezetett be.

Osztály kulcsszó

Új osztályt definiál. A class kulcsszó egy valódi .NET-keretrendszer típus. Az osztálytagok nyilvánosak.

class MyClass
{
}

Kulcsszó és enumerálások számbavétele

A kulcsszó támogatása enum hozzá lett adva, és kompatibilitástörő változás. A enum határoló jelenleg új vonal. Azok számára, akik már használják enum , kerülő megoldásként beszúrhat egy és (&) erősítőt a szó elé. Jelenlegi korlátozások: önmagában nem definiálhat enumerátort, de inicializálhat enum egy másikat enum, ahogy az alábbi példában látható:

Az alaptípus jelenleg nem adható meg. Az alaptípus mindig [int].

enum Color2
{
    Yellow = [Color]::Blue
}

Az enumerátorértéknek elemzési időállandónak kell lennie. Az enumerátor értéke nem állítható egy meghívott parancs eredményére.

enum MyEnum
{
    Enum1
    Enum2
    Enum3 = 42
    Enum4 = [int]::MaxValue
}

Enum az alábbi példában látható módon támogatja az aritmetikai műveleteket:

enum SomeEnum { Max = 42 }
enum OtherEnum { Max = [SomeEnum]::Max + 1 }

Rejtett kulcsszó

Az hidden Windows PowerShell 5.0-s verzióban bevezetett kulcsszó elrejti az osztálytagokat az alapértelmezett Get-Member eredmények elől. Adja meg a rejtett tulajdonságot az alábbi sorban látható módon:

hidden [type] $classmember = <value>

A rejtett tagok nem jelennek meg lapkiegészítés vagy IntelliSense használatával, kivéve, ha a befejezés a rejtett tagot meghatározó osztályban történik.

Egy új attribútum, a System.Management.Automation.HiddenAttribute lett hozzáadva, hogy a C#-kód ugyanazokkal a szemantikával rendelkezzen a PowerShellben.

További információ: [about_Hidden[(/powershell/module/microsoft.powershell.core/about/about_hidden).

Import-DscResource

Import-DscResource A mostantól egy valódi dinamikus kulcsszó. A PowerShell elemzi a megadott modul gyökérmodulját, és megkeresi a DscResource attribútumot tartalmazó osztályokat.

Tulajdonságok

Új mező ImplementingAssemblylett hozzáadva a programhoz ModuleInfo. Ha a szkript osztályokat határoz meg, vagy a bináris modulok ImplementingAssembly betöltött szerelvénye a szkriptmodulhoz létrehozott dinamikus szerelvényre van beállítva. A modultípus = jegyzékfájl esetén nincs beállítva.

A mező tükröződése ImplementingAssembly egy modul erőforrásait deríti fel. Ez azt jelenti, hogy a PowerShellben vagy más felügyelt nyelveken írt erőforrásokat is felfedezhet.

Inicializálókkal rendelkező mezők.

[int] $i = 5

A statikus érték támogatott, és a típuskényszerekhez hasonló attribútumként működik, így bármilyen sorrendben megadható.

static [int] $count = 0

A típus megadása nem kötelező.

$s = "hello"

Minden tag nyilvános. A tulajdonságokhoz új vonal vagy pontosvessző szükséges. Ha nincs megadva objektumtípus, a tulajdonság típusa Objektum.

Konstruktorok és példányosítás

A PowerShell-osztályok olyan konstruktorokkal rendelkezhetnek, amelyek neve megegyezik az osztályuk nevével. A konstruktorok túlterhelhetők. A statikus konstruktorok támogatottak. Az inicializálási kifejezésekkel rendelkező tulajdonságok inicializálva lesznek, mielőtt bármilyen kódot futtatnak egy konstruktorban. A statikus tulajdonságok inicializálása a statikus konstruktor törzse előtt, a példánytulajdonságok pedig a nem statikus konstruktor törzse előtt vannak inicializálva. Jelenleg nincs szintaxis egy konstruktor más konstruktorból való meghívásához, például a C#-szintaxishoz: ": this()"). A kerülő megoldás egy közös Init-metódus definiálása.

Az osztályok példányosításának módjai a következők:

  • Példányosítás az alapértelmezett konstruktor használatával. Vegye figyelembe, hogy New-Object ez a kiadás nem támogatott.

    $a = [MyClass]::new()

  • Konstruktor meghívása paraméterrel.

    $b = [MyClass]::new(42)

  • Tömb átadása több paraméterrel rendelkező konstruktornak

    $c = [MyClass]::new(@(42,43,44), "Hello")

Ebben a kiadásban a típusnév csak lexikálisan látható, ami azt jelenti, hogy az osztályt definiáló modulon vagy szkripten kívül nem látható. A függvények a PowerShellben definiált osztály példányait is visszaadhatják, a példányok pedig jól működnek a modulon vagy a szkripten kívül.

A Get-MemberStatikus paraméter a konstruktorokat listázza, így a túlterheléseket bármely más módszerhez hasonlóan tekintheti meg. Ennek a szintaxisnak a teljesítménye is lényegesen gyorsabb, mint New-Objecta .

Az új nevű pszeudo-statikus metódus a .NET-típusokkal működik, ahogy az az alábbi példában látható. [hashtable]::new()

Most már láthatja a konstruktorok túlterhelését Get-Memberaz alábbi példában látható módon:

[hashtable]::new
OverloadDefinitions
-------------------
hashtable new()
hashtable new(int capacity)
hashtable new(int capacity, float loadFactor)

Metódusok

A PowerShell-osztálymetódus szkriptblokkként van implementálva, amelynek csak egy végpontja van. Minden metódus nyilvános. Az alábbiakban egy DoSomething nevű metódus definiálására láthat példát.

class MyClass
{
    DoSomething($x)
    {
        $this._doSomething($x)       # method syntax
    }
    private _doSomething($a) {}
}

Metódushívás

A túlterhelt metódusok támogatottak. A túlterhelt metódusok neve megegyezik egy meglévő metódussal, de a megadott értékek megkülönböztetik őket.

$b = [MyClass]::new()
$b.DoSomething(42)

Könyörgése

Lásd a metódushívást.

Attribútumok

Három új attribútum lett hozzáadva: DscResource, DscResourceKeyés DscResourceMandatory.

Visszatérési típusok

A visszatérési típus szerződés. A visszaadott érték a várt típusra lesz konvertálva. Ha nincs megadva visszatérési típus, a visszatérési típus érvénytelen. Az objektumok és objektumok nem streamelhetők szándékosan vagy véletlenül a folyamatba.

Változók lexikális hatókörkezelése

Az alábbiakban egy példa látható a lexikális hatókörkezelés működésére ebben a kiadásban.

$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élda: Egyéni osztályok létrehozása

Az alábbi példa számos új, egyéni osztályt hoz létre egy HTML dinamikus stíluslapnyelv (DSL) implementálásához. A példa segédfüggvényeket ad hozzá adott elemtípusok létrehozásához az elemosztály részeként, például címsorstílusok és táblázatok részeként, mivel a típusok nem használhatók a modul hatókörén kívül.

# 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 }

Lásd még

about_Enum

about_Hidden

about_Language_Keywords

about_Methods

Egyéni PowerShell-Desired State Configuration-erőforrások létrehozása