我试图从脚本中删除变量的定义,并从类似于以下内容的 XML 配置文件中读取它们:
XML文件
<?xml version="1.0" encoding="utf-8" ?>
<settings>
<process>FALSE</process>
<xmlDir>\\serv1\dev</xmlDir>
<scanDir>\\serv1\dev</scanDir>
<processedDir>\\serv1\dev\done</processedDir>
<errorDir>\\serv1\dev\err</errorDir>
<log>\\serv1\dev\log\dev-Log##DATE##.log</log>
<retryDelay>5</retryDelay>
<retryLimit>3</retryLimit>
</settings>
Run Code Online (Sandbox Code Playgroud)
然后使用以下内容解析脚本中的 XML:
[xml]$configFile = Get-Content $PSScriptRoot\$confFile
$settings = $configFile.settings.ChildNodes
foreach ($setting in $settings) {
New-Variable -Name $setting.LocalName -Value ($setting.InnerText -replace '##DATE##',(get-date -f yyyy-MM-dd)) -Force
}
Run Code Online (Sandbox Code Playgroud)
这很好用,但问题是它们都作为字符串读取,但有些我需要作为整数读取。为了解决这个问题,我必须在创建变量后将它们更改为整数,如下所示:
$retryDelay = ([int]$retryDelay)
$retryLimit = ([int]$retryLimit)
Run Code Online (Sandbox Code Playgroud)
虽然这可行,但我希望在 XML 中包含其他变量,例如布尔值 $true / $false (并作为布尔值读入),并且宁愿让 foreach 能够处理它们的类型,而不是脚本中的其他行。任何线索表示赞赏。
首先,永远不要像这样读取 XML 文件。这会破坏 XML 解析器中内置的编码检测,并迟早会导致数据被破坏。
# BAD, DO NOT USE
[xml]$configFile = Get-Content $PSScriptRoot\$confFile
Run Code Online (Sandbox Code Playgroud)
正确读取 XML 文件的方式如下 - 创建一个新的 XML 对象并让它处理文件加载:
$configFile = New-Object xml
$configFile.Load("$PSScriptRoot\$confFile")
Run Code Online (Sandbox Code Playgroud)
其次,我强烈建议不要从文件创建全局变量。这是不好的风格,因为它很容易通过盲目覆盖现有变量来破坏你的程序。使用哈希来存储文件中的值,或者直接使用 XML 文件作为您的配置。
$config = @{}
foreach ($setting in $configFile.SelectNodes("/settings/*") ) {
$config[$setting.Name] = $setting.InnerText
}
Run Code Online (Sandbox Code Playgroud)
第三,XML没有固有的数据类型信息。一切都是字符串,直到您添加更多有关它的信息。一种方法可以是type属性(type="string"可以视为默认):
<settings>
<process type="boolean">FALSE</process>
<xmlDir type="string">\\serv1\dev</xmlDir>
<scanDir type="string">\\serv1\dev</scanDir>
<processedDir type="string">\\serv1\dev\done</processedDir>
<errorDir type="string">\\serv1\dev\err</errorDir>
<log type="string">\\serv1\dev\log\dev-Log##DATE##.log</log>
<retryDelay type="int">5</retryDelay>
<retryLimit type="int">3</retryLimit>
</settings>
Run Code Online (Sandbox Code Playgroud)
当然,该type属性本身没有任何意义。您需要编写关注这些属性并执行必要的类型转换(if ($setting.type -eq "boolean") { ... }等)的代码。
第四,我相信简单地使用 JSON 作为配置文件格式会更好。它更容易编辑并且具有固有的数据类型信息。
{
"settings": {
"process": false,
"xmlDir": "\\\\serv1\\dev",
"scanDir": "\\\\serv1\\dev",
"processedDir": "\\\\serv1\\dev\\done",
"errorDir": "\\\\serv1\\dev\\err",
"log": "\\\\serv1\dev\\log\\dev-Log##DATE##.log",
"retryDelay": 5,
"retryLimit": 3
}
}
Run Code Online (Sandbox Code Playgroud)
使用ConvertFrom-JSONcmdlet 解析数据。用来Get-Content -Encoding UTF8阅读它。
在处理文本文件时以及使用或Encoding写入文件时,使用该参数很重要。这里没有隐藏的魔法可以做正确的事情,您必须明确编码。Set-ContentOut-File
Out-File以下是有关和的行为的一些更深入的信息Set-Content。Powershell set-content 和 out-file 有什么区别?