XML编辑 - 值为null

时间:2017-09-13 06:43:18

标签: xml powershell

遇到一个带有空值表达式的问题,我似乎无法弄明白。

该脚本应该更改<ComputerName>文件中节点unattend.xml的值,但会返回错误。

XML文件:

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
  <settings pass="windowsPE">
    <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <SetupUILanguage>
      <UILanguage>en-US</UILanguage>
      </SetupUILanguage>
      <InputLocale>0c09:00000409</InputLocale>
      <SystemLocale>en-US</SystemLocale>
      <UILanguage>en-US</UILanguage>
      <UILanguageFallback>en-US</UILanguageFallback>
      <UserLocale>en-AU</UserLocale>
    </component>
    <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <DiskConfiguration>
        <Disk wcm:action="add">
          <CreatePartitions>
            <CreatePartition wcm:action="add">
              <Order>1</Order>
              <Type>Primary</Type>
              <Size>100</Size>
            </CreatePartition>
            <CreatePartition wcm:action="add">
              <Extend>true</Extend>
              <Order>2</Order>
              <Type>Primary</Type>
            </CreatePartition>
          </CreatePartitions>
          <ModifyPartitions>
            <ModifyPartition wcm:action="add">
              <Active>true</Active>
              <Format>NTFS</Format>
              <Label>System Reserved</Label>
              <Order>1</Order>
              <PartitionID>1</PartitionID>
              <TypeID>0x27</TypeID>
            </ModifyPartition>
            <ModifyPartition wcm:action="add">
              <Active>true</Active>
              <Format>NTFS</Format>
              <Label>OS</Label>
              <Letter>C</Letter>
              <Order>2</Order>
              <PartitionID>2</PartitionID>
            </ModifyPartition>
          </ModifyPartitions>
          <DiskID>0</DiskID>
          <WillWipeDisk>true</WillWipeDisk>
        </Disk>
      </DiskConfiguration>
      <ImageInstall>
      <OSImage>
      <InstallTo>
      <DiskID>0</DiskID>
      <PartitionID>2</PartitionID>
      </InstallTo>
      <InstallToAvailablePartition>false</InstallToAvailablePartition>
      </OSImage>
      </ImageInstall>
      <UserData>
        <AcceptEula>true</AcceptEula>
        <FullName>Testuser</FullName>
        <Organization></Organization>
      </UserData>
      <EnableFirewall>true</EnableFirewall>
    </component>
  </settings>
  <settings pass="offlineServicing">
    <component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <EnableLUA>false</EnableLUA>
    </component>
  </settings>
  <settings pass="generalize">
    <component name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <SkipRearm>1</SkipRearm>
    </component>
  </settings>
  <settings pass="specialize">
    <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <InputLocale>0c09:00000409</InputLocale>
      <SystemLocale>en-AU</SystemLocale>
      <UILanguage>en-AU</UILanguage>
      <UILanguageFallback>en-AU</UILanguageFallback>
      <UserLocale>en-AU</UserLocale>
    </component>
    <component name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <SkipAutoActivation>true</SkipAutoActivation>
    </component>
    <component name="Microsoft-Windows-SQMApi" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <CEIPEnabled>0</CEIPEnabled>
    </component>
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ComputerName>Test5-PC</ComputerName>
      <ProductKey>W3GGN-FT8W3-Y4M27-J84CP-Q3VJ9</ProductKey>
    </component>
  </settings>
  <settings pass="oobeSystem">
    <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <AutoLogon>
        <Password>
          <Value></Value>
          <PlainText>true</PlainText>
        </Password>
        <Enabled>true</Enabled>
        <Username>Testuser</Username>
      </AutoLogon>
      <OOBE>
        <HideEULAPage>true</HideEULAPage>
        <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
        <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
        <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
        <NetworkLocation>Work</NetworkLocation>
        <ProtectYourPC>1</ProtectYourPC>
        <SkipUserOOBE>true</SkipUserOOBE>
        <SkipMachineOOBE>true</SkipMachineOOBE>
      </OOBE>
      <UserAccounts>
        <LocalAccounts>
          <LocalAccount wcm:action="add">
            <Password>
              <Value></Value>
              <PlainText>true</PlainText>
            </Password>
            <Description></Description>
            <DisplayName>Testuser</DisplayName>
            <Group>Administrators</Group>
            <Name>Testuser</Name>
          </LocalAccount>
        </LocalAccounts>
      </UserAccounts>
      <RegisteredOrganization></RegisteredOrganization>
      <RegisteredOwner>Testuser</RegisteredOwner>
      <DisableAutoDaylightTimeSet>false</DisableAutoDaylightTimeSet>
      <TimeZone>AUS Eastern Standard Time</TimeZone>
      <VisualEffects>
        <SystemDefaultBackgroundColor>2</SystemDefaultBackgroundColor>
      </VisualEffects>
    </component>
    <component name="Microsoft-Windows-ehome-reg-inf" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="NonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <RestartEnabled>true</RestartEnabled>
    </component>
    <component name="Microsoft-Windows-ehome-reg-inf" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="NonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <RestartEnabled>true</RestartEnabled>
    </component>
  </settings>
