使用PowerShell进行XML更新

时间:2014-06-14 09:37:44

标签: xml powershell

我有以下示例XML:

<?xml version="1.0" encoding="utf-8"?>        
<SQLUsers>
      <SQLFile>
        <FileVersion>260</FileVersion>
        <FileDate>06.14.2014</FileDate>
      </SQLFile>
      <SQLAccount>
        <user001>
          <AccountName>user001</AccountName>
          <SQLSysAdmin>Adm_user001</SQLSysAdmin>
          <SQLSysAdminPassword>P@ssw0rd</SQLSysAdminPassword>
          <SQLReadOnlyUser>user004</SQLReadOnlyUser>
          <SQLReadOnlyUserPassword>P@ssw0rd</SQLReadOnlyUserPassword>
          <CreationDate>06.13.2014</CreationDate>
          <InstanceID>InstanceID</InstanceID>
        </user001>
      </SQLAccount>
      <SQLAccount>
        <user002>
          <AccountName>user002</AccountName>
          <SQLSysAdmin>Adm_user001</SQLSysAdmin>
          <SQLSysAdminPassword>P@ssw0rd</SQLSysAdminPassword>
          <SQLReadOnlyUser>user005</SQLReadOnlyUser>
          <SQLReadOnlyUserPassword>P@ssw0rd</SQLReadOnlyUserPassword>
          <CreationDate>06.13.2014</CreationDate>
          <InstanceID>InstanceID</InstanceID>
         </user002>
      </SQLAccount>
    </SQLUsers>

我应该更新这个XML文件,在&#34; UserXXX&#34;下添加一个新元素。节点。像这样的东西:

<user002>
    <AccountName>user002</AccountName>
    <SQLSysAdmin>Adm_user001</SQLSysAdmin>
    <SQLSysAdminPassword>P@ssw0rd</SQLSysAdminPassword>
    <SQLReadOnlyUser>user005</SQLReadOnlyUser>
    <SQLReadOnlyUserPassword>P@ssw0rd</SQLReadOnlyUserPassword>
    <CreationDate>06.13.2014</CreationDate>
    <InstanceID>InstanceID</InstanceID>
    <DatabaseName>database1</DatabaseName>
    <DatabaseName>database2</DatabaseName>
 </user002>

我有以下powershell脚本,它接受用户名,数据库名称作为参数:

param($accountName,$database)

$ErrorActionPreference = "Stop"

[string]$date = Get-Date -format "MM.dd.yyyy"
$Instanceid = "Testid"

[xml] $xml = gc "C:\LogFiles\$Instanceid-SQLUsers.xml"

$child = $xml.CreateElement("DatabaseName")
$child.SetAttribute('DatabaseName','$database')
$xml.SQLUsers.SQLAccount.$accountName.AppendChild($child)

$xml.save("C:\LogFiles\$Instanceid-SQLUsers_update.xml")

但是,我收到以下错误:

You cannot call a method on a null-valued expression.
At D:\Scripts\AttachUserToDB_XML3.ps1:12 char:1
+ $xml.SQLUsers.SQLAccount.$accountName.AppendChild($child)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvokeMethodOnNull

我也尝试使用innerXML,但是,没有用。 任何帮助将不胜感激!

非常感谢!

2 个答案:

答案 0 :(得分:0)

由于您的xml结构具有多个sqlaccount标记,因此您将无法导航到确切的用户帐户元素。

将xml结构更改为具有单个sqlaccounts并列出所有用户或使用xpath查询检索确切的用户元素并在其上调用appendChild。

答案 1 :(得分:0)

您的xml设计糟糕。节点应该有&#34;标准&#34;名称,以便您可以针对架构验证xml。你有一个user0002 - 节点,它有点无用,因为这个值已在AccountName - 元素中指定。这样:

<SQLAccount>
  <user002>
    <AccountName>user002</AccountName>
  </use002>
</SQLAccount>

应该简化为类似的东西(因为AccountName元素已经包含用户名/唯一值):

<SQLAccount>
  <AccountName>user002</AccountName>
</SQLAccount>

但是要回答你的问题,我想指出一些事情:

  1. 问题在于,当您运行$xml.SQLUsers.SQLAccount.$accountName时,会得到两个项目的数组:空对象和xmlelement,因此您需要指定$xml.SQLUsers.SQLAccount.$accountName[1]来获取节点。如果帐户不存在,您仍然会得到两个项目的数组:两个空对象。所以请记住验证是否找到了该节点。防爆。检查AccountName - 属性是否存在。

  2. 您也在创建错误的元素。您的示例不包含databasename - 属性,但您的脚本会尝试创建一个。

  3. 您的脚本从一个文件读取并保存到另一个文件。因此,为了能够添加您样本中显示的多个数据库,您的脚本需要在一次调用中支持多个数据库名称。

  4. 你可以试试这个:

    function UpdateXML {
        param($accountName,[string[]]$database)
    
        $Instanceid = "Testid"
    
        [xml] $xml = gc "C:\LogFiles\$Instanceid-SQLUsers.xml"
    
        #case sensitive! easy to read
        #$accountnode = $xml.SelectSingleNode("//AccountName[. = '$accountName']").parentnode
    
        #case insensitive
        $accountnode = $xml.SQLUsers.SQLAccount.$accountName[1]
    
        #If a node for the account was found
        if($accountnode.AccountName) {
            foreach ($dbname in $database) {
                $element = $xml.CreateElement("DatabaseName")
                $element.InnerText = $dbname
                $accountnode.AppendChild($element) | Out-Null
            }
    
            $xml.save("C:\LogFiles\$Instanceid-SQLUsers_update.xml")
        } else {
            Write-Error "Account '$accountName' doesn't exist!"
        }
    }
    
    UpdateXML -accountName "user002" -database "database1", "database2"