PowerShell DSC - 如何将配置参数传递给ScriptResources?

mcl*_*ton 25 powershell dsc

我在尝试使用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"
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

作为参考,我的配置数据如下所示:

$config = @{
    AllNodes = @(
        @{
            NodeName = "*"
            ConfigFolder = "C:\myapp\config"
            ConfigFile = "C:\myapp\config\config.txt"
        }
        @{
            NodeName = "ServerA"
            Enabled = "true"
        }
        @{
            NodeName = "ServerB"
            Enabled = "false"
        }
    )
}
Run Code Online (Sandbox Code Playgroud)

我正在使用DSC进行以下操作:

$mof = MyApp -ConfigurationData $config;
Start-DscConfiguration MyApp –Wait –Verbose;
Run Code Online (Sandbox Code Playgroud)

当我应用此配置时,它很乐意创建该文件夹,但无法对配置文件执行任何操作.看看下面的输出,很明显,因为$ 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.
Run Code Online (Sandbox Code Playgroud)

我已经烧了一整天在线搜索这个特定的问题,但所有变量,参数和配置数据的例子都使用File和Registry资源或其他非脚本资源,我已经在"ConfigurationFolder"中工作了"阻止我的剧本.我坚持的是如何从像"ConfigurationFile"这样的脚本资源中引用配置数据.

我画了一个完整的空白,所以任何帮助将不胜感激.如果所有其他方法都失败了,我可能需要为每个服务器创建一个单独的"配置"脚本并对这些值进行硬编码,如果可能的话我真的不想这样做.

干杯,

麦克风

小智 34

改变这个:$Node.ConfigFolder$using:Node.ConfigFolder.

如果您有一个被调用的变量,$Foo并且您希望将其传递给脚本DSC资源,那么请使用$using:Foo

  • 但****点是将它放在$()中:`$($ using:Node.ConfigFolder)` (4认同)
  • 这个_should_是正确答案`$ using`是为了解决这个问题,不需要自己生成字符串...请参阅https://msdn.microsoft.com/en-us/powershell/dsc/scriptResource for一个例子. (4认同)

mcl*_*ton 10

根据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;
}
Run Code Online (Sandbox Code Playgroud)

我的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);
            }
Run Code Online (Sandbox Code Playgroud)

您必须注意配置数据中的引号和转义,因为Format-DscScriptBlock只执行文字替换,但这对我的目的来说已经足够了.


Ast*_*ain 8

解决此问题的一种非常优雅的方法是使用常规{0}占位符.通过应用-f运算符,占位符可以替换为其实际值.

这种方法的唯一缺点是你不能将花括号{}用于除占位符之外的任何东西(比如说哈希表或for循环),因为-f运算符要求大括号包含整数.

您的代码如下所示:

        SetScript = ({ 
            Set-ItemProperty "IIS:\AppPools\{0}" "managedRuntimeVersion" "v4.0"
            Set-ItemProperty "IIS:\AppPools\{0}" "managedPipelineMode" 1 # 0 = Integrated, 1 = Classic
        } -f @($ApplicationPoolName))
Run Code Online (Sandbox Code Playgroud)

此外,通过简单地使用文本编辑器查看生成的.mof文件,一个很好的方法来确定您是否正确执行此操作; 如果你看一下生成的TestScript/GetScript/SetScript成员,你会发现代码片段确实是一个字符串.$占位符值应该已经在那里被替换.

  • 实际上,你可以使用花括号,你只需要加倍它们(所以```变成``{{`和`}`变成`}}`). (4认同)

小智 7

ConfigurationData仅在编译MOF文件时存在,而不是在DSC引擎应用脚本时的运行时.Script资源的SetScript,GetScript和TestScript属性实际上是字符串,而不是脚本块.

可以生成这些脚本字符串(已经扩展了ConfigurationData中的所有必需数据),但是必须小心正确使用转义符,子表达式和引号.

我在原始的TechNet主题上发布了一个简短的例子,网址是http://social.technet.microsoft.com/Forums/en-US/2eb97d67-f1fb-4857-8840-de9c4cb9cae0/dsc-configuration-data-for-脚本资源?论坛= winserverpowershell