Reputation: 147
Running into an issue with a null valued expression which I can't seem to figure out.
The script is supposed to change the value of the node <ComputerName>
in an unattend.xml
file, but returns an error.
XML file:
<?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 script:
$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('"')
The error is:
You cannot call a method on a null-valued expression. At line:1 char:1 + $node.Trim() + ~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
Typing $node
shows the value as Test5-PC so it is assigned a value.
Running:
if ($node -eq $null) {
Write-Host "is null"
} else {
Write-Host "is not null"
}
Results in "is null", so it's null but at the same time it has a value?
Removing the .Trim()
from $node.Trim()
makes the script run without errors, but the XML value isn't updated in the XML file.
What am I missing here?
Upvotes: 1
Views: 1668
Reputation: 200453
You have 11 <settings>
nodes in your XML file, but only one of them has a nested node <ComputerName>
. Since your code expands all <settings>
nodes, and then tries to expand nested <component>
and <ComputerName>
nodes you end up with an array with 11 elements, 10 of which are $null
. You can verify that by piping $node
into an output loop like this:
PS C:\> $node | ForEach-Object { "-$_-" } -- -- -- -- -- -- -- -Test5-PC- -- -- --
Instead of messing around with string manipulations make proper use of the XML parser that's built into PowerShell. Use the SelectSingleNode()
method with an XPath expression to select the node you want to modify, change its value, then save the file.
$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)
Note that you need a namespace manager here, because your XML file uses namespaces (xmlns=...
). Note also, that XPath expressions are case-sensitive, so //ns:computername
will NOT work. You MUST use //ns:ComputerName
.
Upvotes: 4
Reputation: 147
Solved by specifying $node as a string:
$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('"')
Upvotes: 0
Reputation: 23395
You could do this with a RegEx-based -Replace
:
$ComputerName = "Test2-PC"
$filePath = ".\unattend.xml"
(Get-Content $filePath) -Replace "^<ComputerName>(.*?)</ComputerName>$","<ComputerName>$ComputerName</ComputerName>" | Set-Content $filePath
Upvotes: 0