Escribir un recurso de DSC personalizado con clases de PowerShell
Se aplica a: Windows PowerShell 5.0
Con la introducción de las 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, así que no hay necesidad de crear un archivo MOF independiente. La estructura de carpetas de un recurso basado en clases también es más sencilla, porque no es necesaria una carpeta DSCResources.
En un recurso de DSC basado en clases, el esquema se define como propiedades de la clase que se pueden modificar con atributos para especificar el tipo de propiedad. El recurso se implementa con los métodos Get()
, Set()
y Test()
(equivalentes a las funciones 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 más información sobre los recursos DSC, consulte Crear recursos de configuración de estado deseado de Windows PowerShell personalizados.
Nota
Los recursos basados en clases no admiten colecciones genéricas.
Estructura de carpetas de un recurso de clase
Para implementar un recurso de DSC personalizado 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
Crear la clase
Utilice 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. Se declaran 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 las propiedades se modifican mediante atributos. El significado de los atributos es el que se muestra a continuación:
- DscProperty(Key) : La propiedad es obligatoria. Se trata de una clave. Los valores de todas las propiedades marcadas como claves deben combinarse para identificar de forma única la instancia de un recurso dentro de una configuración.
- DscProperty(Mandatory) : La propiedad es obligatoria.
- 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 con el método
Get()
cuando existe. - DscProperty() : La propiedad se puede configurar, pero no es obligatoria.
Las propiedades $Path
y $SourcePath
son cadenas. $CreationTime
es una propiedad DateTime. La propiedad $Ensure
es un tipo de enumeración, que se define como se indica a continuación.
enum Ensure
{
Absent
Present
}
Inserción de clases
Si quiere incluir un nuevo tipo con propiedades definidas para usarlo dentro del recurso, simplemente cree una clase con tipos de propiedad como se ha explicado anteriormente.
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
Nota
La MyDscResourceReason
clase 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, anteponga los nombres de las clases incrustadas con el nombre del módulo. Si no es probable que el nombre de la clase insertada entre en conflicto, puede usarlo sin un 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 anteponga el nombre de la clase insertada 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 de DSC. Las funciones se deben declarar como públicas, pero los bloques de script dentro de esas funciones públicas pueden llamar a funciones privadas. La única diferencia es si aparecen 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
}
Implementar los métodos
Los métodos Get()
, Set()
y Test()
son análogos a las funciones Get-TargetResource
, Set-TargetResource
y Test-TargetResource
de un recurso de script.
Como procedimiento recomendado, minimice la cantidad de código dentro de la implementación de 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
}
El archivo completo
A continuación se muestra el archivo de clases 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
}
}
Crear 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 se exporten los recursos. El 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
}
}
Probar el recurso
Después de guardar la clase y los archivos de manifiesto en la estructura de carpetas tal y como se describió anteriormente, puede crear una configuración que utilice el nuevo recurso. Para obtener información sobre cómo ejecutar una configuración DSC, consulte Establecer configuraciones. La siguiente configuración comprueba si el archivo de /tmp/test.txt
existe y si el contenido coincide con la cadena proporcionada por la propiedad "Content". Si no, 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 es compatible con PowerShell 5.0 y versiones posteriores.
La propiedad PsDscRunAsCredential se puede usar en el bloque de recursos de configuraciones de DSC para especificar que el recurso se debe ejecutar bajo un conjunto especificado de credenciales. Para más información, consulte DSC de ejecución con las credenciales de usuario.
Exigir o impedir PsDscRunAsCredential para el recurso
El atributo DscResource()
toma un parámetro opcional RunAsCredential. Este parámetro toma uno de estos 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
Las configuraciones que llaman a este recurso no pueden usar PsDscRunAsCredential.Default
Igual queOptional
.
Por ejemplo, use el atributo siguiente para especificar que el recurso personalizado no admite el uso de PsDscRunAsCredential:
[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}
Declaración de 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 del mismo .psm1
archivo e incluir cada nombre en el .psd1
manifiesto.
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
|- MyDscResource.psm1
MyDscResource.psd1
Acceso al contexto de usuario
Para tener acceso al contexto de usuario desde un recurso personalizado, puede usar la variable automática $global:PsDscContext
.
Por ejemplo, el código siguiente podría escribir el contexto de usuario bajo el cual se ejecuta el recurso en el flujo de salida detallado:
if (PsDscContext.RunAsUser) {
Write-Verbose "User: $global:PsDscContext.RunAsUser";
}
Consulte también
Crear recursos de configuración de estado deseado de Windows PowerShell personalizados
Comentarios
https://aka.ms/ContentUserFeedback.
Próximamente: A lo largo de 2024 iremos eliminando gradualmente GitHub Issues como mecanismo de comentarios sobre el contenido y lo sustituiremos por un nuevo sistema de comentarios. Para más información, vea:Enviar y ver comentarios de