做过Windows运维或者自动化开发的人,多少都碰到过改配置文件的需求。比如某个服务的配置存在C:\Program Files\MyApp\MyApp.config里,测试环境和生产环境的端口、连接字符串不一样,手动改不仅慢还容易出错。PowerShell对XML的支持是原生级别的,它内置了[xml]类型加速器,加载一个XML文件后,节点和属性会自动映射成对象属性,直接用点号就能访问和修改。这篇文章就来完整讲一遍从读取、遍历、修改到保存的全流程,并给出可以直接复制使用的脚本实例。

一、用类型加速器加载和读取XML文件
PowerShell里读取XML最简单的方式就是把文件内容强制转换成[xml]类型。转换完成后,PowerShell底层调用的是.NET的XmlDocument对象,XML的层级结构会直接映射成对象的属性层级。假设有一个配置文件C:\Scripts\app.config,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="ServerName" value="192.168.0.1" />
<add key="Port" value="8080" />
<add key="LogLevel" value="Info" />
</appSettings>
<database>
<connectionString>Server=db01;Database=main;Integrated Security=True</connectionString>
<timeout>30</timeout>
</database>
</configuration>读取它只需要三行代码:
$xml = [xml](Get-Content -Path "C:\Scripts\app.config" -Encoding UTF8)
# 直接用点号访问节点
$xml.configuration.appSettings.add
# 读取某个具体配置项的值
$port = $xml.configuration.appSettings.add | Where-Object { $_.key -eq "Port" }
$port.value这里有个细节需要注意:appSettings下有多个同名节点add,PowerShell会把它自动展开成集合,所以可以直接用Where-Object筛选。如果节点名是唯一的,比如database下的timeout,那么$xml.configuration.database.timeout拿到的直接就是节点本身,要取文本值可以用它的#text属性或者InnerText方法。
另外要提醒的是编码问题。如果XML文件里有中文注释或者中文节点值,强烈建议在Get-Content时显式指定-Encoding UTF8,否则在部分系统默认编码为GBK的环境下可能出现乱码,甚至导致XML解析失败抛出异常。
二、修改节点值、属性并保存回文件
修改比读取还要直接,因为拿到的对象本身就是XmlDocument里的活节点,改了属性再调用Save方法即可。下面的脚本把端口从8080改成9090,把日志级别改成Debug,然后保存:
$path = "C:\Scripts\app.config"
$xml = [xml](Get-Content -Path $path -Encoding UTF8)
# 修改指定key的value属性
$portNode = $xml.configuration.appSettings.add | Where-Object { $_.key -eq "Port" }
$portNode.value = "9090"
$logNode = $xml.configuration.appSettings.add | Where-Object { $_.key -eq "LogLevel" }
$logNode.value = "Debug"
# 修改普通节点的文本内容
$xml.configuration.database.timeout.InnerText = "60"
# 保存回文件
$xml.Save($path)保存这一步有个常见的坑:Save方法默认会把整个文件重新序列化,中文内容的编码处理、缩进格式都可能发生变化。如果希望输出保持整齐的缩进,可以先设置XmlWriter的格式化参数:
$settings = New-Object System.Xml.XmlWriterSettings $settings.Indent = $true $settings.Encoding = [System.Text.Encoding]::UTF8 $writer = [System.Xml.XmlWriter]::Create($path, $settings) $xml.Save($writer) $writer.Close()
这样写出来的文件带有标准缩进,而且编码统一为UTF-8,避免文件被改得面目全非。对于要提交到版本库或者被其他程序严格校验的配置文件,这种保存方式更稳妥。
三、新增、删除节点和XPath高级查找
除了改值,脚本的常见需求还包括动态增删配置项。新增节点要用CreateElement方法创建,再用AppendChild挂到父节点上;删除则用RemoveChild。示例代码如下:
$path = "C:\Scripts\app.config"
$xml = [xml](Get-Content -Path $path -Encoding UTF8)
# 新增一个配置项
$newAdd = $xml.CreateElement("add")
$newAdd.SetAttribute("key", "CacheSize")
$newAdd.SetAttribute("value", "512")
$xml.configuration.appSettings.AppendChild($newAdd) | Out-Null
# 删除一个配置项
$toDelete = $xml.configuration.appSettings.add | Where-Object { $_.key -eq "LogLevel" }
$xml.configuration.appSettings.RemoveChild($toDelete) | Out-Null
$xml.Save($path)当配置文件结构比较复杂时,逐层点号访问会很啰嗦,这时候XPath就派上用场了。SelectNodes和SelectSingleNode方法支持完整的XPath语法,例如查找所有value属性以192开头的节点:
$nodes = $xml.SelectNodes("//add[starts-with(@value,'192')]")
foreach ($node in $nodes) {
Write-Host "找到节点: $($node.key) = $($node.value)"
}
# 查找database节点下的connectionString
$conn = $xml.SelectSingleNode("//connectionString")
$conn.InnerText如果XML文件带有命名空间声明(比如很多软件的配置文件根节点上有xmlns属性),直接用SelectNodes("//add")会查不到任何结果,这是新手最容易踩的坑。解决办法是构造一个XmlNamespaceManager,把命名空间注册进去再查询:
$ns = New-Object System.Xml.XmlNamespaceManager($xml.NameTable)
$ns.AddNamespace("cfg", "http://schemas.ippipp.com/config")
$nodes = $xml.SelectNodes("//cfg:add", $ns)掌握了这几个核心操作后,读取、修改、增删、查找、保存就形成了一个完整闭环。把上面这些代码片段封装成带参数的函数,配合环境变量切换不同机器的路径,比如测试机走C:\Scripts\app.config、生产机走D:\App\config\app.config,就能实现一条命令完成配置下发和批量修改,比手工编辑配置文件省事得多,也避免了手滑改错行的风险。
PowerShell XMLPowerShell脚本XML配置文件修改修改时间:2026-09-04 03:18:38