</unattend>

PowerShell脚本:

$ComputerName = "Test2-PC"
#Set ComputerName in unattend file
$filePath = "C:\unattend.xml"
[xml]$xml = Get-Content $filePath.TrimStart('"').TrimEnd('"')
$node = $xml.unattend | foreach settings | foreach component | foreach computername
$content = Get-Content -Path $filePath.TrimStart('"').TrimEnd('"')
$content | foreach {
    $_.Replace($node.Trim(), $ComputerName)
} | Set-Content $filePath.TrimStart('"').TrimEnd('"')

错误是:

You cannot call a method on a null-valued expression.
At line:1 char:1
+ $node.Trim()
+ ~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

键入$node会将值显示为 Test5-PC ,因此会为其分配值。

运行:

if ($node -eq $null) {
    Write-Host "is null"
} else {
    Write-Host "is not null"
}

&#34>中的结果为空&#34;,所以它为空,但同时它有一个值?

.Trim()中删除$node.Trim()会使脚本正常运行,但XML值不会在XML文件中更新。

我在这里缺少什么?

3 个答案:

答案 0 :(得分:3)

您的XML文件中有11个<settings>个节点,但其中只有一个节点具有嵌套节点<ComputerName>。由于您的代码扩展了所有<settings>个节点,然后尝试展开嵌套的<component><ComputerName>节点,最终会得到一个包含11个元素的数组,其中10个为$null。您可以通过将$node连接到这样的输出循环来验证这一点:

PS C:\> $node | ForEach-Object { "-$_-" }
--
--
--
--
--
--
--
-Test5-PC-
--
--
--

不要乱用字符串操作,而是正确使用PowerShell中内置的XML解析器。使用SelectSingleNode()方法和XPath expression选择要修改的节点,更改其值,然后保存文件。

$ComputerName = "Test2-PC"
$filePath = "C:\unattend.xml"

[xml]$xml = Get-Content $filePath

$nsm = New-Object Xml.XmlNamespaceManager($xml.NameTable)
$nsm.AddNamespace("ns", $xml.DocumentElement.NamespaceURI)
$node = $xml.SelectSingleNode("//ns:ComputerName", $nsm)
$node.'#text' = $ComputerName

$xml.Save($filePath)

请注意,此处需要命名空间管理器,因为您的XML文件使用命名空间(xmlns=...)。另请注意,XPath表达式区分大小写,因此//ns:computername将不起作用。你必须使用//ns:ComputerName

答案 1 :(得分:0)

您可以使用基于RegEx的-Replace

执行此操作
$ComputerName = "Test2-PC"
$filePath = ".\unattend.xml"

(Get-Content $filePath) -Replace "^<ComputerName>(.*?)</ComputerName>$","<ComputerName>$ComputerName</ComputerName>" | Set-Content $filePath

答案 2 :(得分:0)

通过将$ node指定为字符串来解决:

$ComputerName = "Test2-PC"
#Set ComputerName in unattend file
$filePath = "C:\unattend.xml"
[xml]$xml = Get-Content $filePath.TrimStart('"').TrimEnd('"')
[string]$node = $xml.unattend | foreach settings | foreach component | foreach computername
$content = Get-Content -Path $filePath.TrimStart('"').TrimEnd('"')
$content | foreach {
    $_.Replace($node.Trim(), $ComputerName)
} | Set-Content $filePath.TrimStart('"').TrimEnd('"')