0

We are trying to update our BIOS within a task sequence and I have a script provided by Lenovo which is working fine in Windows 10 and PowerShell v5. However, it is not working properly in Windows 7 with PowerShell v2. We can't upgrade to v5 on the Windows 7 machines.

The script reads an XML file I have exported from the SCCM and matches the appropriate BIOS package, downloads it and runs it.

So the script looks like:

[xml]$Packages = Get-Content BIOSPackages.xml

# Environment variable call for task sequence only
$tsenv = New-Object -ComObject Microsoft.SMS.TSEnvironment

$BIOS = (Get-WmiObject -Namespace root\cimv2 -Class Win32_BIOS).SMBIOSBIOSVersion.Substring(0,4)

$ns = New-Object Xml.XmlNamespaceManager $Packages.NameTable
$ns.AddNamespace("def", "http://schemas.microsoft.com/powershell/2004/04")

$Xpathqry = "/def:Objs/def:Obj//def:MS[contains(.,`"$BIOS`")]"

$Package = ($Packages.SelectNodes($xpathqry,$ns))
$PackageID = $Package.SelectNodes('def:S[contains(@N,"PackageID")]',$ns)
$tsenv.Value('OSDDownloadDownloadPackages') = $PackageID.InnerXML

and it fails on:

$PackageID = $Package.SelectNodes('def:S[contains(@N,"PackageID")]',$ns)

I have tried to fudge with it for a day and I am just hitting a wall.

What I get is the following error:

Method invocation failed because [System.Xml.XPathNodeList] doesn't contain a
method named 'SelectNodes'.
At C:\_SMSTaskSequence\Packages\NC1002CB\Get-BIOSPackages.ps1:17 char:38
+ $PackageID = $Package.SelectNodes <<<< ('def:S[contains(@N,"PackageID")]',$ns)
    + CategoryInfo          : InvalidOperation: (SelectNodes:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328

1 Answers1

1

The error message is actually pretty clear. $Packages.SelectNodes() returns an XPathNodeList collection. In the subsequent statement you're trying to call a method SelectNodes() on that collection when the collection doesn't have such a method. Which is what's causing the error.

The reason why the code works in PowerShell v5 is that Microsoft introduced a new feature called "member enumeration" with PowerShell v3 that automagically passes calls to non-existing members (properties and methods) of a collection to the elements of the collection. In your case, since the collection $Package doesn't have a method SelectNodes(), calling $Package.SelectNodes() will throw an error in PowerShell v2 and older, and call SelectNodes() on the elements of $package in PowerShell v3 and newer.

There are various ways to address the issue, e.g.

  • Update PowerShell to v3 or newer on the Windows 7 machines. Yes, I saw that you said that you can't upgrade the Windows 7 machines, but this is in fact the preferred solution.

  • Restrict the result of $Packages.SelectNodes() to one item:

    $Package = $Packages.SelectNodes($xpathqry, $ns) |
               Select-Object -First 1
    
  • Use onle the first element of $Packages in the next statment:

    $PackageID = $Package[0].SelectNodes('def:S[contains(@N,"PackageID")]',$ns)
    
  • Call SelectNodes() for each element of $Package:

    $PackageID = $Package | ForEach-Obejct {
        $_.SelectNodes('def:S[contains(@N,"PackageID")]',$ns)
    }
    
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328