如何在 PowerShell 中正确获取系统模型并将其设置为参数?

How to properly get System Model in PowerShell and set it as a parameter?

提问人:Arthur Durand 提问时间:2/21/2023 最后编辑:mklement0Arthur Durand 更新时间:3/6/2023 访问量:432

问:

我需要使用 PowerShell 正确获取电脑的系统型号,并将型号用作参数,以便可以运行特定于型号的任务。

我的代码有点复杂,因为某些方法返回的值如“不可用”、“由 O.E.M. 填充”或“系统产品制造商”——在这些情况下,我不希望$Model参数为“不可用”、“由 O.E.M. 填充”或“系统产品制造商”。

我有以下内容,但它不能按预期工作

    $BaseBoardManufacturer = Get-WmiObject Win32_BaseBoard | Select Manufacturer
if ((-not ([string]::IsNullOrWhiteSpace($BaseBoardManufacturer))) -and ($BaseBoardManufacturer.Manufacturer -ne 'Not Available') -or ($BaseBoardManufacturer.Manufacturer -ne 'System manufacturer'))
    {
        [String]$Manufacturer = ($BaseBoardManufacturer.Manufacturer).ToString()
    }
    
    $ProductManufacturer = Get-WmiObject -Class:Win32_ComputerSystemProduct | select Vendor
    if ((-not ([string]::IsNullOrWhiteSpace($ProductManufacturer))) -and ($ProductManufacturer.Vendor -ne 'Not Available') -or ($ProductManufacturer.Vendor -ne 'System manufacturer') -or ($ProductManufacturer.Vendor -ne 'To be filled by O.E.M.'))
    {
        [String]$Manufacturer = ($ProductManufacturer.Vendor).ToString()
    }
    
    $SystemManufacturer = Get-WmiObject -Class:Win32_ComputerSystem | select Manufacturer
    if ((-not ([string]::IsNullOrWhiteSpace($SystemManufacturer))) -and ($SystemManufacturer.Manufacturer -ne 'Not Available') -or ($SystemManufacturer.Manufacturer -ne 'System manufacturer') -or ($SystemManufacturer.Manufacturer -ne 'To be filled by O.E.M.'))
    {
        [String]$Manufacturer = ($SystemManufacturer.Manufacturer).ToString()
    }
    
    $BaseBoardProduct = Get-WmiObject Win32_BaseBoard | Select Product
    if ((-not ([string]::IsNullOrWhiteSpace($BaseBoardProduct))) -and ($BaseBoardProduct.Product -ne 'Not Available'))
    {
        [String]$Model = ($BaseBoardProduct.Product).ToString()
    }
    
    $ProductVersion = Get-WmiObject -Class:Win32_ComputerSystemProduct | select Version
    if ((!($ProductVersion.Version -ne 'System Version')) -xor (!($ProductVersion.Version -ne 'To be filled by O.E.M.')) -and (-not ([string]::IsNullOrWhiteSpace($ProductVersion))))
    {
        [String]$Model = ($ProductVersion.Version).ToString()
    }
    
    $SystemModel = Get-WmiObject -Class:Win32_ComputerSystem | select Model
    if ((-not ([string]::IsNullOrWhiteSpace($SystemModel))) -and ($SystemModel.Model -ne 'System Product Name') -or ($SystemModel.Model -ne 'To be filled by O.E.M.'))
    {
        [String]$Model = ($SystemModel.Model).ToString()
    }
    
    $SystemManufacturer = Get-WmiObject -Class:Win32_ComputerSystem | select Manufacturer
    if ((-not ([string]::IsNullOrWhiteSpace($SystemManufacturer))) -and ($SystemManufacturer.Manufacturer -ne 'Not Available') -or ($SystemManufacturer.Manufacturer -ne 'System manufacturer') -or ($SystemManufacturer.Manufacturer -ne 'To be filled by O.E.M.'))
    {
        [String]$Manufacturer = ($SystemManufacturer.Manufacturer).ToString()
    }
    
    if ($Manufacturer -like '*Lenovo*')
    {
        $ProductVersion = Get-WmiObject -Class:Win32_ComputerSystemProduct | select Version
    [String]$Model = ($ProductVersion.Version).ToString()
    }

例如,我想要

    ((!($ProductVersion.Version -ne 'System Version')) -or (!($ProductVersion.Version -ne 'To be filled by O.E.M.')) -and (-not ([string]::IsNullOrWhiteSpace($ProductVersion))))

当 ProductVersion 返回“To be filled by O.E.M.”或“System Version”时返回 false,但它返回 true!

我试过了

    ((!($ProductVersion.Version -ne 'System Version')) -xor (!($ProductVersion.Version -ne 'To be filled by O.E.M.')) -and (-not ([string]::IsNullOrWhiteSpace($ProductVersion))))

    if ((-not ($SystemModel.Model -eq 'System Product Name')) -or (-not ($SystemModel.Model -eq 'To be filled by O.E.M.')) -and (-not ([string]::IsNullOrWhiteSpace($SystemModel))))

