Een aangepaste DSC-resource schrijven met PowerShell-klassen
Van toepassing op: Windows PowerShell 5.0
Met de introductie van PowerShell-klassen in Windows PowerShell 5.0 kunt u nu een DSC-resource definiëren door een klasse te maken. De klasse definieert zowel het schema als de implementatie van de resource, dus u hoeft geen afzonderlijk MOF-bestand te maken. De mapstructuur voor een op klassen gebaseerde resource is ook eenvoudiger, omdat een DSCResources- map niet nodig is.
In een DSC-resource op basis van een klasse wordt het schema gedefinieerd als eigenschappen van de klasse die kan worden gewijzigd met kenmerken om het eigenschapstype op te geven. De resource wordt geïmplementeerd door Get()
, Set()
en Test()
methoden (gelijk aan de Get-TargetResource
, Set-TargetResource
en Test-TargetResource
functies in een scriptresource.
In dit artikel maken we een eenvoudige resource met de naam NewFile waarmee een bestand in een opgegeven pad wordt beheerd.
Zie Aangepaste Windows PowerShell Desired State Configuration-resources bouwen voor meer informatie over DSC-resources
Notitie
Algemene verzamelingen worden niet ondersteund in op klassen gebaseerde resources.
Mapstructuur voor een klasseresource
Als u een aangepaste DSC-resource wilt implementeren met een PowerShell-klasse, maakt u de volgende mapstructuur.
De klasse wordt gedefinieerd in MyDscResource.psm1
en het modulemanifest wordt gedefinieerd in MyDscResource.psd1
.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
MyDscResource.psm1
MyDscResource.psd1
De klasse maken
U gebruikt het trefwoord klasse om een PowerShell-klasse te maken. Als u wilt opgeven dat een klasse een DSC-resource is, gebruikt u het kenmerk DscResource()
. De naam van de klasse is de naam van de DSC-resource.
[DscResource()]
class NewFile {
}
Eigenschappen declareren
Het DSC-resourceschema wordt gedefinieerd als eigenschappen van de klasse. We declareren drie eigenschappen als volgt.
[DscProperty(Key)]
[string] $path
[DscProperty(Mandatory)]
[ensure] $ensure
[DscProperty()]
[string] $content
[DscProperty(NotConfigurable)]
[MyDscResourceReason[]] $Reasons
U ziet dat de eigenschappen worden gewijzigd door kenmerken. De betekenis van de kenmerken is als volgt:
- DscProperty(Key): de eigenschap is vereist. De eigenschap is een sleutel. De waarden van alle eigenschappen die als sleutels zijn gemarkeerd, moeten worden gecombineerd om een resource-exemplaar in een configuratie uniek te identificeren.
- DscProperty(Verplicht): de eigenschap is vereist.
-
DscProperty(NotConfigurable): de eigenschap heeft het kenmerk Alleen-lezen. Eigenschappen die zijn gemarkeerd met dit kenmerk kunnen niet worden ingesteld door een configuratie, maar worden ingevuld door de
Get()
methode wanneer deze aanwezig zijn. - DscProperty(): de eigenschap kan worden geconfigureerd, maar is niet vereist.
De eigenschappen $Path
en $SourcePath
zijn beide tekenreeksen. De $CreationTime
is een eigenschap DateTime. De eigenschap $Ensure
is een opsommingstype dat als volgt is gedefinieerd.
enum Ensure
{
Absent
Present
}
Klassen insluiten
Als u een nieuw type wilt opnemen met gedefinieerde eigenschappen die u in uw resource kunt gebruiken, maakt u een klasse met eigenschapstypen zoals hierboven beschreven.
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
Notitie
De MyDscResourceReason
klasse wordt hier gedeclareerd met de naam van de module als voorvoegsel. Hoewel u ingesloten klassen een willekeurige naam kunt geven, als twee of meer modules een klasse met dezelfde naam definiëren en beide worden gebruikt in een configuratie, genereert PowerShell een uitzondering.
Als u uitzonderingen wilt voorkomen die worden veroorzaakt door naamconflicten in DSC, moet u de namen van uw ingesloten klassen vooraf laten gaan door de modulenaam. Als de naam van uw ingesloten klasse al niet conflicteert, kunt u deze gebruiken zonder voorvoegsel.
Als uw DSC-resource is ontworpen voor gebruik met de machineconfiguratiefunctie van Azure Automanage, moet u altijd de naam van de ingesloten klasse vooraf laten gaan die u maakt voor de eigenschap Redenen.
Openbare en privéfuncties
U kunt PowerShell-functies maken in hetzelfde modulebestand en deze gebruiken in de methoden van uw DSC-klasseresource. De functies moeten als openbaar worden gedeclareerd, maar de scriptblokken binnen deze openbare functies kunnen functies aanroepen die privé zijn. Het enige verschil is of ze worden vermeld in de eigenschap FunctionsToExport
van het modulemanifest.
<#
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
}
De methoden implementeren
De methoden Get()
, Set()
en Test()
zijn vergelijkbaar met de functies Get-TargetResource
, Set-TargetResource
en Test-TargetResource
in een scriptresource.
Minimaliseer als best practice de hoeveelheid code binnen de klasse-implementatie. Verplaats in plaats daarvan het merendeel van uw code naar openbare functies in de module, die vervolgens onafhankelijk kunnen worden getest.
<#
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
}
Het volledige bestand
Het volledige klassebestand volgt.
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
}
}
Een manifest maken
Als u een klasseresource beschikbaar wilt maken voor de DSC-engine, moet u een DscResourcesToExport
-instructie opnemen in het manifestbestand waarmee de module wordt geïnstrueerd om de resource te exporteren. Ons manifest ziet er als volgt uit:
@{
# 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
}
}
De resource testen
Nadat u de klasse- en manifestbestanden in de mapstructuur hebt opgeslagen zoals eerder is beschreven, kunt u een configuratie maken die gebruikmaakt van de nieuwe resource. Zie Configuraties uitvoerenvoor meer informatie over het uitvoeren van een DSC-configuratie. Met de volgende configuratie wordt gecontroleerd of het bestand op /tmp/test.txt
bestaat en of de inhoud overeenkomt met de tekenreeks van de eigenschap 'Inhoud'. Zo niet, dan wordt het hele bestand geschreven.
Configuration MyConfig
{
Import-DSCResource -ModuleName NewFile
NewFile testFile
{
Path = "/tmp/test.txt"
Content = "DSC Rocks!"
Ensure = "Present"
}
}
MyConfig
Ondersteuning voor PsDscRunAsCredential
[Opmerking] PsDscRunAsCredential- wordt ondersteund in PowerShell 5.0 en hoger.
De eigenschap PsDscRunAsCredential kan worden gebruikt in DSC-configuraties resourceblok om op te geven dat de resource moet worden uitgevoerd onder een opgegeven set referenties. Zie DSC uitvoeren met gebruikersreferentiesvoor meer informatie.
PsDscRunAsCredential vereisen of weigeren voor uw resource
Het kenmerk DscResource()
gebruikt een optionele parameter RunAsCredential-. Deze parameter heeft een van de drie waarden:
-
Optional
PsDscRunAsCredential- is optioneel voor configuraties die deze resource aanroepen. Dit is de standaardwaarde. -
Mandatory
PsDscRunAsCredential- moet worden gebruikt voor elke configuratie die deze resource aanroept. -
NotSupported
Configuraties die deze resource aanroepen, kunnen PsDscRunAsCredential-niet gebruiken. -
Default
Hetzelfde alsOptional
.
Gebruik bijvoorbeeld het volgende kenmerk om op te geven dat uw aangepaste resource geen ondersteuning biedt voor het gebruik van PsDscRunAsCredential-:
[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}
Meerdere klassebronnen declareren in een module
Een module kan meerdere DSC-resources op basis van klassen definiëren. U hoeft alleen alle klassen in hetzelfde .psm1
bestand te declareren en elke naam op te nemen in het .psd1
manifest.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
|- MyDscResource.psm1
MyDscResource.psd1
Toegang tot de gebruikerscontext
Als u toegang wilt krijgen tot de gebruikerscontext vanuit een aangepaste resource, kunt u de automatische variabele $global:PsDscContext
gebruiken.
Met de volgende code wordt bijvoorbeeld de gebruikerscontext geschreven waaronder de resource wordt uitgevoerd naar de uitgebreide uitvoerstroom:
if (PsDscContext.RunAsUser) {
Write-Verbose "User: $global:PsDscContext.RunAsUser";
}
Zie ook
Aangepaste Windows PowerShell Desired State Configuration-resources maken