PowerShell DSC - как передать параметры конфигурации в ScriptResources?

у меня есть много проблем, пытаясь получить сценарий конфигурации желаемого состояния 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:myappconfig"
            ConfigFile = "C:myappconfigconfig.txt"
        }
        @{
            NodeName = "ServerA"
            Enabled = "true"
        }
        @{
            NodeName = "ServerB"
            Enabled = "false"
        }
    )
}

и я применяю DSC со следующим:

$mof = MyApp -ConfigurationData $config;
Start-DscConfiguration MyApp –Wait –Verbose;

когда я применяю эту конфигурацию, он с радостью создает папку, но ничего не делает с файлом конфигурации. Глядя на вывод ниже, очевидно, что это потому, что переменная $Node равна null внутри области ConfigurationFile / TestScript, но я понятия не имею, как ссылаться на нее из этого блока.

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" в моем скрипте. Я застрял в том, как ссылаться на данные конфигурации из ресурса скрипта, такого как мой "файл конфигурации".

Я нарисовал полный пробел, поэтому любая помощь будет очень признательна. Если все остальное не удастся, мне, возможно, придется ... создайте отдельный скрипт "конфигурации" на сервере и жестко Закодируйте значения, чего я действительно не хочу делать, если это вообще возможно.

спасибо,

Майк

4 ответов


ConfigurationData существует только во время компиляции MOF-файлов, а не во время выполнения, когда ядро DSC применяет ваши скрипты. Атрибуты SetScript, GetScript и TestScript ресурса скрипта на самом деле являются строками, а не блоками скриптов.

можно генерировать эти строки сценария (с учетом всех необходимых данных из данных конфигурации уже расширили), но вы должны быть осторожны, чтобы использовать побеги, подвыражения и кавычки правильно.

Я опубликовал краткий пример этого в исходном потоке 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


основываясь на ответе Дэвида, я написал служебную функцию, которая преобразует мой блок скрипта в строку, а затем выполняет очень наивный поиск и замену, чтобы развернуть ссылки на данные конфигурации следующим образом.

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);
            }

вы должны помнить о кавычках и escapes в ваших данных конфигурации, потому что Format-Dscriptblock выполняет только буквальную подстановку, но это было достаточно хорошо для моих целей.


довольно элегантный способ решить эту проблему-работать с обычным {0} заполнители. Применяя -f оператор заполнители могут быть заменены их фактическими значениями.

единственным недостатком этого метода является то, что вы не можете использовать фигурные скобки { } для чего-либо, кроме заполнителей (например, хэш-таблицы или for-loop), потому что требует, чтобы фигурные скобки содержали целое число.

ваш код тогда выглядит так это:

        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 уже должны были быть заменены там.