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 Resources をビルドする」を参照してください。
手記
ジェネリック コレクションは、クラス ベースのリソースではサポートされていません。
クラス リソースのフォルダー構造
PowerShell クラスを使用して DSC カスタム リソースを実装するには、次のフォルダー構造を作成します。
クラスは MyDscResource.psm1
で定義され、モジュール マニフェストは MyDscResource.psd1
で定義されます。
$env:ProgramFiles\WindowsPowerShell\Modules (folder)
|- MyDscResource (folder)
MyDscResource.psm1
MyDscResource.psd1
クラスを作成する
class キーワードを使用して PowerShell クラスを作成します。 クラスが 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
}
手記
ここで、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 を要求または禁止する
- PsDscRunAsCredential
、このリソースを呼び出す構成では省略可能です。 これが既定値です。 - PsDscRunAsCredential
、このリソースを呼び出す構成に使用する必要があります。 このリソースを呼び出す構成では、PsDscRunAsCredential 使用できません。 -
Default
Optional
と同じです。
たとえば、次の属性を使用して、カスタム リソースで PsDscRunAsCredentialの使用がサポートされていないことを指定します。
[DscResource(RunAsCredential=NotSupported)]
class NewFile {
}
モジュールで複数のクラス リソースを宣言する
モジュールでは、複数のクラス ベースの 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";
}
関連項目
カスタム Windows PowerShell Desired State Configuration Resources をビルドする