windowspowershellwmisystem-information

Powershell based replacement for WMI commands


I have an old script, its one of the first ones I wrote when i first started with Powershell. It uses Get-CimInstance -ClassName Win32_ComputerSystem and Get-CimInstance -ClassName Win32_OperatingSystem. Dusted it off for use on some users systems then found that some of the users have some sort of weird permissions issue for WMI and can't use the script. Personally, I never had an issue with it and never thought anyone else would.

So I'm looking to get away from the WMI/CIM instances and replace those with a .NET command or something else for use in the PowerShell script. Is there something else to use in the script besides the WMI/CIM instances? See script below I want to change

$Comp = (Get-CimInstance -ClassName Win32_ComputerSystem); 
$DRole =   ($Comp).DomainRole;
switch ($DRole)
{
    0 {$DominRole = 'Standalone Workstation'}
    1 {$DominRole = 'Member Workstation'}
    2 {$DominRole = 'Standalone Server'}
    3 {$DominRole = 'Member Server'}
    4 {$DominRole = 'Backup Domain Controller'}
    5 {$DominRole = 'Primary Domain Controller'}
}
$PhyMem = [string][math]::Round(($Comp).TotalPhysicalMemory/1GB, 1);
$FreePhyMem = [string][math]::Round((Get-CimInstance -ClassName Win32_OperatingSystem).FreePhysicalMemory/1024/1024, 1);
$cpux = (Get-WmiObject Win32_Processor).Name;
$GBMem = $PhyMem + ' GB Physical Memory (' + $FreePhyMem + ' GB Free)';
Return $DominRole + ' - ' + $GBMem + '/' + $cpux

Solution

  • If you're using at least PowerShell 5.1, Get-ComputerInfo makes a lot of this information available. You can see the relevant properties it provides with...

    PS> Get-ComputerInfo -Property 'CsDomainRole', '*Memory*', '*Processor*'
    

    Otherwise, you could use the classes in the System.Management namespace to directly query WMI in much the same way Get-WmiObject would under the hood...

    $selectedProperties = 'DomainRole', 'TotalPhysicalMemory'
    # https://learn.microsoft.com/dotnet/api/system.management.selectquery
    $query = New-Object -TypeName 'System.Management.SelectQuery' `
        -ArgumentList ('Win32_ComputerSystem', $null, $selectedProperties)
    # https://learn.microsoft.com/dotnet/api/system.management.managementobjectsearcher
    $searcher = New-Object -TypeName 'System.Management.ManagementObjectSearcher' `
        -ArgumentList $query
    
    try
    {
        # https://learn.microsoft.com/dotnet/api/system.management.managementobjectsearcher.get
        $results = $searcher.Get()
        # ManagementObjectCollection exposes an enumerator but not an indexer
        $computerSystem = $results | Select-Object -First 1
    
        $domainRole = $computerSystem['DomainRole']
        $totalPhysicalMemory = $computerSystem['TotalPhysicalMemory']
    
        # Do something with $domainRole and $totalPhysicalMemory...
        $domainRoleText = switch ($domainRole) {
            0 { 'Standalone Workstation'   ; break }
            1 { 'Member Workstation'       ; break }
            2 { 'Standalone Server'        ; break }
            3 { 'Member Server'            ; break }
            4 { 'Backup Domain Controller' ; break }
            5 { 'Primary Domain Controller'; break }
            default { $domainRole.ToString() }
        }
        $totalPhysicalMemoryGB = [Math]::Round($totalPhysicalMemory / 1GB, 1)
    }
    finally
    {
        $computerSystem.Dispose()
        $results.Dispose()
        $searcher.Dispose()
    }
    

    It's hard to know if your issue is with WMI itself or the cmdlets accessing it without more detail, though.