Retrieve Basic Operating System Information with PowerShell

PowerShell version 5.1 added a new cmdlet named Get-ComputerInfo which retrieves lots of information from the local computer. It can be wrapped inside of the PowerShell remoting Invoke-Command cmdlet to retrieve that same information from remote computers.

My biggest complaint with Get-ComputerInfo is that it takes forever to return the information and then when it does finally complete, it's missing values for most of its properties. Also, if you're going to wrap it inside of Invoke-Command, then all of your remote machines would need PowerShell 5.1 or higher installed.

Because of these shortcomings, I decided to write my own simple function to retrieve just the operating system information I wanted while relying on CIM sessions for remote connectivity so down level clients could also be queried.

 1#Requires -Version 3.0
 2function Get-MrOSInfo {
 3
 4<#
 5.SYNOPSIS
 6    Gets basic operating system properties.
 7
 8.DESCRIPTION
 9    The Get-MrOSInfo function gets basic operating system properties for the local computer or for one or more remote
10    computers.
11
12 .PARAMETER CimSession
13    Specifies the CIM session to use for this function. Enter a variable that contains the CIM session or a command that
14    creates or gets the CIM session, such as the New-CimSession or Get-CimSession cmdlets. For more information, see
15    about_CimSessions.
16
17.EXAMPLE
18    Get-MrOSInfo
19
20.EXAMPLE
21    Get-MrOSInfo -CimSession (New-CimSession -ComputerName Server01, Server02)
22
23.INPUTS
24    None
25
26.OUTPUTS
27    PSCustomObject
28
29.NOTES
30    Author:  Mike F Robbins
31    Website: http://mikefrobbins.com
32    Twitter: @mikefrobbins
33#>
34
35    [CmdletBinding()]
36    param (
37        [Microsoft.Management.Infrastructure.CimSession[]]$CimSession
38    )
39
40    $Params = @{}
41
42    if ($PSBoundParameters.CimSession) {
43        $Params.CimSession = $CimSession
44    }
45
46    $OSInfo = Get-CimInstance @Params -ClassName Win32_OperatingSystem -Property Caption, BuildNumber, OSArchitecture, CSName
47
48    $OSVersion = Invoke-CimMethod @Params -Namespace root\cimv2 -ClassName StdRegProv -MethodName GetSTRINGvalue -Arguments @{
49                    hDefKey=[uint32]2147483650; sSubKeyName='SOFTWARE\Microsoft\Windows NT\CurrentVersion'; sValueName='ReleaseId'}
50
51    $PSVersion = Invoke-CimMethod @Params -Namespace root\cimv2 -ClassName StdRegProv -MethodName GetSTRINGvalue -Arguments @{
52                    hDefKey=[uint32]2147483650; sSubKeyName='SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine'; sValueName='PowerShellVersion'}
53
54    foreach ($OS in $OSInfo) {
55        if (-not $PSBoundParameters.CimSession) {
56            $OSVersion.PSComputerName = $OS.CSName
57            $PSVersion.PSComputerName = $OS.CSName
58        }
59
60        $PS = $PSVersion | Where-Object PSComputerName -eq $OS.CSName
61
62        if (-not $PS.sValue) {
63            $Params2 = @{}
64
65            if ($PSBoundParameters.CimSession) {
66                $Params2.CimSession = $CimSession | Where-Object ComputerName -eq $OS.CSName
67            }
68
69            $PS = Invoke-CimMethod @Params2 -Namespace root\cimv2 -ClassName StdRegProv -MethodName GetSTRINGvalue -Arguments @{
70                        hDefKey=[uint32]2147483650; sSubKeyName='SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine'; sValueName='PowerShellVersion'}
71        }
72
73        [pscustomobject]@{
74            ComputerName = $OS.CSName
75            OperatingSystem = $OS.Caption
76            Version = ($OSVersion | Where-Object PSComputerName -eq $OS.CSName).sValue
77            BuildNumber = $OS.BuildNumber
78            OSArchitecture = $OS.OSArchitecture
79            PowerShellVersion = $PS.sValue
80
81        }
82
83    }
84
85}

One of the most difficult parts of writing this function was figuring out how to query the registry of a remote computer with a CIM session. I also didn't want to retrieve the information from one remote computer at a time. Instead, I wanted to retrieve the information for all of the computers at once and then put the pieces together before returning the information. While this is a little more complicated than query one computer at a time, the added efficiency and reduced run-time makes it worth the effort.

Simply run the function with no parameters to retrieve information from the local computer.

1Get-MrOSInfo

osinfo1a.jpg

Now, I'll create CIM sessions to several different servers running different operating system versions and various versions of PowerShell.

1$CimSession = New-MrCimSession -ComputerName dc01, sql05, sql08, sql14, srv1, srv2
2$CimSession

osinfo2b.jpg

Notice that by using my New-MrCimSession function, it automatically created all of the ones capable of using the WSMan protocol using it and the one that wasn't using the DCom protocol. The SQL05 server runs Windows Server 2008 (non-R2) and does not have PowerShell installed at all.

1Get-MrOSInfo -CimSession $CimSession

osinfo3a.jpg

The version number such as 1511, 1607, 1703, or 1709 will only show up for machines running Windows 10 or Server 2016 (or higher if you're reading this in the future), but the neat thing is the Get-MrOSInfo function is able to query down level servers such as SQL05 that do not have PowerShell installed.

I went ahead and added PowerShell version 1.0 to my SQL05 server. When the same command is run again, it shows that server does indeed now have PowerShell 1.0 installed. That particular version of PowerShell does not include remoting or the ability to return the version with the $PSVersionTable built-in variable.

1Get-MrOSInfo -CimSession $CimSession

osinfo4a.jpg

Both the Get-MrOSInfo and New-MrCimSession functions shown in this blog article can be downloaded from my PowerShell repository on GitHub.

µ