I'm writing a PowerShell script to manipulate some Windows Installer XML (WiX). I'm using the new XML APIs in .NET 3.5 to do this, as I find it an easier API to work with than the DOM. The following script fragment is flatly refusing to work:
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq") | Out-Null
# Basic idea: Iterate through en.wxl's l10ns, get string for each l10n, search all wxs files for that value.
pushd "C:\temp\installer_l10n"
$wxlFileName = "${pwd}\en.wxl"
$wxl = [System.Xml.Linq.XDocument]::Load($wxlFileName)
$strings = $wxl.Descendants("String")
$strings
$strings | foreach {
$_
}
popd
The script should output each <String> tag on a separate line. I'm going to get it to do something more interesting once this bug's been solved ;-)
The XML document is a standard WiX localisation file:
<?xml version="1.0" encoding="utf-8" ?>
<WixLocalization Culture="en-US" xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="0">Advertising published resource</String>
<String Id="1">Allocating registry space</String>
...
</WixLocalization>
$strings is not $null (I've explicitly tested it), and if I write-host $wxl, I can see that the document has been loaded. Piping $strings into Get-Member returns an error stating that "No object has been specified to get-member" and write-host $strings does nothing. I've also tried $wxl.Descendants("WixLocalization") with the same results. Things like $wxl.Root and $wxl.Nodes work as expected. Debugging with PowerShell ISE, I see that $strings has been set to IEnumerator, rather than the expected IEnumerable<XElement>. Testing the IEnumerator with a single MoveNext and then a Current indicates that "Current = ", presumably $null.
The weird thing is that the same technique worked in a previous script. The exact same code, but with different variable names and string literals. And having just tried debugging that script too (to verify the behaviour), it seems it's now also displaying the same behaviour.