但是我将“系统版本”设置为参数而不是型号,换句话说,当参数应该返回false时,该参数返回true

PowerShell 条件语句布尔 逻辑

评论

0赞 mklement0 2/21/2023
顺便说一句:CIM cmdlet(例如)取代了 PowerShell v3(2012 年 9 月发布)中的 WMI cmdlet(例如 )。因此,应避免使用 WMI cmdlet,尤其是因为 PowerShell (Core) v6+(所有未来的努力都将用于此)甚至不再具有它们。但请注意,WMI 仍然是 CIM cmdlet 的基础。有关详细信息,请参阅此答案Get-CimInstanceGet-WmiObject
0赞 mklement0 2/21/2023
请允许我给你一个提示,以备将来的问题:你的问题中的代码比说明问题所需的代码多,这会分散注意力,使诊断问题变得更加困难。问题的最佳表现形式是以最小可重复的例子的形式。

答:

1赞 mklement0 2/21/2023 #1
  • 首先,我建议简化您的属性检索命令

    • 使用 Select-Object 从调用发出的对象中提取单个属性Get-WmiObject

    • 也许令人惊讶的是,类似(缩写:)的东西不会返回输入对象属性的,它为每个输入对象返回一个新对象,该对象是类型并且本身具有属性... | Select Product... | Select-Object -Property Product.Product[pscustomobject]Product

    • 若要仅提取属性,请使用 Select-Object-ExpandProperty 参数,而不是 (位置隐含) 参数;
      例如 ... |Select-Object -ExpandProperty 产品
      -Property

    • 有关更多信息和更有效的替代方案,请参阅这篇文章

  • 其次,布尔逻辑存在问题,将在下一节中解释。

但是,我建议简化您的条件如下:

# Sample input objects.
@(
  $null
  [pscustomobject] @{ Version = $null }
  [pscustomobject] @{ Version = '' }
  [pscustomobject] @{ Version = 'System Version' }
  [pscustomobject] @{ Version = 'To be filled by O.E.M.' }
  [pscustomobject] @{ Version = '1' }

) | ForEach-Object {
  
  $ProductVersion = $_

  # Output $true only if $ProductVersion is an object that has 
  # a .Version property whose value is neither $null, the empty string
  # nor 'System Version' nor 'To be filled by O.E.M.'
  $ProductVersion.Version -notlike '' -and 
    $ProductVersion.Version -notin 'System Version', 'To be filled by O.E.M.'

}
  • $ProductVersion.Version -notlike ''确保属性值既不是空字符串,也不是空字符串(甚至确保本身不是空字符串,尽管在您的情况下不应发生这种情况)。.Version$null$ProductVersion$null

  • -notin 运算符提供了一种方便的方法来测试 LHS 字符串值是否不等于 RHS 数组的任何元素。

输出:

False
False
False
False
False
True

至于你试过的

