在Windows自动化运维和部署脚本里,XML配置文件随处可见,比如应用程序的app.config、web.config或者服务自身的设定文件。PowerShell作为系统自带且功能完整的脚本环境,提供了一套非常直接的XML处理机制,不需要借助第三方库就能完成读取、查找、修改和保存。

一、用PowerShell加载XML文件
PowerShell有一个特殊的类型加速器叫[xml],它可以把XML格式的字符串或者文件内容直接转换成一个可遍历的对象树。相比用Get-Content把文件读成纯文本再去正则替换,这种方式能保留节点结构、属性和注释,也不容易因为格式微调而弄坏文件。
最基础的加载方式是先读取文件内容,再转型为xml对象。下面的例子展示了如何从磁盘读取一个配置文件并验证是否加载成功:
$path = "C:tempapp.config"
$xmlContent = Get-Content -Path $path -Raw
$cfg = [xml]$xmlContent
if ($cfg -ne $null) {
Write-Host "XML加载成功,根节点为:$($cfg.DocumentElement.Name)"
}
另一种更简洁的写法是直接把路径丢给类型转换,PowerShell会尝试把文件内容转为XML对象。不过需要注意,如果文件含有BOM或者编码异常,建议显式指定编码,例如使用Get-Content的-Encoding参数。加载后,每一个XML元素都变成了对象的属性,属性值则通过对象的Attributes集合或直接使用节点属性名访问。
这种对象化处理的优势在于,你可以像操作普通PowerShell对象一样去点选子节点,而不用关心尖括号和换行。同时,如果XML本身不合法,转型时会直接抛出异常,这比事后才发现配置损坏要好得多。
二、读取XML中的配置节点
读取配置主要有两种思路:一是利用对象属性链直接访问,适合结构固定且层级浅的文件;二是使用Select-Xml配合XPath,适合结构复杂或者需要按条件筛选的场景。
假设有如下简单的配置文件:
<configuration>
<appSettings>
<add key="LogPath" value="C:logs" />
<add key="MaxCount" value="10" />
</appSettings>
</configuration>
用属性链读取的方式非常直观:
$logPath = $cfg.configuration.appSettings.add | Where-Object { $_.key -eq "LogPath" }
Write-Host "当前日志路径:$($logPath.value)"
如果节点较多或者路径较深,XPath会更稳定。Select-Xml返回的是匹配节点包装对象,需要用.Node拿到真实节点:
$node = Select-Xml -Xml $cfg -XPath "//add[@key='MaxCount']"
if ($node -ne $null) {
Write-Host "最大数量配置为:$($node.Node.value)"
}
使用XPath时要注意命名空间问题。很多.NET配置文件带有xmlns命名空间声明,此时直接用//add会匹配不到。需要先注册命名空间前缀,再在路径里使用,例如将默认命名空间映射为ns,写成//ns:add。这一步是读取官方配置时最容易踩的坑。
三、修改XML节点与属性
修改操作和读取一脉相承:先拿到目标节点,再对其属性或文本赋值,最后保存。继续上面的例子,把日志路径改成D盘:
$target = $cfg.configuration.appSettings.add | Where-Object { $_.key -eq "LogPath" }
if ($target -ne $null) {
$target.value = "D:logs"
Write-Host "已修改日志路径为:$($target.value)"
}
</p>
<p>如果需要新增一个配置项,可以用CreateElement构造节点,设好属性和文本后再AppendChild到对应父节点。下面演示如何新增一个超时设置:</p>
<pre class=brush:powershell;toolbar:false>
$newNode = $cfg.CreateElement("add")
$newNode.SetAttribute("key", "Timeout")
$newNode.SetAttribute("value", "30")
$cfg.configuration.appSettings.AppendChild($newNode) | Out-Null
Write-Host "已新增Timeout节点"
修改时务必确认父节点存在,否则会报空引用错误。另外,直接对节点文本赋值要用#text或InnerText,而不是把整个节点替换成字符串,否则会破坏子结构。对于带命名空间的文档,创建节点也要带上命名空间URI,否则保存后文件可能不被原程序识别。
四、保存修改并保留格式
很多人用$cfg.Save()之后发现文件变成了一行,缩进和注释全没了。这是因为XmlDocument默认保存为紧凑格式。要保留较好可读性,可以借助XmlTextWriter设置缩进:
$savePath = "C:tempapp_new.config" $settings = New-Object System.Xml.XmlWriterSettings $settings.Indent = $true $settings.IndentChars = " " $writer = [System.Xml.XmlWriter]::Create($savePath, $settings) $cfg.Save($writer) $writer.Close() Write-Host "配置已保存至:$savePath"
如果原文件含有声明行比如<?xml version="1.0" encoding="utf-8"?>,上述方式也能保留。保存后建议再用[xml]加载一次新文件,确认能正常解析,避免写出非法XML导致业务中断。
还有一种场景是希望原地覆盖原文件。只需把$savePath设为原路径即可,但务必先备份。因为一旦保存逻辑有错,原配置可能直接损坏,而自动化脚本往往没有二次确认。
五、避坑与最佳实践
第一,不要用Get-Content读成文本再-replace去改XML,这种方式遇到自闭合标签、属性顺序变化就会失效,还可能误伤注释里的相似字符串。第二,处理带命名空间的配置文件时,提前打印$cfg.NameTable或者查阅原文件声明,规划好XPath前缀。
第三,在脚本开头用try-catch包住加载和保存过程,一旦XML格式错误就抛出清晰信息并退出,而不是让脚本继续跑下去写坏文件。第四,如果配置被其他进程占用,Save会失败,可以先复制副本修改,再用计划任务或重启时替换。
| 方式 | 优点 | 风险 |
|---|---|---|
| 对象属性链 | 写法简单直观 | 结构变动易报错 |
| Select-Xml | 灵活、可条件筛选 | 命名空间处理麻烦 |
| 文本替换 | 不需要解析 | 极易破坏格式 |
掌握上述读取、修改、保存与避坑方法后,你完全可以在PowerShell里写出稳定的配置维护脚本,支撑日常部署和批量机器管理。
PowerShellXML_config配置文件修改时间:2026-08-07 04:48:33