Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Pode definir um Recurso do DSC ao criar uma classe do PowerShell. Num Recurso DSC baseado na classe, o esquema é definido como propriedades da classe que podem ser modificadas com atributos para especificar o tipo de propriedade. O Recurso é implementado com métodos Get, Set e Test (igual às Get-TargetResource
funções , Set-TargetResource
e Test-TargetResource
num Recurso de script).
Neste artigo, criamos um Recurso mínimo com o nome NewFile
que gere um ficheiro num caminho especificado.
Para obter mais informações sobre os Recursos do DSC, veja Recursos do DSC.
Nota
As coleções genéricas não são suportadas em Recursos baseados na classe.
Estrutura de pastas para um Recurso de classe
Para implementar um Recurso DSC com uma classe do PowerShell, crie a seguinte estrutura de pastas. A classe é definida em MyDscResource.psm1
e o manifesto do módulo é definido em MyDscResource.psd1
.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
MyDscResource.psm1
MyDscResource.psd1
Criar a classe
Utilize a class
palavra-chave para criar uma classe do PowerShell. Para especificar que uma classe é um Recurso DSC, utilize o DscResource()
atributo . O nome da classe é o nome do Recurso do DSC.
[DscResource()]
class NewFile {
}
Declarar propriedades
O esquema de Recursos do DSC é definido como propriedades da classe. Declaramos três propriedades da seguinte forma.
[DscProperty(Key)]
[string] $path
[DscProperty(Mandatory)]
[ensure] $ensure
[DscProperty()]
[string] $content
[DscProperty(NotConfigurable)]
[MyDscResourceReason[]] $Reasons
Repare que as propriedades são modificadas por atributos. O significado dos atributos é o seguinte:
- DscProperty(Chave): a propriedade é necessária. A propriedade é uma chave. Os valores de todas as propriedades marcadas como chaves têm de ser combinados para identificar exclusivamente uma Instância de recurso numa configuração.
- DscProperty(Obrigatório): a propriedade é necessária.
- DscProperty(NotConfigurable): a propriedade é só de leitura. As propriedades marcadas com este atributo não podem ser definidas por uma configuração, mas são preenchidas pelo método Get .
- DscProperty(): a propriedade é configurável, mas não é necessária.
As propriedades Path e SourcePath são ambas cadeias. O CreationTime é uma propriedade DateTime . A propriedade Garantir é um tipo de enumeração, definido da seguinte forma.
enum Ensure {
Absent
Present
}
Incorporar classes
Se quiser incluir um novo tipo com propriedades definidas que pode utilizar no recurso do DSC, crie uma classe com tipos de propriedade, conforme descrito anteriormente.
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
Nota
A MyDscResourceReason
classe é declarada aqui com o nome do módulo como um prefixo. Embora possa atribuir qualquer nome às classes incorporadas, se dois ou mais módulos definirem uma classe com o mesmo nome e forem ambos utilizados numa configuração, o PowerShell cria uma exceção.
Para evitar exceções causadas por conflitos de nomes no DSC, prefixe os nomes das classes incorporadas com o nome do módulo. Se o nome da sua classe incorporada já não estiver em conflito, pode utilizá-lo sem um prefixo.
Se o recurso do DSC for concebido para utilização com a funcionalidade de configuração do computador do Azure Automanage, prefixe sempre o nome da classe incorporada que criar para a propriedade Reasons .
Funções Públicas e Privadas
Pode criar funções do PowerShell no mesmo ficheiro de módulo e utilizá-las dentro dos métodos da classe do Recurso do DSC. As funções têm de ser exportadas como membros do módulo na definição FunctionsToExport do manifesto do módulo. Os blocos de script nessas funções podem chamar funções não reportadas.
<#
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 $path -ErrorAction SilentlyContinue
if ($fileExists) {
$filePresent.phrase = @(
"The file was expected to be: $ensure"
"The file exists at path: $path"
) -join "`n"
$existingFileContent = Get-Content $path -Raw
if ([string]::IsNullOrEmpty($existingFileContent)) {
$existingFileContent = ''
}
if (![string]::IsNullOrEmpty($content)) {
$content = $content | ConvertTo-SpecialChars
}
$fileContent.phrase = @(
"The file was expected to contain: $content"
"The file contained: $existingFileContent"
) -join "`n"
if ($content -eq $existingFileContent) {
$ensureReturn = 'Present'
}
} else {
$filePresent.phrase = @(
"The file was expected to be: $ensure"
"The file does not exist at path: $path"
) -join "`n"
$path = 'file not found'
}
@{
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
}
$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])
}
$string
}
Implementar os métodos
Os métodos Get, Set e Test são análogos às Get-TargetResource
funções , Set-TargetResource
e Test-TargetResource
num Recurso de script.
É melhor prática limitar a quantidade de código na implementação da classe. Mova a maioria do seu código para funções de módulo exportadas, que pode testar de forma independida.
<#
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
}
O ficheiro completo
Segue-se o ficheiro de classe completo.
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 $path -ErrorAction SilentlyContinue
if ($fileExists) {
$filePresent.phrase = @(
"The file was expected to be: $ensure"
"The file exists at path: $path"
) -join "`n"
$existingFileContent = Get-Content $path -Raw
if ([string]::IsNullOrEmpty($existingFileContent)) {
$existingFileContent = ''
}
if (![string]::IsNullOrEmpty($content)) {
$content = $content | ConvertTo-SpecialChars
}
$fileContent.phrase = @(
"The file was expected to contain: $content"
"The file contained: $existingFileContent"
) -join "`n"
if ($content -eq $existingFileContent) {
$ensureReturn = 'Present'
}
} else {
$filePresent.phrase = @(
"The file was expected to be: $ensure"
"The file does not exist at path: $path"
) -join "`n"
$path = 'file not found'
}
@{
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
}
}
Criar um manifesto
Para disponibilizar um Recurso DSC baseado na classe, tem de incluir uma DscResourcesToExport
instrução no ficheiro de manifesto que instrui o módulo a exportar o Recurso do DSC. O nosso manifesto tem o seguinte aspeto:
@{
# 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
}
}
Testar o Recurso
Depois de guardar os ficheiros de classe e manifesto na estrutura de pastas descrita anteriormente, pode criar uma Configuração do DSC que utilize o novo Recurso DSC. As seguintes Configuration
verificações para ver se o ficheiro em /tmp/test.txt
existe e se os conteúdos correspondem à cadeia fornecida pela propriedade Conteúdo. Caso contrário, todo o ficheiro é escrito.
Configuration MyConfig {
Import-DSCResource -ModuleName NewFile
NewFile testFile {
Path = "/tmp/test.txt"
Content = "DSC Rocks!"
Ensure = "Present"
}
}
MyConfig
Declarar vários Recursos DSC baseados em classes num módulo
Um módulo pode definir vários Recursos DSC baseados em classes. Tem de declarar todas as classes no mesmo .psm1
ficheiro e incluir cada nome no .psd1
manifesto.
$env:ProgramFiles\PowerShell\Modules (folder)
|- MyDscResource (folder)
|- MyDscResource.psm1
MyDscResource.psd1