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