-1

I need to use PowerShell to properly get the System Model of a PC and use the model number as a parameter so that I can run tasks specific to the model number.

My code is a little more complex due to the fact that some of the methods returns values like 'Not Available', 'To be filled by O.E.M.'or 'System Product Manufacturer' - in these instances I do not want the $Model parameter to be 'Not Available', 'To be filled by O.E.M.'or 'System Product Manufacturer'.

I have the following, but it doesn't work as desired

    $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()
    }

I want e.g.

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

to return false when the ProductVersion returns 'To be filled by O.E.M.' or 'System Version', but it returns true!

I've tried

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

and

    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))))

but I get 'System Version' set as the parameter instead of the Model Number, in other words the argument returns true when it is supposed to return false

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • As an aside: The CIM cmdlets (e.g., `Get-CimInstance`) superseded the WMI cmdlets (e.g., `Get-WmiObject`) in PowerShell v3 (released in September 2012). Therefore, the WMI cmdlets should be avoided, not least because PowerShell (Core) v6+, where all future effort will go, doesn't even _have_ them anymore. Note that WMI still _underlies_ the CIM cmdlets, however. For more information, see [this answer](https://stackoverflow.com/a/54508009/45375) – mklement0 Feb 20 '23 at 21:22
  • Allow me to give you a tip for future questions: There's more code in your question than is necessary to illustrate the problem, which creates a distraction and makes it harder to diagnose the problem. The best possible presentation of a problem is in the form of a [mcve]. – mklement0 Feb 20 '23 at 22:40

2 Answers2

1
  • First, I suggest simplifying your property retrieval commands:

    • You're using Select-Object to extract a single property from the objects emitted by your Get-WmiObject calls

    • Perhaps surprisingly, something like ... | Select Product (short for: ... | Select-Object -Property Product) does not return the values of the input objects' .Product property, it returns a new object for each input object, which is of type [pscustomobject]and itself has a Product property.

    • To only extract the property values, use Select-Object's -ExpandProperty parameter instead of the (positionally implied) -Property parameter; e.g.
      ... | Select-Object -ExpandProperty Product.

    • See this post for more information and more efficient alternatives.

  • Second, there's a problem with your Boolean logic, explained in the next section.

However, I suggest simplifying your conditional as follows:

# 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 '' ensures that the .Version property value is neither $null nor the empty string (and even ensures that $ProductVersion itself is not $null (or the empty string, though that shouldn't happen in your case).

  • The -notin operator offers a convenient way of testing whether the LHS string value isn't equal to any of the elements of the RHS array.

Output:

False
False
False
False
False
True

As for what you tried:

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

This can be simplified to:

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

and is the opposite of what you want, i.e. it returns $true if either of the string values are found.

You could negate the expression as a whole (! and -not are the same operator):

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

or use -ne instead of -eq, which requires you to change -or to -and:

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

-xor, which returns true only if exactly one operand is $true, isn't called for here, because it requires evaluating both operands, which isn't necessary here.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I would love to do as you suggest, but my code needs to run in PowerShell in WinPE – Arthur Durand Feb 20 '23 at 23:30
  • @ArthurDurand, I've never used PowerShell in WinPE. What, specifically, from what this answer suggests, does _not_ work in WinPE, and why? – mklement0 Feb 20 '23 at 23:34
  • @ArthurDurand, another tip for the future: If you need to run in a specific environment, add the appropriate tag to your question, such as [tag:winpe] in this case. – mklement0 Feb 20 '23 at 23:36
  • @ArthurDurand, for the benefit of future readers: You state in a comment on your answer that the problem is that you cannot use CIM cmdlets in your WinPE environment. However, that is irrelevant to the solutions in this answer. – mklement0 Feb 21 '23 at 15:10
-3
    $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
    }

solves my issue! However, ChatGPT came up with

$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
}

or

$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
}

for older versions of PowerShell!

  • I've revived part of my original answer to explain the problem with not using `-ExpandProperty`. Your answer lacks an explanation, and it is missing the code that was your primary problem: the flawed logic of your conditionals (e.g. `((!($ProductVersion.Version -ne 'System Version')) -or (!($ProductVersion.Version -ne 'To be filled by O.E.M.')) -and (-not ([string]::IsNullOrWhiteSpace($ProductVersion))))`) – mklement0 Feb 20 '23 at 21:38
  • For the reasons stated, I'm down-voting, but I'm always happy to revisit based on a good-faith dialogue aimed at reaching a shared understanding. Of course, if _you_ feel that your answer is worth advertising as the solution to your problem, you should [self-accept](http://stackoverflow.com/help/self-answer) it, which you can do after 48 hours. – mklement0 Feb 20 '23 at 23:41
  • You did point me in the right direction, I would've loved to run with your suggestions, but like I said, WinPE doesn't support CimInstance! – Arthur Durand Feb 21 '23 at 14:55
  • Whether to use CIM vs. the WMI cmdlets is incidental to the solution. It also is no longer part of my answer, just an aside posted as a comment on the question now. To close this - inconsequential - tangent: It is interesting that the CIM cmdlets aren't available WinPE (which you hadn't mentioned before); I'm asking innocently: is this limitation documented somewhere? – mklement0 Feb 21 '23 at 15:06
  • And, leaving aside whether my answer solves your problem or not, please consider addressing the points I've made about why I think your answer won't be helpful to future readers. – mklement0 Feb 21 '23 at 15:16