Escritura de un recurso de DSC personalizado con clases de PowerShell
Se aplica a: Windows PowerShell 5.0
Con la introducción de clases de PowerShell en Windows PowerShell 5.0, ahora puede definir un recurso de DSC mediante la creación de una clase . La clase define el esquema y la implementación del recurso, por lo que no es necesario crear un archivo MOF independiente. La estructura de carpetas de un recurso basado en clases también es más sencilla, ya que no es necesaria una carpeta de DSCResources.
En un recurso de DSC basado en clases, el esquema se define como propiedades de la clase que se puede modificar con atributos para especificar el tipo de propiedad. El recurso se implementa mediante métodos Get()
, Set()
y Test()
(equivalentes a las funciones de Get-TargetResource
, Set-TargetResource
y Test-TargetResource
en un recurso de script.
En este artículo, crearemos un recurso simple denominado NewFile que administra un archivo en una ruta de acceso especificada.
Para obtener más información sobre los recursos de DSC, consulte Build Custom Windows PowerShell Desired State Configuration Resources
Nota
Las colecciones genéricas no se admiten en recursos basados en clases.
Estructura de carpetas de un recurso de clase
Para implementar un recurso personalizado de DSC con una clase de PowerShell, cree la siguiente estructura de carpetas.
La clase se define en MyDscResource.psm1
y el manifiesto del módulo se define en MyDscResource.psd1
.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
MyDscResource.psm1
MyDscResource.psd1
Creación de la clase
Use la palabra clave class para crear una clase de PowerShell. Para especificar que una clase es un recurso de DSC, use el atributo DscResource()
. El nombre de la clase es el nombre del recurso de DSC.
[DscResource()]
class NewFile {
}
Declarar propiedades
El esquema de recursos de DSC se define como propiedades de la clase . Declaramos tres propiedades como se indica a continuación.
[DscProperty(Key)]
[string] $path
[DscProperty(Mandatory)]
[ensure] $ensure
[DscProperty()]
[string] $content
[DscProperty(NotConfigurable)]
[MyDscResourceReason[]] $Reasons
Observe que los atributos modifican las propiedades. El significado de los atributos es el siguiente:
- DscProperty(Key): se requiere la propiedad . La propiedad es una clave. Los valores de todas las propiedades marcadas como claves deben combinarse para identificar de forma única una instancia de recurso dentro de una configuración.
- DscProperty(Obligatorio): se requiere la propiedad .
-
DscProperty(NotConfigurable): la propiedad es de solo lectura. Las propiedades marcadas con este atributo no se pueden establecer mediante una configuración, pero se rellenan mediante el método
Get()
cuando están presentes. - DscProperty(): la propiedad es configurable, pero no es necesaria.
Las propiedades $Path
y $SourcePath
son cadenas. El $Ensure
es un tipo de enumeración, definido como se indica a continuación.
enum Ensure
{
Absent
Present
}
Inserción de clases
Si desea incluir un nuevo tipo con propiedades definidas que puede usar en el recurso, solo tiene que crear una clase con tipos de propiedad como se describió anteriormente.
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
Nota
La clase MyDscResourceReason
se declara aquí con el nombre del módulo como prefijo. Aunque puede asignar cualquier nombre a las clases incrustadas, si dos o más módulos definen una clase con el mismo nombre y se usan en una configuración, PowerShell genera una excepción.
Para evitar excepciones causadas por conflictos de nombres en DSC, prefijo los nombres de las clases insertadas con el nombre del módulo. Si no es probable que el nombre de la clase insertada entre en conflicto, puede usarlo sin prefijo.
Si el recurso de DSC está diseñado para su uso con la característica de configuración de la máquina de Azure Automanage, siempre prefijo el nombre de la clase incrustada que cree para la propiedad Reasons.
Funciones públicas y privadas
Puede crear funciones de PowerShell en el mismo archivo de módulo y usarlas dentro de los métodos del recurso de clase DSC. Las funciones deben declararse como públicas, pero los bloques de script dentro de esas funciones públicas pueden llamar a funciones privadas. La única diferencia es si se muestran en la propiedad FunctionsToExport
del manifiesto del módulo.
<#
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
}
Implementación de los métodos
Los métodos Get()
, Set()
y Test()
son análogos a las funciones Get-TargetResource
, Set-TargetResource
y Test-TargetResource
en un recurso de script.
Como procedimiento recomendado, minimice la cantidad de código dentro de la implementación de la clase. En su lugar, mueva la mayoría del código a las funciones públicas del módulo, que luego se pueden probar de forma independiente.
<#
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
}
Archivo completo
A continuación se muestra el archivo de clase 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 -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
}
}
Creación de un manifiesto
Para que un recurso basado en clases esté disponible para el motor de DSC, debe incluir una instrucción DscResourcesToExport
en el archivo de manifiesto que indique al módulo que exporte el recurso. Nuestro manifiesto tiene este aspecto:
@{
# 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
}
}
Prueba del recurso
Después de guardar los archivos de clase y manifiesto en la estructura de carpetas como se ha descrito anteriormente, puede crear una configuración que use el nuevo recurso. Para obtener información sobre cómo ejecutar una configuración de DSC, consulte Configuración de la creación de. La siguiente configuración comprobará si el archivo en /tmp/test.txt
existe y si el contenido coincide con la cadena proporcionada por la propiedad "Content". Si no es así, se escribe todo el archivo.
Configuration MyConfig
{
Import-DSCResource -ModuleName NewFile
NewFile testFile
{
Path = "/tmp/test.txt"
Content = "DSC Rocks!"
Ensure = "Present"
}
}
MyConfig
Compatibilidad con PsDscRunAsCredential
[Nota] psDscRunAsCredential se admite en PowerShell 5.0 y versiones posteriores.
La propiedad psDscRunAsCredential se puede usar en configuraciones de DSC bloque de recursos para especificar que el recurso debe ejecutarse en un conjunto especificado de credenciales. Para obtener más información, consulte Ejecución de DSC con credenciales de usuario.
Requerir o no permitir PsDscRunAsCredential para el recurso
El atributo DscResource()
toma un parámetro opcional runAsCredential. Este parámetro toma uno de los tres valores:
-
Optional
psDscRunAsCredential es opcional para las configuraciones que llaman a este recurso. Este es el valor predeterminado. -
Mandatory
psDscRunAsCredential debe usarse para cualquier configuración que llame a este recurso. -
NotSupported
Configuraciones que llaman a este recurso no pueden usar PsDscRunAsCredential. -
Default
igual queOptional
.
Por ejemplo, use el siguiente atributo para especificar que el recurso personalizado no admite el uso de PsDscRunAsCredential:
[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}
Declarar varios recursos de clase en un módulo
Un módulo puede definir varios recursos de DSC basados en clases. Solo tiene que declarar todas las clases en el mismo archivo .psm1
e incluir cada nombre en el manifiesto de .psd1
.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
|- MyDscResource.psm1
MyDscResource.psd1
Acceso al contexto del usuario
Para acceder al contexto de usuario desde un recurso personalizado, puede usar la variable automática $global:PsDscContext
.
Por ejemplo, el código siguiente escribiría el contexto de usuario en el que se ejecuta el recurso en el flujo de salida detallado:
if (PsDscContext.RunAsUser) {
Write-Verbose "User: $global:PsDscContext.RunAsUser";
}
Consulte también
crear recursos personalizados de configuración de estado deseado de Windows PowerShell