我正在尝试从脚本中删除变量的定义,并从类似于下面的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>
然后使用以下内容解析脚本中的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
}
这很好用,但问题是它们都被读作字符串,但有些我需要作为整数。为了解决这个问题,我必须在创建变量之后将它们更改为整数:
$retryDelay = ([int]$retryDelay)
$retryLimit = ([int]$retryLimit)
虽然这有效,但我想在XML中有其他变量,例如boolean $ true / $ false(并以布尔值读入),而宁愿让foreach能够处理它们的类型而不是其他行在脚本中。任何线索都赞赏。
答案 0 :(得分:3)
首先,永远不要读这样的XML文件。这会破坏XML解析器中内置的编码检测,并且迟早会导致数据损坏。
# BAD, DO NOT USE
[xml]$configFile = Get-Content $PSScriptRoot\$confFile
正确读取XML文件 的工作原理如下 - 创建一个新的XML对象并让它处理文件加载:
$configFile = New-Object xml
$configFile.Load("$PSScriptRoot\$confFile")
其次,我强烈建议不要从文件创建全局变量。这是一种糟糕的风格,因为它可以通过盲目地覆盖现有变量来轻松破坏您的程序。使用哈希来存储文件中的值,或者直接使用XML文件作为配置。
$config = @{}
foreach ($setting in $configFile.SelectNodes("/settings/*") ) {
$config[$setting.Name] = $setting.InnerText
}
第三,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>
当然,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
}
}
使用ConvertFrom-JSON
cmdlet解析数据。使用Get-Content -Encoding UTF8
进行阅读。
在处理文本文件时,使用Encoding
参数非常重要,当您使用Set-Content
或Out-File
编写文件时也是如此。没有隐藏的魔法在这里做正确的事情,你必须明确编码。
以下是有关Out-File
和Set-Content
行为的更深入信息。 Powershell set-content and out-file what is the difference?
答案 1 :(得分:1)
我同意Tomalak的回答,JSON可能更适合您的用例。这是一个实用的例子,向您展示如何使用它。这是使用从哈希表创建的自定义对象,从中生成JSON并将其保存到文件中:
$Config = [pscustomobject]@{
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
}
$Config | ConvertTo-Json | Out-File .\config.txt -Encoding UTF8
这会创建如下所示的JSON:
{
"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
}
可以这样读:
$Settings = Get-Content .\config.txt -Encoding UTF8 | ConvertFrom-Json
由于您可以看到JSON存储变量的方式,PowerShell在回读它们时可以更好地正确键入它们。