使用PowerShell

时间:2018-07-17 15:35:29

标签: xml powershell

我正在从一些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之间的分配可能做错了什么?

2 个答案:

答案 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>