Подтвердить что ты не робот

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

У меня много проблем с попыткой получить конфигурацию желаемого состояния PowerShell script, работающую над настройкой собственного приложения. Корень проблемы заключается в том, что я не могу передать свои данные конфигурации в ScriptResource (по крайней мере, не так, как я пытаюсь это сделать).

My script должен создать конфигурационную папку для нашего внутреннего приложения, а затем записать некоторые настройки в файл:

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 имеет значение 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.

Я сжег целый день в Интернете, чтобы узнать об этой конкретной проблеме, но все примеры переменных, параметров и данных конфигурации используют ресурсы File и Registry или другие ресурсы без script, которые у меня уже есть работая в блоке "ConfigurationFolder" в моем script. Я застрял в том, как ссылаться на данные конфигурации из ресурса script, например, на мой "ConfigurationFile".

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

Приветствия,

Mike

4b9b3361

Ответ 1

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

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

Я привел краткий пример этого в исходном потоке TechNet в http://social.technet.microsoft.com/Forums/en-US/2eb97d67-f1fb-4857-8840-de9c4cb9cae0/dsc-configuration-data-for-script-resources?forum=winserverpowershell

Ответ 2

Измените это: $Node.ConfigFolder на $using:Node.ConfigFolder.

Если у вас есть переменная с именем $Foo, и вы хотите, чтобы она была передана в ресурс script DSC, затем используйте $using:Foo

Ответ 3

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

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

Затем My 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 выполняет только литеральную замену, но это было достаточно для моих целей.

Ответ 4

Очень элегантный способ решить эту проблему - работать с обычными заполнителями {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))

Кроме того, хороший способ узнать, правильно ли вы делаете это, - просто просмотреть сгенерированный файл .mof с помощью текстового редактора; если вы посмотрите на сгенерированные элементы TestScript/GetScript/SetScript, вы увидите, что фрагмент кода действительно является строкой. Значения $placeholder уже должны быть заменены там.