我在使用 v2 中未正确 运行 的 PowerShell 代码时遇到问题

I am having trouble with PowerShell code that doesn't run properly in v2

我们正尝试在任务序列中更新我们的 BIOS,我有一个由 Lenovo 提供的脚本,它在 Windows10 和 PowerShell v5 中运行良好。但是,它无法在 Windows 7 中使用 PowerShell v2 正常工作。我们无法在 Windows 7 台机器上升级到 v5。

脚本读取我从 SCCM 导出的 XML 文件并匹配适当的 BIOS 包,下载并运行它。

所以脚本看起来像:

[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

失败于:

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

我试了一天,但碰壁了。

我得到的是以下错误:

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

错误信息其实很清楚。 $Packages.SelectNodes() returns 一个 XPathNodeList 集合。在随后的语句中,当集合没有这样的方法时,您试图对该集合调用方法 SelectNodes()。这是导致错误的原因。

代码在 PowerShell v5 中工作的原因是 Microsoft 在 PowerShell v3 中引入了一个名为 "member enumeration" 的新功能,该功能自动将对集合中不存在的成员(属性和方法)的调用传递给 集合的元素。在您的情况下,由于集合 $Package 没有方法 SelectNodes(),调用 $Package.SelectNodes() 将在 PowerShell v2 和更早版本中引发错误,并在 [ PowerShell v3 和更新版本中的 $package 的 =42=] 元素 。

有多种方法可以解决这个问题,例如

  • Update PowerShell 到 Windows 7 台机器上的 v3 或更新版本。是的,我看到你说你不能升级 Windows 7 台机器,但这实际上是首选解决方案。

  • $Packages.SelectNodes()的结果限制为一项:

    $Package = $Packages.SelectNodes($xpathqry, $ns) |
               Select-Object -First 1
    
  • 在下一个语句中仅使用 $Packages 的第一个元素:

    $PackageID = $Package[0].SelectNodes('def:S[contains(@N,"PackageID")]',$ns)
    
  • $Package的每个元素调用SelectNodes():

    $PackageID = $Package | ForEach-Obejct {
        $_.SelectNodes('def:S[contains(@N,"PackageID")]',$ns)
    }