社内アプリケーションを構成するためにPowerShellの必要な状態の構成スクリプトを機能させるのに苦労しています。問題の根本は、構成データをScriptResourceに渡すことができないように思えるということです(少なくとも、私がやろうとしている方法では)。
私のスクリプトは、社内アプリケーション用の構成フォルダーを作成し、いくつかの設定をファイルに書き込むことになっています。
configuration MyApp {
param (
[string[]] $ComputerName = $env:ComputerName
)
node $ComputerName {
File ConfigurationFolder {
Type = "Directory"
DestinationPath = $Node.ConfigFolder
Ensure = "Present"
}
Script ConfigurationFile {
SetScript = {
write-verbose "running ConfigurationFile.SetScript";
write-verbose "folder = $($Node.ConfigFolder)";
write-verbose "filename = $($Node.ConfigFile)";
[System.IO.File]::WriteAllText($Node.ConfigFile, "enabled=" + $Node.Enabled);
}
TestScript = {
write-verbose "running ConfigurationFile.TestScript";
write-verbose "folder = $($Node.ConfigFolder)";
write-verbose "filename = $($Node.ConfigFile)";
return (Test-Path $Node.ConfigFile);
}
GetScript = { @{Configured = (Test-Path $Node.ConfigFile)} }
DependsOn = "[File]ConfigurationFolder"
}
}
}
参考までに、私の構成データは次のようになります。
$config = @{
AllNodes = @(
@{
NodeName = "*"
ConfigFolder = "C:\myapp\config"
ConfigFile = "C:\myapp\config\config.txt"
}
@{
NodeName = "ServerA"
Enabled = "true"
}
@{
NodeName = "ServerB"
Enabled = "false"
}
)
}
そして、私はDSCを次のように適用しています:
$mof = MyApp -ConfigurationData $config;
Start-DscConfiguration MyApp –Wait –Verbose;
この構成を適用すると、フォルダは喜んで作成されますが、構成ファイルでは何もできません。以下の出力を見ると、$ Node変数がConfigurationFile/TestScriptのスコープ内でnullであることが原因であることが明らかですが、そのブロック内から参照する方法がわかりません。
LCM: [ Start Resource ] [[Script]ConfigurationFile]
LCM: [ Start Test ] [[Script]ConfigurationFile]
[[Script]ConfigurationFile] running ConfigurationFile.TestScript
[[Script]ConfigurationFile] node is null = True
[[Script]ConfigurationFile] folder =
[[Script]ConfigurationFile] filename =
LCM: [ End Test ] [[Script]ConfigurationFile] in 0.4850 seconds.
私はこの特定の問題をオンラインで検索して丸一日焼き尽くしましたが、変数、パラメーター、および構成データのすべての例はすべて、ファイルおよびレジストリリソースまたはその他の非スクリプトリソースを使用しています。これらは、「ConfigurationFolder "スクリプトでブロックします。私が行き詰まっているのは、 "ConfigurationFile"のようなスクリプトリソース内から構成データを参照する方法です。
私は完全な空白を描いたので、どんな助けでも大歓迎です。他のすべてが失敗した場合、サーバーごとに個別の「構成」スクリプトを作成し、値をハードコード化する必要があるかもしれません。
乾杯、
マイク
ConfigurationDataは、MOFファイルのコンパイル時にのみ存在し、DSCエンジンがスクリプトを適用する実行時には存在しません。スクリプトリソースのSetScript、GetScript、およびTestScript属性は、実際には文字列であり、スクリプトブロックではありません。
それらのスクリプト文字列を生成することは可能です(ConfigurationDataからのすべての必要なデータが既に展開されています)。ただし、エスケープ、部分式、引用符を正しく使用するように注意する必要があります。
この簡単な例を元のTechNetスレッドの http://social.technet.Microsoft.com/Forums/en-US/2eb97d67-f1fb-4857-8840-de9c4cb9cae0/dsc-configuration-に投稿しましたdata-for-script-resources?forum = winserverpowershell
これを変更します:$Node.ConfigFolder
を$using:Node.ConfigFolder
に変更します。
$Foo
という変数があり、それをスクリプトDSCリソースに渡したい場合は、$using:Foo
を使用します。
Davidの答えに基づいて、スクリプトブロックを文字列に変換し、非常に単純な検索と置換を実行して、次のように構成データへの参照を展開するユーティリティ関数を作成しました。
function Format-DscScriptBlock()
{
param(
[parameter(Mandatory=$true)]
[System.Collections.Hashtable] $node,
[parameter(Mandatory=$true)]
[System.Management.Automation.ScriptBlock] $scriptBlock
)
$result = $scriptBlock.ToString();
foreach( $key in $node.Keys )
{
$result = $result.Replace("`$Node.$key", $node[$key]);
}
return $result;
}
私のSetScriptは次のようになります。
SetScript = Format-DscScriptBlock -Node $Node -ScriptBlock {
write-verbose "running ConfigurationFile.SetScript";
write-verbose "folder = $Node.ConfigFolder";
write-verbose "filename = $Node.ConfigFile)";
[System.IO.File]::WriteAllText("$Node.ConfigFile", "enabled=" + $Node.Enabled);
}
Format-DscScriptBlockはリテラル置換のみを実行するため、構成データの引用符とエスケープに注意する必要がありますが、これは私の目的には十分です。
この問題を解決する非常にエレガントな方法は、通常の{0}
プレースホルダーを使用することです。 -f
演算子を適用することにより、プレースホルダーを実際の値に置き換えることができます。
このメソッドの唯一の欠点は、-f
演算子には波括弧に整数を含める必要があるため、プレースホルダー以外(つまり、ハッシュテーブルやforループなど)に波括弧{}を使用できないことです。
コードは次のようになります。
SetScript = ({
Set-ItemProperty "IIS:\AppPools\{0}" "managedRuntimeVersion" "v4.0"
Set-ItemProperty "IIS:\AppPools\{0}" "managedPipelineMode" 1 # 0 = Integrated, 1 = Classic
} -f @($ApplicationPoolName))
また、正しく実行されているかどうかを確認する良い方法は、生成された.mofファイルをテキストエディターで表示することです。生成されたTestScript/GetScript/SetScriptメンバーを見ると、コードフラグメントが実際には文字列であることがわかります。 $ placeholderの値は既に置き換えられているはずです。