Skriva en anpassad DSC-resurs med PowerShell-klasser
Gäller för: Windows PowerShell 5.0
Med introduktionen av PowerShell-klasser i Windows PowerShell 5.0 kan du nu definiera en DSC-resurs genom att skapa en klass. Klassen definierar både schemat och implementeringen av resursen, så det finns inget behov av att skapa en separat MOF-fil. Mappstrukturen för en klassbaserad resurs är också enklare eftersom en DSCResources mapp inte behövs.
I en klassbaserad DSC-resurs definieras schemat som egenskaper för klassen som kan ändras med attribut för att ange egenskapstypen. Resursen implementeras av metoderna Get()
, Set()
och Test()
(motsvarande funktionerna Get-TargetResource
, Set-TargetResource
och Test-TargetResource
i en skriptresurs.
I den här artikeln skapar vi en enkel resurs med namnet NewFile som hanterar en fil i en angiven sökväg.
Mer information om DSC-resurser finns i Skapa anpassade Windows PowerShell-resurser för önskad tillståndskonfiguration
Not
Allmänna samlingar stöds inte i klassbaserade resurser.
Mappstruktur för en klassresurs
Om du vill implementera en anpassad DSC-resurs med en PowerShell-klass skapar du följande mappstruktur.
Klassen definieras i MyDscResource.psm1
och modulmanifestet definieras i MyDscResource.psd1
.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
MyDscResource.psm1
MyDscResource.psd1
Skapa klassen
Du använder klassnyckelordet för att skapa en PowerShell-klass. Om du vill ange att en klass är en DSC-resurs använder du attributet DscResource()
. Namnet på klassen är namnet på DSC-resursen.
[DscResource()]
class NewFile {
}
Deklarera egenskaper
DSC-resursschemat definieras som egenskaper för klassen. Vi deklarerar tre egenskaper enligt följande.
[DscProperty(Key)]
[string] $path
[DscProperty(Mandatory)]
[ensure] $ensure
[DscProperty()]
[string] $content
[DscProperty(NotConfigurable)]
[MyDscResourceReason[]] $Reasons
Observera att egenskaperna ändras av attribut. Attributens betydelse är följande:
- DscProperty(Key): Egenskapen krävs. Egenskapen är en nyckel. Värdena för alla egenskaper som har markerats som nycklar måste kombineras för att unikt identifiera en resursinstans i en konfiguration.
- DscProperty(obligatoriskt): Egenskapen krävs.
-
DscProperty(NotConfigurable): Egenskapen är skrivskyddad. Egenskaper som har markerats med det här attributet kan inte anges av en konfiguration, men fylls i med metoden
Get()
när de finns. - DscProperty(): Egenskapen kan konfigureras, men den krävs inte.
Egenskaperna $Path
och $SourcePath
är båda strängarna.
$CreationTime
är en DateTime- egenskap. Egenskapen $Ensure
är en uppräkningstyp som definieras på följande sätt.
enum Ensure
{
Absent
Present
}
Inbäddningsklasser
Om du vill inkludera en ny typ med definierade egenskaper som du kan använda i resursen skapar du bara en klass med egenskapstyper enligt beskrivningen ovan.
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
Not
Klassen MyDscResourceReason
deklareras här med modulens namn som prefix. Du kan ge inbäddade klasser valfritt namn, men om två eller flera moduler definierar en klass med samma namn och båda används i en konfiguration, skapar PowerShell ett undantag.
För att undvika undantag som orsakas av namnkonflikter i DSC prefixar du namnen på dina inbäddade klasser med modulnamnet. Om det redan är osannolikt att namnet på den inbäddade klassen är i konflikt kan du använda det utan ett prefix.
Om din DSC-resurs är utformad för användning med Azure Automanages datorkonfigurationsfunktion, prefixar du alltid namnet på den inbäddade klass som du skapar för egenskapen Reasons.
Offentliga och privata funktioner
Du kan skapa PowerShell-funktioner i samma modulfil och använda dem i metoderna för din DSC-klassresurs. Funktionerna måste deklareras som offentliga, men skriptblocken i dessa offentliga funktioner kan anropa funktioner som är privata. Den enda skillnaden är om de visas i egenskapen FunctionsToExport
för modulmanifestet.
<#
Public Functions
#>
function Get-File {
param(
[ensure]$ensure,
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$path,
[String]$content
)
$fileContent = [MyDscResourceReason]::new()
$fileContent.code = 'file:file:content'
$filePresent = [MyDscResourceReason]::new()
$filePresent.code = 'file:file:path'
$ensureReturn = 'Absent'
$fileExists = Test-path $path -ErrorAction SilentlyContinue
if ($true -eq $fileExists) {
$filePresent.phrase = "The file was expected to be: $ensure`nThe file exists at path: $path"
$existingFileContent = Get-Content $path -Raw
if ([string]::IsNullOrEmpty($existingFileContent)) {
$existingFileContent = ''
}
if ($false -eq ([string]::IsNullOrEmpty($content))) {
$content = $content | ConvertTo-SpecialChars
}
$fileContent.phrase = "The file was expected to contain: $content`nThe file contained: $existingFileContent"
if ($content -eq $existingFileContent) {
$ensureReturn = 'Present'
}
}
else {
$filePresent.phrase = "The file was expected to be: $ensure`nThe file does not exist at path: $path"
$path = 'file not found'
}
return @{
ensure = $ensureReturn
path = $path
content = $existingFileContent
Reasons = @($filePresent,$fileContent)
}
}
function Set-File {
param(
[ensure]$ensure = "Present",
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$path,
[String]$content
)
Remove-Item $path -Force -ErrorAction SilentlyContinue
if ($ensure -eq "Present") {
New-Item $path -ItemType File -Force
if ([ValidateNotNullOrEmpty()]$content) {
$content | ConvertTo-SpecialChars | Set-Content $path -NoNewline -Force
}
}
}
function Test-File {
param(
[ensure]$ensure = "Present",
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$path,
[String]$content
)
$test = $false
$get = Get-File @PSBoundParameters
if ($get.ensure -eq $ensure) {
$test = $true
}
return $test
}
<#
Private Functions
#>
function ConvertTo-SpecialChars {
param(
[parameter(Mandatory = $true,ValueFromPipeline)]
[ValidateNotNullOrEmpty()]
[string]$string
)
$specialChars = @{
'`n' = "`n"
'\\n' = "`n"
'`r' = "`r"
'\\r' = "`r"
'`t' = "`t"
'\\t' = "`t"
}
foreach ($char in $specialChars.Keys) {
$string = $string -replace ($char,$specialChars[$char])
}
return $string
}
Implementera metoderna
Metoderna Get()
, Set()
och Test()
motsvarar funktionerna Get-TargetResource
, Set-TargetResource
och Test-TargetResource
i en skriptresurs.
Vi rekommenderar att du minimerar mängden kod i klassimplementeringen. Flytta i stället merparten av koden till offentliga funktioner i modulen, som sedan kan testas oberoende av varandra.
<#
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.
#>
[NewFile] Get() {
$get = Get-File -ensure $this.ensure -path $this.path -content $this.content
return $get
}
<#
This method is equivalent of the Set-TargetResource script function.
It sets the resource to the desired state.
#>
[void] Set() {
$set = Set-File -ensure $this.ensure -path $this.path -content $this.content
}
<#
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() {
$test = Test-File -ensure $this.ensure -path $this.path -content $this.content
return $test
}
Den fullständiga filen
Den fullständiga klassfilen följer.
enum ensure {
Absent
Present
}
<#
This class is used within the DSC Resource to standardize how data
is returned about the compliance details of the machine. Note that
the class name is prefixed with the module name - this helps prevent
errors raised when multiple modules with DSC Resources define the
Reasons property for reporting when they're out-of-state.
#>
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
<#
Public Functions
#>
function Get-File {
param(
[ensure]$ensure,
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$path,
[String]$content
)
$fileContent = [MyDscResourceReason]::new()
$fileContent.code = 'file:file:content'
$filePresent = [MyDscResourceReason]::new()
$filePresent.code = 'file:file:path'
$ensureReturn = 'Absent'
$fileExists = Test-path $path -ErrorAction SilentlyContinue
if ($true -eq $fileExists) {
$filePresent.phrase = "The file was expected to be: $ensure`nThe file exists at path: $path"
$existingFileContent = Get-Content $path -Raw
if ([string]::IsNullOrEmpty($existingFileContent)) {
$existingFileContent = ''
}
if ($false -eq ([string]::IsNullOrEmpty($content))) {
$content = $content | ConvertTo-SpecialChars
}
$fileContent.phrase = "The file was expected to contain: $content`nThe file contained: $existingFileContent"
if ($content -eq $existingFileContent) {
$ensureReturn = 'Present'
}
}
else {
$filePresent.phrase = "The file was expected to be: $ensure`nThe file does not exist at path: $path"
$path = 'file not found'
}
return @{
ensure = $ensureReturn
path = $path
content = $existingFileContent
Reasons = @($filePresent,$fileContent)
}
}
function Set-File {
param(
[ensure]$ensure = "Present",
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$path,
[String]$content
)
Remove-Item $path -Force -ErrorAction SilentlyContinue
if ($ensure -eq "Present") {
New-Item $path -ItemType File -Force
if ([ValidateNotNullOrEmpty()]$content) {
$content | ConvertTo-SpecialChars | Set-Content $path -NoNewline -Force
}
}
}
function Test-File {
param(
[ensure]$ensure = "Present",
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$path,
[String]$content
)
$test = $false
$get = Get-File @PSBoundParameters
if ($get.ensure -eq $ensure) {
$test = $true
}
return $test
}
<#
Private Functions
#>
function ConvertTo-SpecialChars {
param(
[parameter(Mandatory = $true,ValueFromPipeline)]
[ValidateNotNullOrEmpty()]
[string]$string
)
$specialChars = @{
'`n' = "`n"
'\\n' = "`n"
'`r' = "`r"
'\\r' = "`r"
'`t' = "`t"
'\\t' = "`t"
}
foreach ($char in $specialChars.Keys) {
$string = $string -replace ($char,$specialChars[$char])
}
return $string
}
<#
This resource manages the file in a specific path.
[DscResource()] indicates the class is a DSC resource
#>
[DscResource()]
class NewFile {
<#
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 is optional. When provided, the content of the file
will be overwridden by this value.
#>
[DscProperty()]
[string] $content
<#
This property reports the reasons the machine is or is not compliant.
[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)]
[MyDscResourceReason[]] $Reasons
<#
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.
#>
[NewFile] Get() {
$get = Get-File -ensure $this.ensure -path $this.path -content $this.content
return $get
}
<#
This method is equivalent of the Set-TargetResource script function.
It sets the resource to the desired state.
#>
[void] Set() {
$set = Set-File -ensure $this.ensure -path $this.path -content $this.content
}
<#
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() {
$test = Test-File -ensure $this.ensure -path $this.path -content $this.content
return $test
}
}
Skapa ett manifest
Om du vill göra en klassbaserad resurs tillgänglig för DSC-motorn måste du inkludera en DscResourcesToExport
-instruktion i manifestfilen som instruerar modulen att exportera resursen. Vårt manifest ser ut så här:
@{
# Script module or binary module file associated with this manifest.
RootModule = 'NewFile.psm1'
# Version number of this module.
ModuleVersion = '1.0.0'
# ID used to uniquely identify this module
GUID = 'fad0d04e-65d9-4e87-aa17-39de1d008ee4'
# Author of this module
Author = 'Microsoft Corporation'
# Company or vendor of this module
CompanyName = 'Microsoft Corporation'
# Copyright statement for this module
Copyright = ''
# Description of the functionality provided by this module
Description = 'Create and set content of a file'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '5.0'
# Functions to export from this module
FunctionsToExport = @('Get-File','Set-File','Test-File')
# DSC resources to export from this module
DscResourcesToExport = @('NewFile')
# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell.
PrivateData = @{
PSData = @{
# Tags applied to this module. These help with module discovery in online galleries.
# Tags = @(Power Plan, Energy, Battery)
# A URL to the license for this module.
# LicenseUri = ''
# A URL to the main website for this project.
# ProjectUri = ''
# A URL to an icon representing this module.
# IconUri = ''
# ReleaseNotes of this module
# ReleaseNotes = ''
} # End of PSData hashtable
}
}
Testa resursen
När du har sparat klass- och manifestfilerna i mappstrukturen enligt beskrivningen tidigare kan du skapa en konfiguration som använder den nya resursen. Information om hur du kör en DSC-konfiguration finns i Anta konfigurationer. Följande konfiguration kontrollerar om filen på /tmp/test.txt
finns och om innehållet matchar strängen som tillhandahålls av egenskapen "Innehåll". Annars skrivs hela filen.
Configuration MyConfig
{
Import-DSCResource -ModuleName NewFile
NewFile testFile
{
Path = "/tmp/test.txt"
Content = "DSC Rocks!"
Ensure = "Present"
}
}
MyConfig
Stöd för PsDscRunAsCredential
[Obs! PsDscRunAsCredential stöds i PowerShell 5.0 och senare.
Egenskapen PsDscRunAsCredential kan användas i DSC-konfigurationer resursblock för att ange att resursen ska köras under en angiven uppsättning autentiseringsuppgifter. Mer information finns i Köra DSC med användarautentiseringsuppgifter.
Kräv eller tillåt inte PsDscRunAsCredential för din resurs
Attributet DscResource()
tar en valfri parameter RunAsCredential. Den här parametern tar ett av tre värden:
-
Optional
PsDscRunAsCredential är valfritt för konfigurationer som anropar den här resursen. Det här är standardvärdet. -
Mandatory
PsDscRunAsCredential måste användas för alla konfigurationer som anropar den här resursen. -
NotSupported
Konfigurationer som anropar den här resursen kan inte använda PsDscRunAsCredential. -
Default
Samma somOptional
.
Använd till exempel följande attribut för att ange att din anpassade resurs inte stöder användning av PsDscRunAsCredential:
[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}
Deklarera flera klassresurser i en modul
En modul kan definiera flera klassbaserade DSC-resurser. Du behöver bara deklarera alla klasser i samma .psm1
fil och inkludera varje namn i .psd1
-manifestet.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
|- MyDscResource.psm1
MyDscResource.psd1
Komma åt användarkontexten
Om du vill komma åt användarkontexten inifrån en anpassad resurs kan du använda den automatiska variabeln $global:PsDscContext
.
Följande kod skulle till exempel skriva användarkontexten under vilken resursen körs till den utförliga utdataströmmen:
if (PsDscContext.RunAsUser) {
Write-Verbose "User: $global:PsDscContext.RunAsUser";
}
Se även
Skapa anpassade Windows PowerShell-resurser för önskad tillståndskonfiguration