((!($ProductVersion.Version -ne 'System Version')) -or (!($ProductVersion.Version -ne 'To be filled by O.E.M.'))

这可以简化为:

$ProductVersion.Version -eq 'System Version' -or $ProductVersion.Version -eq 'To be filled by O.E.M.'

并且与您想要的相反,即如果找到任何一个字符串值,它将返回。$true

您可以将表达式作为一个整体来否定( 和 -not同一个运算符):!

-not ($ProductVersion.Version -eq 'System Version' -or $ProductVersion.Version -eq 'To be filled by O.E.M.')

或 use 代替 ,这需要您更改为:-ne-eq-or-and

$ProductVersion.Version -ne 'System Version' -and $ProductVersion.Version -ne 'To be filled by O.E.M.'

-xor,仅当正好一个操作数为 时才返回 true,这里不需要,因为它需要计算两个操作数,这里不需要。$true

评论

0赞 Arthur Durand 2/21/2023
我很想按照您的建议去做,但我的代码需要在 WinPE 的 PowerShell 中运行
0赞 mklement0 2/21/2023
@ArthurDurand,我从未在 WinPE 中使用过 PowerShell。具体来说,从这个答案所暗示的内容来看,什么在 WinPE 中不起作用,为什么?
0赞 mklement0 2/21/2023
@ArthurDurand,未来的另一个提示:如果您需要在特定环境中运行,请在您的问题中添加适当的标记,例如本例中的 winpe
0赞 mklement0 2/21/2023
@ArthurDurand,为了将来的读者的利益:你在对答案的评论中指出,问题在于无法在 WinPE 环境中使用 CIM cmdlet。但是,这与本答案中的解决方案无关。
-3赞 Arthur Durand 2/21/2023 #2
    $BaseBoardProduct = Get-WmiObject Win32_BaseBoard | Where-Object {$_.Product -ne 'Not Available'} | Select-Object -ExpandProperty Product
    if (-not ([string]::IsNullOrWhiteSpace($BaseBoardProduct)))
    {
        $Model = $BaseBoardProduct
    }
    
    $ProductVersion = Get-WmiObject -Class:Win32_ComputerSystemProduct | Where- Object {$_.Version -ne 'System Version' -and $_.Version -ne 'To be filled by O.E.M.'} | Select-Object -ExpandProperty Version
    if (-not ([string]::IsNullOrWhiteSpace($ProductVersion)))
    {
        $Model = $ProductVersion
    }
    
    $SystemModel = Get-WmiObject -Class:Win32_ComputerSystem | Where-Object {$_.Model -ne 'System Product Name' -and $_.Model -ne 'To be filled by O.E.M.'} | Select-Object -ExpandProperty Model
    if (-not ([string]::IsNullOrWhiteSpace($SystemModel)))
    {
        $Model = $SystemModel
    }
    
    $SystemManufacturer = Get-WmiObject -Class:Win32_ComputerSystem | Where- Object {$_.Manufacturer -ne 'Not Available' -and $_.Manufacturer -ne 'System manufacturer' -and $_.Manufacturer -ne 'To be filled by O.E.M.'} | Select-Object -ExpandProperty Manufacturer
    if (-not ([string]::IsNullOrWhiteSpace($SystemManufacturer)))
    {
        $Manufacturer = $SystemManufacturer
    }
    
    if ($Manufacturer -like '*Lenovo*')
    {
        $ProductVersion = Get-WmiObject -Class:Win32_ComputerSystemProduct | 
Select-Object -ExpandProperty Version
        $Model = $ProductVersion
    }

解决了我的问题!然而,ChatGPT 想出了

$ExcludedManufacturers = 'Not Available', 'System Manufacturer', 'To be filled by O.E.M.'
$Filter = "Manufacturer!='Not Available' AND Manufacturer!='System Manufacturer' AND Manufacturer!='To be filled by O.E.M.'"

$SystemInfo = Get-CimInstance -ClassName Win32_ComputerSystem -Property Model, Manufacturer -Filter $Filter | Sort-Object Manufacturer
$BaseBoardProduct = Get-CimInstance -ClassName Win32_BaseBoard -Property Product -Filter "Product!='Not Available'" | Sort-Object Product | Select-Object -First 1
$ProductVersion = $SystemInfo | Where-Object { $_.Version -notin 'System Version', 'To be filled by O.E.M.' } | Sort-Object Manufacturer | Select-Object -First 1 -ExpandProperty Version
$Model = ($BaseBoardProduct.Product, $SystemInfo.Model) | Where-Object { $_ -notin 'System Product Name', 'To be filled by O.E.M.' } | Select-Object -First 1
$Manufacturer = $SystemInfo[0].Manufacturer

if ($Manufacturer -like '*Lenovo*') {
    $Model = $ProductVersion
}

$BaseBoardProduct = Get-WmiObject -Class Win32_BaseBoard | Select-Object -ExpandProperty Product | Where-Object {$_ -ne 'Not Available'} | Select-Object -First 1
$ProductVersion = Get-WmiObject -Class Win32_ComputerSystemProduct | Select-Object -ExpandProperty Version | Where-Object {$_ -notin ('System Version', 'To be filled by O.E.M.')} | Select-Object -First 1
$SystemModel = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Model | Where-Object {$_ -notin ('System Product Name', 'To be filled by O.E.M.')} | Select-Object -First 1
$SystemManufacturer = Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Manufacturer | Where-Object {$_ -notin ('Not Available', 'System Manufacturer', 'To be filled by O.E.M.')} | Select-Object -First 1

if ($SystemManufacturer -like '*Lenovo*') {
    $Model = $ProductVersion
} else {
    $Model = $BaseBoardProduct ?? $SystemModel ?? $ProductVersion
}

适用于旧版本的 PowerShell!

评论

0赞 mklement0 2/21/2023
我已经恢复了我原来的部分答案,以解释不使用 .你的答案缺乏解释,它缺少你的主要问题代码:你的条件的逻辑有缺陷(例如-ExpandProperty((!($ProductVersion.Version -ne 'System Version')) -or (!($ProductVersion.Version -ne 'To be filled by O.E.M.')) -and (-not ([string]::IsNullOrWhiteSpace($ProductVersion)))))
0赞 mklement0 2/21/2023
出于上述原因,我投了反对票,但我总是乐于在旨在达成共识的真诚对话的基础上重新讨论。当然,如果你觉得你的答案值得宣传作为你问题的解决方案,你应该自我接受它,你可以在 48 小时后这样做。
0赞 Arthur Durand 2/21/2023
您确实为我指出了正确的方向,我很想按照您的建议运行,但就像我说的,WinPE 不支持 CimInstance!
0赞 mklement0 2/21/2023
是否使用 CIM 还是 WMI cmdlet 是解决方案附带的。它也不再是我答案的一部分,只是作为现在对这个问题的评论而发布的旁白。关闭这个 - 无关紧要 - 切线:有趣的是,CIM cmdlet 不可用 WinPE (你之前没有提到过) ;我天真地问:这个限制是否记录在某个地方?
0赞 mklement0 2/21/2023
而且,撇开我的答案是否能解决你的问题不谈,请考虑解决我提出的观点,即为什么我认为你的答案对未来的读者没有帮助。