我正在从一些XML数据中检索文本字符串,然后尝试用其他内容替换该字符串。我正在使用的代码是:
$newstring = "mystring"
$bar = Get-Gpo -Name "My GPO"
$gpoid = $bar.Id.ToString()
$drivesxml = New-Object XML
$drivesxml.Load("\\mydomain.co.uk\sysvol\mydomain.co.uk\Policies\{gpoid}\User\Preferences\Drives\drives.xml")
$oldpath = $drivesxml.Drives.Drive.Properties.Path[0]
$oldlabel = $drivesxml.Drives.Drive.Properties.Label[0]
#1
[string]$newtemppath = $oldpath -replace "Oldstring$", "$newstring"
[string]$newtemplabel = $oldlabel -replace "^Oldstring", "$newstring"
#2
$drivesxml.Drives.Drive.Properties.Path[0] = $newtemppath
$drivesxml.Drives.Drive.Properties.Label[0] = $newtemplabel
#3
$drivesxml.Save("\\mydomain.co.uk\sysvol\mydomain.co.uk\Policies\{gpoid}\User\Preferences\Drives\drives.xml")
它从sysvol fine检索XML,如果我查询$oldpath
和$oldlabel
,则在第1点,它们包含XML期望的文本。
在#2,如果我查询$newtemppath
和$newtemplabel
,则按预期返回字符串,并修改了文本,因此“ Oldstring”的实例已由“ mystring”替换。
在#3处,如果我查询$drivesxml.Drives.Drive.Properties.Path[0]
和$drivesxml.Drives.Drive.Properties.Label[0]
,我希望它们返回与$newtemppath
和$newtemplabel
变量相同的内容,但是它们继续返回其原始值。
保存XML后,如果再次查询它,内容没有改变。
谁能看到我在#2和#3之间的分配可能做错了什么?
答案 0 :(得分:3)
Powershell支持用于导航XML文件的“点路径”语法,这对于从XML文件读取数据非常方便-大概是为了方便使用XML输入或使用XML配置文件。
该语法的缺点是它tries to return strings and arrays whenever it can。在您的情况下,connect
是一个字符串,不再是XML节点,因此,您分配给该值的任何内容都会丢失。
诀窍是保留XML节点。实现这一目标的最简单方法是使用use XPath for navigation(无论如何,它比点路径语法更强大):
$drivesxml.Drives.Drive.Properties.Path[0]
您还可以使用$path = $drivesxml.SelectSingleNode('/Drives/Drive/Properties/Path')
$path.InnerText = $path.InnerText -replace "Oldstring$",$newstring
# ...
$drivesxml.Save($xmlPath)
和.SelectNodes
循环进行多项更改。
不相关的注释是,Powershell将在双引号字符串中进行变量插值。这可能会与正则表达式冲突,其中foreach
具有其自身的含义。在上述情况下,没有任何歧义,但是最好养成对正则表达式使用单引号字符串的习惯:
$
关于XML名称空间的注释:如果XML文件使用名称空间(在元素上用$path.InnerText = $path.InnerText -replace 'Oldstring$',$newstring
声明),则需要在使用XPath之前使这些名称空间已知:Using PowerShell, how do I add multiple namespaces (one of which is the default namespace)?
答案 1 :(得分:1)
为完整起见,一旦实现了Tomalak的答案,工作代码就可以了。
$newstring = "mystring"
$bar = Get-Gpo -Name "My GPO"
$gpoid = $bar.Id.ToString()
$drivesxml = New-Object XML
$drivesxml.Load("\\mydomain.co.uk\sysvol\mydomain.co.uk\Policies\{gpoid}\User\Preferences\Drives\drives.xml")
$path=$drivesxml.SelectNodes('/Drives/Drive/Properties')
$path[0].path = $path[0].path -replace 'Oldstring$',$newstring
$path[0].label = $path[0].label -replace '^Oldstring',$newstring
$drivesxml.Save("\\mydomain.co.uk\sysvol\mydomain.co.uk\Policies\{gpoid}\User\Preferences\Drives\drives.xml")
以及正在查询以供参考的XML:
<?xml version="1.0" encoding="utf-8"?>
<Drives clsid="{8FDDCC1A-0C3C-43cd-A6B4-71A6DF30DA8C}">
<Drive clsid="{935D1B74-9CB8-4e3c-9914-7DD559C7A417}" name="S:" status="S:" image="0" changed="2010-07-15 15:01:51" uid="{ACCCC2A9-809B-4CE3-9F2D-F4B4643B02F5}" bypassErrors="1">
<Properties action="C" thisDrive="SHOW" allDrives="SHOW" userName="" path="\\mydomain.co.uk\GroupData$\Companies\mystring" label="mystring - Shared drive" persistent="1" useLetter="1" letter="S" />
</Drive>
<Drive clsid="{935D1B74-9CB8-4e3c-9914-7DD559B8A417}" name="U:" status="U:" image="0" changed="2010-07-15 15:04:20" uid="{FA3F7F3C-A1A0-4618-89E1-88191C780A67}" bypassErrors="1">
<Properties action="C" thisDrive="SHOW" allDrives="NOCHANGE" userName="" path="\\mydomain.co.uk\data\users\%username%" label="Personal drive (My documents)" persistent="1" useLetter="1" letter="U" />
</Drive>
</Drives>