PowerShell クラスを使用したカスタム DSC リソースの記述
適用先:Windows PowerShell 5.0
Windows PowerShell 5.0 の PowerShell クラスの導入により、クラスを作成して DSC リソースを定義できるようになりました。 クラスでは、スキーマとリソースの実装の両方を定義するため、MOF ファイルを別途作成する必要がありません。 DSCResources フォルダーが必要ないため、クラスベースのリソースのフォルダー構造は単純になりました。
クラス ベースの DSC リソースでは、スキーマはクラスのプロパティとして定義されます。このプロパティは、プロパティの種類を指定するために属性で変更できます。 リソースは、Get()
、Set()
、および Test()
メソッド (スクリプト リソースの Get-TargetResource
、Set-TargetResource
、および Test-TargetResource
関数に相当します) によって実装されます。
この記事では、指定したパス内のファイルを管理する NewFile という名前の単純なリソースを作成します。
DSC リソースの詳細については、「カスタム Windows PowerShell Desired State Configuration のビルド」をご覧ください。
Note
クラスベースのリソースでは、汎用コレクションはサポートされていません。
クラス リソースのフォルダー構造
PowerShell クラスを使用して DSC カスタム リソースを実装するには、次のフォルダー構造を作成します。
クラスは MyDscResource.psm1
で定義し、モジュール マニフェストは MyDscResource.psd1
で定義します。
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
MyDscResource.psm1
MyDscResource.psd1
クラスの作成
PowerShell クラスを作成するには、class キーワードを使用します。 クラスを DSC リソースとして指定するには、DscResource()
属性を使用します。 クラスの名前は、DSC リソースの名前です。
[DscResource()]
class NewFile {
}
プロパティの宣言
DSC リソースのスキーマは、クラスのプロパティとして定義します。 3 つのプロパティを次のように宣言します。
[DscProperty(Key)]
[string] $path
[DscProperty(Mandatory)]
[ensure] $ensure
[DscProperty()]
[string] $content
[DscProperty(NotConfigurable)]
[MyDscResourceReason[]] $Reasons
属性によってプロパティが変更されることに注意してください。 属性の意味は次のとおりです。
- DscProperty(Key) :このプロパティは必須です。 プロパティはキーです。 キーとしてマークされたすべてのプロパティの値を組み合わせて、構成内のリソース インスタンスを一意に識別する必要があります。
- DscProperty(Mandatory) :このプロパティは必須です。
- DscProperty(NotConfigurable) :このプロパティは読み取り専用です。 この属性でマークされたプロパティは、構成で設定できませんが、
Get()
メソッド (存在する場合) によって設定されます。 - DscProperty() :このプロパティは構成可能ですが、必須ではありません。
$Path
プロパティと $SourcePath
プロパティは、両方とも文字列です。 $CreationTime
は、DateTime プロパティです。 $Ensure
プロパティは、次のように定義された列挙型です。
enum Ensure
{
Absent
Present
}
埋め込みクラス
リソース内で使用できる定義済みプロパティと共に新しい型を含める場合、前述のようにプロパティ型でクラスを作成します。
class MyDscResourceReason {
[DscProperty()]
[string] $Code
[DscProperty()]
[string] $Phrase
}
Note
クラスは MyDscResourceReason
、モジュールの名前をプレフィックスとして使用して、ここで宣言されています。 埋め込みクラスには任意の名前を付けることができますが、2 つ以上のモジュールで同じ名前のクラスが定義され、両方とも構成で使用されている場合、PowerShell は例外を発生させます。
DSC で名前の競合によって発生する例外を回避するには、埋め込みクラスの名前の前にモジュール名を付けます。 埋め込みクラスの名前が競合する可能性が既に低い場合は、プレフィックスなしで使用できます。
DSC リソースが Azure Automanage のマシン構成機能で使用するように設計されている場合は、 Reasons プロパティ用に作成した埋め込みクラスの名前の前に必ずプレフィックスを付けます。
パブリック関数とプライベート関数
同じモジュール ファイル内に PowerShell 関数を作成し、その関数を DSC クラス リソースのメソッド内で使用できます。 関数はパブリックとして宣言する必要がありますが、これらのパブリック関数内のスクリプト ブロックはプライベートな関数を呼び出すことができます。 唯一の違いは、モジュール マニフェストの FunctionsToExport
プロパティに一覧表示されるかどうかです。
<#
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
}
メソッドの実装
Get()
、Set()
、および Test()
メソッドは、スクリプト リソースの Get-TargetResource
、Set-TargetResource
、および Test-TargetResource
関数に似ています。
ベスト プラクティスとして、クラス実装内のコードの量を最小限に抑えてください。 代わりに、コードの大部分をモジュール内のパブリック関数に移動します。これにより、個別にテストできます。
<#
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
}
完全なファイル
完全なクラス ファイルは次のとおりです。
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
}
}
マニフェストの作成
クラスベースのリソースを DSC エンジンで使用できるようにするには、マニフェスト ファイルに、リソースをエクスポートするようにモジュールに指示する DscResourcesToExport
ステートメントを含める必要があります。 この例では、マニフェストは次のようになります。
@{
# 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
}
}
リソースのテスト
既に説明したように、クラスとマニフェスト ファイルをフォルダー構造で保存した後で、新しいリソースを使用する構成を作成できます。 DSC 構成を実行する方法については、「構成の適用」をご覧ください。 次の構成では、ファイルが存在するかどうか、/tmp/test.txt
にファイルが存在するかと、プロパティ 'Content' で指定される文字列とコンテンツが一致するかが確認されます。 一致しない場合、ファイル全体が書き込まれます。
Configuration MyConfig
{
Import-DSCResource -ModuleName NewFile
NewFile testFile
{
Path = "/tmp/test.txt"
Content = "DSC Rocks!"
Ensure = "Present"
}
}
MyConfig
PsDscRunAsCredential のサポート
[注] PsDscRunAsCredential は、PowerShell 5.0 以降でサポートされています。
PsDscRunAsCredential プロパティを DSC 構成リソース ブロックで使用して、指定した資格情報のもとでリソースを実行する必要があることを指定できます。 詳細については、「ユーザーの資格情報を指定して DSC を実行する」を参照してください。
使用するリソースに対する PsDscRunAsCredential の要求または却下
DscResource()
属性でオプションのパラメーター RunAsCredential を指定します。 このパラメーターには以下の 3 つの値のいずれかを指定します。
Optional
PsDscRunAsCredential は、このリソースを呼び出す構成では省略可能です。 これが既定値です。Mandatory
PsDscRunAsCredential は、このリソースを呼び出す構成に使用する必要があります。NotSupported
このリソースを呼び出す構成には PsDscRunAsCredential を使用できません。Default
Optional
と同じです。
たとえば、次の属性を使用して、ご使用のカスタム リソースが PsDscRunAsCredential の使用をサポートしないことを指定します。
[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}
1 つのモジュールで複数のクラス リソースを宣言する
モジュールでは、複数のクラスベースの DSC リソースを定義できます。 同じ .psm1
ファイル内のすべてのクラスを宣言し、マニフェストに各名前を .psd1
含めるだけで済みます。
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
|- MyDscResource.psm1
MyDscResource.psd1
ユーザー コンテキストへのアクセス
カスタム リソース内からユーザー コンテキストにアクセスするには、自動変数 $global:PsDscContext
を使用できます。
たとえば、次のコードは、リソースが詳細出力ストリームに実行しているユーザー コンテキストを記述します。
if (PsDscContext.RunAsUser) {
Write-Verbose "User: $global:PsDscContext.RunAsUser";
}
参照
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示