我使用XML文件作为PowerShell脚本的配置文件,基于rkeithhill.wordpress.com上的博客文章。我的一些脚本共享相同的设置,我想从外部XML文件中包含这些设置。我所做的是:
<?xml version="1.0" standalone="no" ?>
<!DOCTYPE doc [
<!ENTITY shareddata SYSTEM "shared.xml">
]>
<configuration >
<appSettings >
&shareddata;
<add key="motorcycle" value="Husqvarna TE610" />
<add key="car" value="Ford Mondeo" />
</appSettings>
</configuration>
并且shared.xml
文件包含(仅限一行):
<add key="backhoe" value="Volvo BM 430 Hymas" />
使用以下代码段我加载XML并将其打印到控制台:
$config = [xml](get-content $path)
$text = $config.OuterXml
Write-Verbose "[LoadConfig] $text"
输出结果为:
VERBOSE: [LoadConfig] <?xml version="1.0" standalone="no"?>
<!DOCTYPE doc[
<!ENTITY shareddata SYSTEM "shared.xml">
]>
<configuration><appSettings>&shareddata;
<add key="motorcycle" value="Husqvarna TE610" />
<add key="car" value="Ford Mondeo" /></appSettings> </configuration>
我加载XML的方式不包括shared.xml
的内容,但它会解析DOCTYPE
标记,因为如果我还原到无效文件,它将会失败。
那么,我怎样才能让PowerShell完全包含XML片段,以便loadconfig
能够找到反铲的关键和价值呢?
我也试过
$Document = ( Select-Xml -Path myfile.xml -XPath / ).Node
但只要我在配置文件中有&shareddata;
,它就不会加载任何内容:
答案 0 :(得分:2)
我在C#中尝试过你的例子,它也没有用。这适用于C#,但是一旦您将shared.xml
更改为包含TEST VALUE
值(即只允许简单值,而不是xml),但它仍然无法在PS中运行:
<configuration >
<appSettings >
<test>&shareddata;</test>
<add key="motorcycle" value="Husqvarna TE610" />
<add key="car" value="Ford Mondeo" />
</appSettings>
</configuration>
使用此代码:
$doc = new-object System.Xml.XmlDocument
$doc.Load("D:\config.xml")
$doc.configuration.appSettings.add
key value
--- -----
motorcycle Husqvarna TE610
car Ford Mondeo
C#中的相同例子:
XmlDocument doc = new XmlDocument();
doc.Load("d:\\config.xml");
var x = doc["configuration"]["appSettings"]["test"];
Console.WriteLine(x.InnerText);
输出
TEST VALUE
似乎Powershell设置了doc.XmlResolver = null;
选项以防止安全相关问题,您可以在PS中看到$doc.XmlResolver
没有返回任何内容。我没有成功通过$doc.XmlResolver = new-object System.Xml.XmlUrlResolver
手动设置解析器。
立即强>,
您可以使用变量替换来实现效果:
<configuration >
<appSettings >
$shared_xml
<add key="motorcycle" value="Husqvarna TE610" />
<add key="car" value="Ford Mondeo" />
</appSettings>
</configuration>
$shared_xml = Get-Content 'D:\shared.xml'
[xml]$config = $ExecutionContext.InvokeCommand.ExpandString((gc $path))
如果在枚举块中枚举变量并加载适当的文件,则可以使这更容易。您可以事先不知道包含哪些文件。
立即强>,
除非对解析器问题有一些正常的解决方案,否则这一切看起来都很麻烦。但是,保持配置为XML的想法在很多层面上都是错误的。为什么在使用powershell config时使用XML:$config = @{ }
$config.motorcycle = 'Husqvarna TE610'
$config.car = 'Ford Mondeo'
$shared = @{}
$shared.backhoe = "Volvo BM 430 Hymas"
$config + $shared
输出
Name Value
---- -----
backhoe Volvo BM 430 Hymas
car Ford Mondeo
motorcycle Husqvarna TE610
你可以跟随&#34;包括&#34;模式如:
<强> config.ps1 强>
$config = @{
motorcycle = 'Husqvarna TE610'
car = 'Ford Mondeo'
}
. shared1.ps1
...
. sharedN.ps1
<强> sharedN.ps1 强>
$config.sharedN_cfg1 = 1
$config.sharedN_cfg2 = 2
如果您真的需要XML,那么之后可以使用ConvertTo-CliXML
和朋友。
如果你仍然想要追求你的方向,我建议你看一下XInclude(你需要第三方聚会来完成这项工作)。
答案 1 :(得分:1)
部分通知数据:https://www.red-gate.com/simple-talk/sysadmin/powershell/powershell-data-basics-xml/
在Powershell中,有多种方法可以加载XML文档,而且它们对外部实体的工作方式都不一样。
假设我们有一对简单的XML文档:
a.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE doc[
<!ENTITY includeSnippet SYSTEM "../path/to/b.xml">
]>
<stuff>
&includeSnippet;
<something>foo</something>
</stuff>
b.xml
<somethingElse>bar</somethingElse>
在Powershell中,我们通常会做$myVar = [xml](Get-Content a.xml)
这样的事情,我们希望事情有效 -
$myVar.stuff.somethingElse ?= 'bar' --> false (was not loaded from b.xml)
$myVar.stuff.something ?= 'foo' --> true (was in a.xml)
但是这并不像上面所述那样工作 - PowerShell的Get Content提供程序只是从磁盘读取文本 - [xml]强制转换(到XmlNode)将该文本解释为XML但它是&#39 ;太晚了&#34;加载其他资源。相反,我们以这种方式加载xml:
$myFile = resolve-path(".\a.xml")
$myDoc = new-object System.Xml.XmlDocument
$myDoc.load($myFile)
实体包含工作 - 有点。我可能误解了Entity包含在此处的意图,但b.xml
的内容并未直接替换到a.xml
文档中,而是显示在新的包装标记中:
$myVar.stuff.includeSnippet.somethingElse == 'bar'
$myVar.stuff.something == 'foo'
我也考虑过使用XInclude(考虑到微软主张它,似乎有理由认为PS会支持它吗?) - 基本上将!Entity
片换成参考:<xi:include href="b.xml" xmlns:xi="http://www.w3.org/2003/XInclude"/>
但是在这种情况下,上面的Powershell XML阅读技术并没有解决包含文件而我们什么也得不到。