Back to top

FREE eBook: The Most USEFUL PowerShell CmdLets and more…

Grab a copy!

How To Get Windows Operating System Details Using PowerShell

Working in a multiserver environment demands very often to have an easy and fast method to collect information about the servers’ hardware or software, particularly Windows OS (Operating System) properties. PowerShell is a very handy tool in that sense, especially when the client’s SLA (Service Level Agreement) is so strict that you cannot install any 3rd party software to do the job.

In order to collect Window Operating System (OS) properties information using PowerShell, we use either WMI or CIM classes, Win32_OperatingSystem or CIM_OperatingSystem respectively.

Get Windows Operating System OS Details Using PowerShell – Solutions

Here are few solutions for the local machine, remote computers, and writing own PowerShell CmdLet.

Solution 1 – Get Windows Operating System OS Details Using PowerShell For The Local Machine.

We call Get-CimInstance CmdLet and get the necessary data from CIM_OperatingSystem CIM Class.

Get-CimInstance -Class CIM_OperatingSystem -ComputerName localhost -ErrorAction Stop | Select-Object *

Here is the result set for the local machine:

Local machine Windows Operating System OS Properties result set

Solution 2 – Get Windows Operating System OS Details Using PowerShell For Remote Computers

Create the list of servers in the text file and save in, for example, C:\Temp folder and run the same command as in the previous solution just use ComputerName parameter in addition. We basically load the content of the text file using Get-Content CmdLet and PowerShell will go through the list and run the same command as in the previous solution for each server on the list.

Get-CimInstance -Class CIM_OperatingSystem -ComputerName (Get-Content -Path C:\Temp\servers.txt) -ErrorAction Stop | Select-Object * | Out-GridView

Here is the result set for the list of servers:

Windows Operating System OS details result set for the list of servers

I do not have servers in my home network so in order to simulate one I have created a very simple input list of servers in a text file just copying the localhost value several times.

Servers.txt file content

Solution 3 – Write Own PowerShell CmdLet ( Get-OSInfo ) To Get Windows Operating System Details Using PowerShell

This is my favorite method. It takes some time to write the code but it pays off in the long run with its reusability and can be combined with the library of other own CmdLets.

I have written my own CmdLet Get-OSInfo CmdLet that I will explain to you shortly.

Here is one example of calling Get-OSInfo CmdLet:

Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose |  Select-Object 'Environment', 'Logical Name', 'Server Name',  'Caption', 'Service pack', 'Version', 'OS Architecture', 'Install Date', 'Last BootUp Time', 'System drive', 'Windows directory', 'Free RAM (GB)', 'Free space in paging files (GB)', 'Free virtual memory (GB)', 'Number of processes', 'Number of users', 'Size stored in paging file (GB)', 'Total virtual memory size (GB)', 'Total visible memory size (GB)', 'IP', 'Collected' | Out-GridView

Here is the result set while calling Get-OSInfo CmdLet:

Get-OSInfo CmdLet result set

Here is the list of properties that are returned with the PowerShell CIM_OperatingSystem CIM Class.

#PropertyDescription
1BootDeviceName of the disk drive from which the Windows operating system starts.
2BuildNumberBuild number of an operating system.
3BuildTypeType of build used for an operating system.
4CaptionShort description of OS and can be localized.
5CodeSetCode page value an operating system uses. A code page contains a character table that an operating system uses to translate strings for different languages.
6CountryCodeCode for the country/region that an operating system uses.
7CreationClassNameWMI or CIM class used in creation of an instance.
8CSCreationClassNameCreation class name of the scoping computer system.
9CSDVersionString that indicates the latest service pack installed on a computer.
10CSNameName of the computer system.
11CurrentTimeZoneNumber, in minutes, an operating system is offset from Greenwich mean time (GMT).
12DataExecutionPrevention_32BitApplications
13DataExecutionPrevention_Available
14DataExecutionPrevention_Drivers
15DataExecutionPrevention_SupportPolicy
16DebugOperating system is a checked (debug) build. If True, the debugging version is installed.
17DescriptionDescription of the Windows operating system.
18DistributedIf True, the operating system is distributed across several computer system nodes.
19EncryptionLevelEncryption level for secure transactions: 40-bit, 128-bit, or n-bit.
20ForegroundApplicationBoostIncrease in priority is given to the foreground application.
21FreePhysicalMemoryNumber, in kilobytes, of physical memory currently unused and available.
22FreeSpaceInPagingFilesNumber, in kilobytes, that can be mapped into the operating system paging files without causing any other pages to be swapped out.
23FreeVirtualMemoryNumber, in kilobytes, of virtual memory currently unused and available.
24InstallDateOperating System OS was installed.
25LargeSystemCacheThis property is obsolete and not supported.
26LastBootUpTimeDate and time the operating system was last restarted.
27LocalDateTimeOperating system version of the local date and time-of-day.
28LocaleLanguage identifier used by the operating system.
29ManufacturerName of the operating system manufacturer.
30MaxNumberOfProcessesMaximum number of process contexts the operating system can support.
31MaxProcessMemorySizeMaximum number, in kilobytes, of memory that can be allocated to a process.
32MUILanguagesMultilingual User Interface Pack (MUI Pack ) languages installed on the computer.
33NameOperating system instance within a computer system.
34NumberOfLicensedUsersNumber of user licenses for the operating system.
35NumberOfProcessesNumber of process contexts currently loaded or running on the operating system.
36NumberOfUsersNumber of user sessions for which the operating system is storing state information currently.
37OperatingSystemSKUStock Keeping Unit (SKU) number for the operating system.
38OrganizationCompany name for the registered user of the operating system.
39OSArchitectureArchitecture of the operating system.
40OSLanguageLanguage version of the operating system installed.
41OSProductSuiteInstalled and licensed system product additions to the operating system.
42OSTypeType of operating system.
43OtherTypeDescriptionAdditional description for the current operating system version.
44PAEEnabledIf True, the physical address extensions (PAE) are enabled by the operating system running on Intel processors.
45PlusProductIDNot supported.
46PlusVersionNumberNot supported.
47PortableOperatingSystemSpecifies whether the operating system booted from an external USB device. If true, the operating system has detected it is booting on a supported locally connected storage device.
48PrimarySpecifies whether this is the primary operating system.
49ProductTypeAdditional system information.
50PSComputerNameComputer name.
51RegisteredUserName of the registered user of the operating system.
52SerialNumberOperating system product serial identification number.
53ServicePackMajorVersionMajor version number of the service pack installed on the computer system.
54ServicePackMinorVersionMinor version number of the service pack installed on the computer system.
55SizeStoredInPagingFilesTotal number of kilobytes that can be stored in the operating system paging files—0 (zero) indicates that there are no paging files.
56StatusCurrent status of operating system OS: OK, Error, Degraded, etc.
57SuiteMaskBit flags that identify the product suites available on the system.
58SystemDevicePhysical disk partition on which the operating system is installed.
59SystemDirectorySystem directory of the operating system.
60SystemDriveLetter of the disk drive on which the operating system resides. Example: "C:"
61TotalSwapSpaceSizeTotal swap space in kilobytes [KB].
62TotalVirtualMemorySizeNumber, in kilobytes, of virtual memory.
63TotalVisibleMemorySizeTotal amount, in kilobytes, of physical memory available to the operating system.
64VersionVersion number of the operating system.
65WindowsDirectoryWindows directory of the operating system.
CIM_OperatingSystem - CIM Class properties

INFO: I have written two PowerShell Add-on functions ( Get-CIMClassProperty and Select-CIMClassAllProperties) that help us working with WMI and CIM classes. First list all the properties and datatypes of WMI or CIM classes and the second one makes the select statements with all the properties for the WMI or CIM class. How To List CIM Or WMI Class All Properties And Their Datatypes With PowerShell AND How To Write Select Statement For All Properties Of CIM Or WMI Class With PowerShell.

Get-OSInfo CmdLet Explained

Get-OSInfo CmdLet collects Windows Operating System OS properties information for the list of servers and this CmdLet belongs to Efficiency Booster PowerShell Project. This project is the library of different CmdLets that can help us IT personal to do our everyday tasks more efficiently and accurately.

Source code for Get-OSInfo CmdLet can be downloaded from this zip file so please feel free to download it and it would be easier for you to follow me along.

Get-OSInfo CmdLet is part of Common module and if you have downloaded the source code it can be found in the folder …\[My] Documents\WindowsPowerShell\Modules\03common

INFO: If you want to know how to install and configure Efficiency Booster PowerShell Project files please read the following article: How To Install And Configure PowerShell: CmdLets, Modules, Profiles.

Get-OSInfo CmdLet – Input Parameters

As input parameters we have:

  • computers – it is a list of servers passed as input parameter with default value ‘localhost’ and accepts both pipeline options. Parameter belongs to the “ServerNames” parameter set. The “ServerNames” parameter set is the default parameter set.
  • filename – it is the name of the text file with the list of servers and represents an alternative option to the “computers” parameter. The parameter belongs to the “FileName” parameter set.
  • errorlog – switch datatype and when turned on it will write errors into an external error log file using Write-ErrorLog CmdLet. The error log file is located in the PSLogs folder of [My] Documents.
  • client – it is a mandatory input parameter and by convention, I use two letters for client shortcode (for example, OK = O client, BK = B client, etc.). This parameter value is part of the filename parameter naming convention.
  • solution – it is a mandatory input parameter and by convention, I use two-three letters for solution shortcode (for example, FIN = Financial solution, HR = HR solution, etc.).

The naming convention for the filename parameter is as follows: Client + Solution + Text.txt. The text file should be located in …[My] Documents\WindowsPowerShell\Modules\01servers folder.

For example:

  • OKFINTestServers.txt – List of test environment servers for OK client and FIN solution
  • OKFINProdServers.txt – List of production environmentservers for OK client and FIN solution.
  • OKFINAllServers.txt – List of all servers for OK client and FIN solution.

INFO: To get a deeper explanation about client and solution input parameters please read these two sections Parameter clientParameter solution.

INFO: In order to customize installation of CmdLet to your needs and setup necessary CSV file please read the following article How To Install And Configure PowerShell: CmdLets, Modules, Profiles

Here is the parameters definition code:

Function Get-OSInfo {
[CmdletBinding(DefaultParametersetName="ServerNames")]
param (
    [Parameter( ValueFromPipeline=$true,
                ValueFromPipelineByPropertyName=$true,
                ParameterSetName="ServerNames",
                HelpMessage="List of computer names separated by commas.")]
    [Alias('hosts')] 
    [string[]]$computers = 'localhost',
    
    [Parameter( ParameterSetName="FileName",
                HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")] 
    [string]$filename,
    
    [Parameter( Mandatory=$false,
                HelpMessage="Write to error log file or not.")]
    [switch]$errorlog,
    
    [Parameter(Mandatory=$true, 
                HelpMessage="Client for example OK = O client, BK = B client")]
    [string]$client,
     
    [Parameter(Mandatory=$true,
                HelpMessage="Solution, for example FIN = Financial, HR = Human Resource")]
    [string]$solution     
)

INFO: To know more about PowerShell Parameters and Parameter Sets with some awesome examples please read the following articles How To Create Parameters In PowerShell and How To Use Parameter Sets In PowerShell Functions.

INFOPowerShell Pipelining is a very important concept and I highly recommend you to read the article written on the subject. How PowerShell Pipeline Works. Here I have shown in many examples the real power of PowerShell using the Pipelining.

BEGIN Block

In the BEGIN block we:

  • If the FileName parameter set has been used we test if text file with a list of servers exists.
  • If the file exists read the file and create the list of servers as a string array in the $computers variable.
  • … and if not write a warning with information to the caller to create the file.
BEGIN {
    if ( $PsCmdlet.ParameterSetName -eq "FileName") {
        if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) {
            Write-Verbose "Read content from file: $filename"
            $computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" )        
        } else {
            Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename"
            Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names."
            break;
        }     
    }
}

PROCESS Block

In the PROCESS block we run this block of code for each server passed into the pipeline or read from the text file:

  • We replace the localhost default value for the local server with the actual name of the local machine.
  • We use Get-ComputerInfo CmdLet to read additional data about each server (name, environment, logical name, IP address).
  • We implement Error Handling using try-catch blocks and writing errors in an external text file using Write-ErrorLog CmdLet.
  • We use PowerShell splatting to prepare the input parameters for the next call of Get-CimInstance CmdLet.
  • We call CIM class CIM_OperatingSystem using Get-CimInstance CmdLet
  • We go through each Operating System OS installed of each server and prepare the resultset of Get-OSInfo CmdLet.

In the PROCESS block, I would like to emphasize three things used in the code:

1 – Splatting

Here is splatting:

$params = @{ 'ComputerName'=$computer;
                         'Class'='CIM_OperatingSystem';
                         'ErrorAction'='Stop'}
            
#Values are already in kilobytes that is the reason to divide with megabytes to get gigabytes.
$OSInfos = Get-CimInstance @params | 
                            
Select-Object   CSName, 
Caption, 
CSDVersion, 
Version, 
OSArchitecture,
InstallDate,
LastBootUpTime,
SystemDrive, 
WindowsDirectory, 
@{Name="FreePhysicalMemory";Expression={("{0:N2}" -f($_.FreePhysicalMemory/1mb))}}, 
@{Name="FreeSpaceInPagingFiles";Expression={("{0:N2}" -f($_.FreeSpaceInPagingFiles/1mb))}}, 
@{Name="FreeVirtualMemory";Expression={("{0:N2}" -f($_.FreeVirtualMemory/1mb))}},  
NumberOfProcesses, 
NumberOfUsers, 
@{Name="SizeStoredInPagingFiles";Expression={("{0:N2}" -f($_.SizeStoredInPagingFiles/1mb))}}, 
@{Name="TotalVirtualMemorySize";Expression={("{0:N2}" -f($_.TotalVirtualMemorySize/1mb))}}, 
@{Name="TotalVisibleMemorySize";Expression={("{0:N2}" -f($_.TotalVisibleMemorySize/1mb))}}

2 – Result set Creation And Type Name Of Result set

Again for creation of result set I use splatting as you can see in the source code:

$properties = @{  
'Environment'=$env;
'Logical name'=$logicalname;
'Server name'=$OSInfo.CSName;
'Caption'=$OSInfo.Caption;
'Service pack'=$OSInfo.CSDVersion;
'Version'=$OSInfo.Version; 
'OS Architecture'=$OSInfo.OSArchitecture;
'Install Date'=$OSInfo.InstallDate;
'Last BootUp Time'=$OSInfo.LastBootUpTime;
'System drive'=$OSInfo.SystemDrive;
'Windows directory'=$OSInfo.WindowsDirectory;
'Free RAM (GB)'=$OSInfo.FreePhysicalMemory;
'Free space in paging files (GB)'=$OSInfo.FreeSpaceInPagingFiles;
'Free virtual memory (GB)'=$OSInfo.FreeVirtualMemory;
'Number of processes'=$OSInfo.NumberOfProcesses;
'Number of users'=$OSInfo.NumberOfUsers;
'Size stored in paging file (GB)'=$OSInfo.SizeStoredInPagingFiles;
'Total virtual memory size (GB)'=$OSInfo.TotalVirtualMemorySize;
'Total visible memory size (GB)'=$OSInfo.TotalVisibleMemorySize;
'IP'=$ip;
'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)}

$obj = New-Object -TypeName PSObject -Property $properties
$obj.PSObject.TypeNames.Insert(0,'Report.OSInfo')

In addition, I give a name (Report.OSInfo) to the type of result set as you can see in the code:

$obj.PSObject.TypeNames.Insert(0,'Report.OSInfo')

So if we call PowerShell Get-Member CmdLet to get the type of result set for Get-OSInfo CmdLet we will get Report.OSInfo type and not standard PowerShell PSObject type.

Get-OSInfo -client "OK" -solution "FIN" | Get-Member 

Here is the result:

Report.OSInfo Type Name for Get-OSInfo CmdLet result set

Type Name of result set gives us a possibility to further expend the use of the result set. For example, we can use MS SQL Database and create table OSInfo based on result set type name (Report.OSInfo) where we can record the result set and use MS SQL Reporting Services to show the results collected over a certain period of time.

3 – Convert RAM Size in Gigabytes [GB]

Notice how we have used the expression to convert all the values from Kilobytes [KB] into Gigabytes [GB] which is the norm nowadays and much better representation than default values delivered:

$OSInfos = Get-CimInstance @params | 

Select-Object   CSName, 
Caption, 
CSDVersion, 
Version, 
OSArchitecture,
InstallDate,
LastBootUpTime,
SystemDrive, 
WindowsDirectory, 
@{Name="FreePhysicalMemory";Expression={("{0:N2}" -f($_.FreePhysicalMemory/1mb))}}, 
@{Name="FreeSpaceInPagingFiles";Expression={("{0:N2}" -f($_.FreeSpaceInPagingFiles/1mb))}}, 
@{Name="FreeVirtualMemory";Expression={("{0:N2}" -f($_.FreeVirtualMemory/1mb))}},  
NumberOfProcesses, 
NumberOfUsers, 
@{Name="SizeStoredInPagingFiles";Expression={("{0:N2}" -f($_.SizeStoredInPagingFiles/1mb))}}, 
@{Name="TotalVirtualMemorySize";Expression={("{0:N2}" -f($_.TotalVirtualMemorySize/1mb))}}, 
@{Name="TotalVisibleMemorySize";Expression={("{0:N2}" -f($_.TotalVisibleMemorySize/1mb))}}

Finally, here is the PROCESS block source code:

PROCESS { 

    foreach ($computer in $computers ) {

        if ( $computer -eq 'localhost' ) {
            $computer = $env:COMPUTERNAME
        }

        $computerinfo = Get-ComputerInfo -computername $computer -client $client -solution $solution
        $hostname = $computerinfo.hostname
        $env = $computerinfo.environment
        $logicalname = $computerinfo.logicalname
        $ip = $computerinfo.ipaddress
        
        try {
            Write-Verbose "Start processing: $computer - $env - $logicalname"
            Write-Verbose "Start CIM_OperatingSystem processing..."
            $OSInfos = $null
            $OSInfo = $null
            $obj = $null

            $params = @{ 'ComputerName'=$computer;
                         'Class'='CIM_OperatingSystem';
                         'ErrorAction'='Stop'}
            
            #Values are already in kilobytes that is the reason to divide with megabytes to get gigabytes.
            $OSInfos = Get-CimInstance @params | 
                Select-Object   CSName, 
                                Caption, 
                                CSDVersion, 
                                Version, 
                                OSArchitecture,
                                InstallDate,
                                LastBootUpTime,
                                SystemDrive, 
                                WindowsDirectory, 
                                @{Name="FreePhysicalMemory";Expression={("{0:N2}" -f($_.FreePhysicalMemory/1mb))}}, 
                                @{Name="FreeSpaceInPagingFiles";Expression={("{0:N2}" -f($_.FreeSpaceInPagingFiles/1mb))}}, 
                                @{Name="FreeVirtualMemory";Expression={("{0:N2}" -f($_.FreeVirtualMemory/1mb))}},  
                                NumberOfProcesses, 
                                NumberOfUsers, 
                                @{Name="SizeStoredInPagingFiles";Expression={("{0:N2}" -f($_.SizeStoredInPagingFiles/1mb))}}, 
                                @{Name="TotalVirtualMemorySize";Expression={("{0:N2}" -f($_.TotalVirtualMemorySize/1mb))}}, 
                                @{Name="TotalVisibleMemorySize";Expression={("{0:N2}" -f($_.TotalVisibleMemorySize/1mb))}}
                                
            Write-Verbose "Finish CIM_OperatingSystem processing..."
            
            foreach ($OSInfo in $OSInfos) {
                Write-Verbose "Start processing OS: $OSInfo"

                $properties = @{ 'Environment'=$env;
                                 'Logical name'=$logicalname;
                                 'Server name'=$OSInfo.CSName;
            	                 'Caption'=$OSInfo.Caption;
            	                 'Service pack'=$OSInfo.CSDVersion;
            	                 'Version'=$OSInfo.Version; 
                                 'OS Architecture'=$OSInfo.OSArchitecture;
                                 'Install Date'=$OSInfo.InstallDate;
                                 'Last BootUp Time'=$OSInfo.LastBootUpTime;
                                 'System drive'=$OSInfo.SystemDrive;
                                 'Windows directory'=$OSInfo.WindowsDirectory;
                                 'Free RAM (GB)'=$OSInfo.FreePhysicalMemory;
                                 'Free space in paging files (GB)'=$OSInfo.FreeSpaceInPagingFiles;
                                 'Free virtual memory (GB)'=$OSInfo.FreeVirtualMemory;
                                 'Number of processes'=$OSInfo.NumberOfProcesses;
                                 'Number of users'=$OSInfo.NumberOfUsers;
                                 'Size stored in paging file (GB)'=$OSInfo.SizeStoredInPagingFiles;
                                 'Total virtual memory size (GB)'=$OSInfo.TotalVirtualMemorySize;
                                 'Total visible memory size (GB)'=$OSInfo.TotalVisibleMemorySize;
                                 'IP'=$ip;
                                 'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)}

                $obj = New-Object -TypeName PSObject -Property $properties
                $obj.PSObject.TypeNames.Insert(0,'Report.OSInfo')

                Write-Output $obj
                Write-Verbose "Finish processing OS: $OSInfo"
            }
            
            Write-Verbose "Finish processing: $computer - $env - $logicalname"
            
        } catch {
            Write-Warning "Computer failed: $computer - $env - $logicalname OS failed: $OSInfo"
            Write-Warning "Error message: $_"

            if ( $errorlog ) {

                $errormsg = $_.ToString()
                $exception = $_.Exception
                $stacktrace = $_.ScriptStackTrace
                $failingline = $_.InvocationInfo.Line
                $positionmsg = $_.InvocationInfo.PositionMessage
                $pscommandpath = $_.InvocationInfo.PSCommandPath
                $failinglinenumber = $_.InvocationInfo.ScriptLineNumber
                $scriptname = $_.InvocationInfo.ScriptName

                $ErrorArguments = @{
                    'hostname' = $computer;
                    'env' = $env;
                    'logicalname' = $logicalname;
                    'errormsg' = $errormsg;
                    'exception' = $exception;
                    'stacktrace'= $stacktrace;
                    'failingline' = $failingline;
                    'positionmsg' = $positionmsg;
                    'pscommandpath' = $pscommandpath;
                    'failinglinenumber' = $failinglinenumber;
                    'scriptname' = $scriptname
                }

                Write-Verbose "Start writing to Error log."
                Write-ErrorLog @ErrorArguments
                #Write-ErrorLog -hostname $computer -env $env -logicalname $logicalname -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace
                Write-Verbose "Finish writing to Error log."
            }
        }
    }
}

INFO: To learn about PowerShell Error Handling and code debugging please read the following articles: How To Log PowerShell Errors And Much More and How To Debug PowerShell Scripts.

END Block

END block is empty.

INFO: To understand BEGINPROCESS and END blocks in PowerShell please read PowerShell Function Begin Process End Blocks Explained With Examples.

Comment-Based Help Section

For every one of my own CmdLets, I write Comment-Based help as well.

INFO: If you want to learn how to write comment-based Help for your own PowerShell Functions and Scripts please read these articles How To Write PowerShell Help (Step by Step). In this article How To Write PowerShell Function’s Or CmdLet’s Help (Fast), I explain the PowerShell Add-on that helps us to be fast with writing help content.

How To Use Get-OSInfo CmdLet – Tips

To get Windows Operating System OS details for the local machine we just call Get-OSInfo CmdLet and provide values for mandatory parameters (client and solution):

Get-OSInfo -client "OK" -solution "FIN"

Here is the result set:

Get-OSInfo CmdLet result set for the local machine

As we have seen in the solution section of this article we can call Get-OSInfo CmdLet for the list of servers:

Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose |  Select-Object 'Environment', 'Logical Name', 'Server Name',  'Caption', 'Service pack', 'Version', 'OS Architecture', 'Install Date', 'Last BootUp Time', 'System drive', 'Windows directory', 'Free RAM (GB)', 'Free space in paging files (GB)', 'Free virtual memory (GB)', 'Number of processes', 'Number of users', 'Size stored in paging file (GB)', 'Total virtual memory size (GB)', 'Total visible memory size (GB)', 'IP', 'Collected' | Out-GridView

Here is the result set for list of servers:

Get-OSInfo CmdLet result set

We can PowerShell pipeline result from Get-OSInfo CmdLet into Save-ToExcel CmdLet and get the result set as an Excel Sheet:

Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Select-Object 'Environment', 'Logical Name', 'Server Name',  'Caption', 'Service pack', 'Version', 'OS Architecture', 'Install Date', 'Last BootUp Time', 'System drive', 'Windows directory', 'Free RAM (GB)', 'Free space in paging files (GB)', 'Free virtual memory (GB)', 'Number of processes', 'Number of users', 'Size stored in paging file (GB)', 'Total virtual memory size (GB)', 'Total visible memory size (GB)', 'IP', 'Collected' | Save-ToExcel -errorlog -ExcelFileName "Get-OSInfo" -title "Get OS info of servers in Financial solution for " -author "Dejan Mladenovic" -WorkSheetName "OS Info" -client "OK" -solution "FIN" 

Here is the Excel Sheet result:

Get-OSInfo CmdLet result set as Excel Sheet

Bonus Tip: I have used Get-OSInfo CmdLet for documentation purposes while making a PDF document for the client where we have installed our solution.

Useful PowerShell Windows Operating System Properties Information Articles

Here are some useful articles and resources:

Get-OSInfo CmdLet Source Code

DISCLAIMERGet-OSInfo function is part of the Efficiency Booster PowerShell Project and as such utilize other CmdLets that are part of the same project. So the best option for you in order for this function to work without any additional customization is to download the source code of the whole project from here.

INFO: My best advice to every PowerShell scripter is to learn writing own PowerShell Advanced Functions and CmdLets and I have written several articles explaining this, so please read them. How To Create A Custom PowerShell CmdLet (Step By Step). Here I explain how to use PowerShell Add-on Function to be faster in writing PowerShell Functions How To Write Advanced Functions Or CmdLets With PowerShell (Fast).

Here is the source code of the whole Get-OSInfo CmdLet:

<#
.SYNOPSIS
Get Operating System info.
.DESCRIPTION
Gets Operating system info for list of servers. 
List of servers is in txt file in 01servers folder or list of strings with names of computers.

CmdLet has two ParameterSets one for list of computers from file and another from list of strings as computer names.

Errors will be saved in log folder PSLogs with name Error_Log.txt. Parameter errorlog controls logging of errors in log file.

Get-OSInfo function uses Get-CimInstance -Class CIM_OperatingSystem PowerShell function to get OS info.

Result shows following columns: Environment (PROD, Acceptance, Test, Course...), 
LogicalName (Application, web, integration, FTP, Scan, Terminal Server...), ServerName, Caption, CSDVersion, Version,
OSArchitecture, Install Date, Last BootUp Time, SystemDrive, WindowsDirectory, FreePhysicalMemory, FreeSpaceInPagingFiles, 
FreeVirtualMemory, NumberOfProcesses, NumberOfUsers, SizeStoredInPagingFile, TotalVirtualMemorySize, TotalVisibleMemorySize, IP

.PARAMETER computers
List of computers that we want to get OS Info from. Parameter belongs to default Parameter Set = ServerNames.
.PARAMETER filename
Name of txt file with list of servers that we want to check OS info. .txt file should be in 01servers folder.
Parameter belongs to Parameter Set = FileName.
.PARAMETER errorlog
Switch parameter that sets to write to log or not to write to log. Error file is in PSLog folder with name Error_Log.txt.
.PARAMETER client
OK - O client
BK - B client
etc.
.PARAMETER solution
FIN - Financial 
HR - Humane resource
etc. 

.EXAMPLE
Get-OSInfo -client "OK" -solution "FIN"

Description
---------------------------------------
Test of default parameter with default value ( computers = 'localhost' ) in default ParameterSet = ServerName.

.EXAMPLE
Get-OSInfo -client "OK" -solution "FIN" -Verbose

Description
---------------------------------------
Test of Verbose parameter. NOTE: Notice how localhost default value of parameter computers replaces with name of server.

.EXAMPLE
'ERROR' | Get-OSInfo -client "OK" -solution "FIN" -errorlog

Description
---------------------------------------
Test of errorlog parameter. There is no server with name ERROR so this call will fail and write to Error log since errorlog switch parameter is on. Look Error_Log.txt file in PSLogs folder.

.EXAMPLE
Get-OSInfo -computers 'APP100001' -client "OK" -solution "FIN" -errorlog

Description
---------------------------------------
Test of computers parameter with one value. Parameter accepts array of strings.

.EXAMPLE
Get-OSInfo -computers 'APP100001', 'APP100002' -client "OK" -solution "FIN" -errorlog -Verbose

Description
---------------------------------------
Test of computers parameter with array of strings. Parameter accepts array of strings.

.EXAMPLE
Get-OSInfo -hosts 'APP100001' -client "OK" -solution "FIN" -errorlog

Description
---------------------------------------
Test of computers paramater alias hosts.

.EXAMPLE
Get-OSInfo -computers (Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" )) -client "OK" -solution "FIN" -errorlog -Verbose

Description
---------------------------------------
Test of computers parameter and values for parameter comes from .txt file that has list of servers.

.EXAMPLE
'APP100001' | Get-OSInfo -client "OK" -solution "FIN" -errorlog

Description
---------------------------------------
Test of pipeline by value of computers parameter.

.EXAMPLE
'APP100001', 'APP100002' | Get-OSInfo -client "OK" -solution "FIN" -errorlog -Verbose

Description
---------------------------------------
Test of pipeline by value with array of strings of computers parameter.

.EXAMPLE
'APP100001', 'APP100002' | Select-Object @{label="computers";expression={$_}} | Get-OSInfo -client "OK" -solution "FIN" -errorlog

Description
---------------------------------------
Test of values from pipeline by property name (computers).

.EXAMPLE
Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" ) | Get-OSInfo -client "OK" -solution "FIN" -errorlog -Verbose

Description
---------------------------------------
Test of pipeline by value that comes as content of .txt file with list of servers.

.EXAMPLE
Help Get-OSInfo -Full

Description
---------------------------------------
Test of Powershell help.

.EXAMPLE
Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose

Description
---------------------------------------
This is test of ParameterSet = FileName and parameter filename. There is list of servers in .txt file.

.EXAMPLE
Get-OSInfo -file "OKFINserverss.txt" -errorlog -client "OK" -solution "FIN" -Verbose

Description
---------------------------------------
This is test of ParameterSet = FileName and parameter filename. This test will fail due to wrong name of the .txt file with warning message "WARNING: This file path does NOT exist:".

.INPUTS
System.String

Computers parameter pipeline both by Value and by Property Name value and has default value of localhost. (Parameter Set = ComputerNames)
Filename parameter does not pipeline and does not have default value. (Parameter Set = FileName)
.OUTPUTS
System.Management.Automation.PSCustomObject

Get-OSInfo returns PSCustomObjects which has been converted from PowerShell function Get-CimInstance -Class CIM_OperatingSystem
Result shows following columns: Environment (PROD, Acceptance, Test, Course...), 
LogicalName (Application, web, integration, FTP, Scan, Terminal Server...), ServerName, Caption, CSDVersion, Version,
OSArchitecture, Install Date, Last BootUp Time, SystemDrive, WindowsDirectory, FreePhysicalMemory, FreeSpaceInPagingFiles, 
FreeVirtualMemory, NumberOfProcesses, NumberOfUsers, SizeStoredInPagingFile, TotalVirtualMemorySize, TotalVisibleMemorySize, IP

.NOTES
FunctionName : Get-OSInfo
Created by   : Dejan Mladenovic
Date Coded   : 10/31/2018 19:06:41
More info    : http://improvescripting.com/

.LINK 
How To Get Windows Operating System Details Using PowerShell
Get-CimInstance -Class CIM_OperatingSystem Get-CimInstance -Class Win32_OperatingSystem #> Function Get-OSInfo { [CmdletBinding(DefaultParametersetName="ServerNames")] param ( [Parameter( ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName="ServerNames", HelpMessage="List of computer names separated by commas.")] [Alias('hosts')] [string[]]$computers = 'localhost', [Parameter( ParameterSetName="FileName", HelpMessage="Name of txt file with list of servers. Txt file should be in 01servers folder.")] [string]$filename, [Parameter( Mandatory=$false, HelpMessage="Write to error log file or not.")] [switch]$errorlog, [Parameter(Mandatory=$true, HelpMessage="Client for example OK = O client, BK = B client")] [string]$client, [Parameter(Mandatory=$true, HelpMessage="Solution, for example FIN = Financial, HR = Human Resource")] [string]$solution ) BEGIN { if ( $PsCmdlet.ParameterSetName -eq "FileName") { if ( Test-Path -Path "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" -PathType Leaf ) { Write-Verbose "Read content from file: $filename" $computers = Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\$filename" ) } else { Write-Warning "This file path does NOT exist: $home\Documents\WindowsPowerShell\Modules\01servers\$filename" Write-Warning "Create file $filename in folder $home\Documents\WindowsPowerShell\Modules\01servers with list of server names." break; } } } PROCESS { foreach ($computer in $computers ) { if ( $computer -eq 'localhost' ) { $computer = $env:COMPUTERNAME } $computerinfo = Get-ComputerInfo -computername $computer -client $client -solution $solution $hostname = $computerinfo.hostname $env = $computerinfo.environment $logicalname = $computerinfo.logicalname $ip = $computerinfo.ipaddress try { Write-Verbose "Start processing: $computer - $env - $logicalname" Write-Verbose "Start CIM_OperatingSystem processing..." $OSInfos = $null $OSInfo = $null $obj = $null $params = @{ 'ComputerName'=$computer; 'Class'='CIM_OperatingSystem'; 'ErrorAction'='Stop'} #Values are already in kilobytes that is the reason to divide with megabytes to get gigabytes. $OSInfos = Get-CimInstance @params | Select-Object CSName, Caption, CSDVersion, Version, OSArchitecture, InstallDate, LastBootUpTime, SystemDrive, WindowsDirectory, @{Name="FreePhysicalMemory";Expression={("{0:N2}" -f($_.FreePhysicalMemory/1mb))}}, @{Name="FreeSpaceInPagingFiles";Expression={("{0:N2}" -f($_.FreeSpaceInPagingFiles/1mb))}}, @{Name="FreeVirtualMemory";Expression={("{0:N2}" -f($_.FreeVirtualMemory/1mb))}}, NumberOfProcesses, NumberOfUsers, @{Name="SizeStoredInPagingFiles";Expression={("{0:N2}" -f($_.SizeStoredInPagingFiles/1mb))}}, @{Name="TotalVirtualMemorySize";Expression={("{0:N2}" -f($_.TotalVirtualMemorySize/1mb))}}, @{Name="TotalVisibleMemorySize";Expression={("{0:N2}" -f($_.TotalVisibleMemorySize/1mb))}} Write-Verbose "Finish CIM_OperatingSystem processing..." foreach ($OSInfo in $OSInfos) { Write-Verbose "Start processing OS: $OSInfo" $properties = @{ 'Environment'=$env; 'Logical name'=$logicalname; 'Server name'=$OSInfo.CSName; 'Caption'=$OSInfo.Caption; 'Service pack'=$OSInfo.CSDVersion; 'Version'=$OSInfo.Version; 'OS Architecture'=$OSInfo.OSArchitecture; 'Install Date'=$OSInfo.InstallDate; 'Last BootUp Time'=$OSInfo.LastBootUpTime; 'System drive'=$OSInfo.SystemDrive; 'Windows directory'=$OSInfo.WindowsDirectory; 'Free RAM (GB)'=$OSInfo.FreePhysicalMemory; 'Free space in paging files (GB)'=$OSInfo.FreeSpaceInPagingFiles; 'Free virtual memory (GB)'=$OSInfo.FreeVirtualMemory; 'Number of processes'=$OSInfo.NumberOfProcesses; 'Number of users'=$OSInfo.NumberOfUsers; 'Size stored in paging file (GB)'=$OSInfo.SizeStoredInPagingFiles; 'Total virtual memory size (GB)'=$OSInfo.TotalVirtualMemorySize; 'Total visible memory size (GB)'=$OSInfo.TotalVisibleMemorySize; 'IP'=$ip; 'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)} $obj = New-Object -TypeName PSObject -Property $properties $obj.PSObject.TypeNames.Insert(0,'Report.OSInfo') Write-Output $obj Write-Verbose "Finish processing OS: $OSInfo" } Write-Verbose "Finish processing: $computer - $env - $logicalname" } catch { Write-Warning "Computer failed: $computer - $env - $logicalname OS failed: $OSInfo" Write-Warning "Error message: $_" if ( $errorlog ) { $errormsg = $_.ToString() $exception = $_.Exception $stacktrace = $_.ScriptStackTrace $failingline = $_.InvocationInfo.Line $positionmsg = $_.InvocationInfo.PositionMessage $pscommandpath = $_.InvocationInfo.PSCommandPath $failinglinenumber = $_.InvocationInfo.ScriptLineNumber $scriptname = $_.InvocationInfo.ScriptName $ErrorArguments = @{ 'hostname' = $computer; 'env' = $env; 'logicalname' = $logicalname; 'errormsg' = $errormsg; 'exception' = $exception; 'stacktrace'= $stacktrace; 'failingline' = $failingline; 'positionmsg' = $positionmsg; 'pscommandpath' = $pscommandpath; 'failinglinenumber' = $failinglinenumber; 'scriptname' = $scriptname } Write-Verbose "Start writing to Error log." Write-ErrorLog @ErrorArguments #Write-ErrorLog -hostname $computer -env $env -logicalname $logicalname -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace Write-Verbose "Finish writing to Error log." } } } } END { } } #Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Select-Object 'Environment', 'Logical Name', 'Server Name', 'Caption', 'Service pack', 'Version', 'OS Architecture', 'Install Date', 'Last BootUp Time', 'System drive', 'Windows directory', 'Free RAM (GB)', 'Free space in paging files (GB)', 'Free virtual memory (GB)', 'Number of processes', 'Number of users', 'Size stored in paging file (GB)', 'Total virtual memory size (GB)', 'Total visible memory size (GB)', 'IP', 'Collected' | Out-GridView <# #Test ParameterSet = ServerName Get-OSInfo -client "OK" -solution "FIN" Get-OSInfo -client "OK" -solution "FIN" -errorlog Get-OSInfo -client "OK" -solution "FIN" -errorlog -Verbose Get-OSInfo -computers 'APP100001' -client "OK" -solution "FIN" -errorlog Get-OSInfo -computers 'APP100001', 'APP100002' -client "OK" -solution "FIN" -errorlog -Verbose Get-OSInfo -hosts 'APP100001' -client "OK" -solution "FIN" -errorlog Get-OSInfo -computers (Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" )) -client "OK" -solution "FIN" -errorlog -Verbose #Pipeline examples 'APP100001' | Get-OSInfo -client "OK" -solution "FIN" -errorlog 'APP100001', 'APP100002' | Get-OSInfo -client "OK" -solution "FIN" -errorlog -Verbose 'APP100001', 'APP100002' | Select-Object @{label="computers";expression={$_}} | Get-OSInfo -client "OK" -solution "FIN" -errorlog Get-Content( "$home\Documents\WindowsPowerShell\Modules\01servers\OKFINservers.txt" ) | Get-OSInfo -client "OK" -solution "FIN" -errorlog -Verbose 'ERROR' | Get-OSInfo -client "OK" -solution "FIN" -errorlog #Test CmdLet help Help Get-OSInfo -Full #SaveToExcel Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Select-Object 'Environment', 'Logical Name', 'Server Name', 'Caption', 'Service pack', 'Version', 'OS Architecture', 'Install Date', 'Last BootUp Time', 'System drive', 'Windows directory', 'Free RAM (GB)', 'Free space in paging files (GB)', 'Free virtual memory (GB)', 'Number of processes', 'Number of users', 'Size stored in paging file (GB)', 'Total virtual memory size (GB)', 'Total visible memory size (GB)', 'IP', 'Collected' | Save-ToExcel -errorlog -ExcelFileName "Get-OSInfo" -title "Get OS info of servers in Financial solution for " -author "Dejan Mladenovic" -WorkSheetName "OS Info" -client "OK" -solution "FIN" #SaveToExcel and send email Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Select-Object 'Environment', 'Logical Name', 'Server Name', 'Caption', 'Service pack', 'Version', 'OS Architecture', 'Install Date', 'Last BootUp Time', 'System drive', 'Windows directory', 'Free RAM (GB)', 'Free space in paging files (GB)', 'Free virtual memory (GB)', 'Number of processes', 'Number of users', 'Size stored in paging file (GB)', 'Total virtual memory size (GB)', 'Total visible memory size (GB)', 'IP', 'Collected' | Save-ToExcel -sendemail -errorlog -ExcelFileName "Get-OSInfo" -title "Get OS info of servers in Financial solution for " -author "Dejan Mladenovic" -WorkSheetName "OS Info" -client "OK" -solution "FIN" #Benchmark #Time = 4 sec; Total Items = 28 Measure-BenchmarksCmdLet { Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose } #Time = 3,69 sec; Total Items = 28 Measure-BenchmarksCmdLet { Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" } #Baseline create Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Save-Baseline -errorlog -BaselineFileName "Get-OSInfo" -client "OK" -solution "FIN" -Verbose #Baseline archive and create new Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose | Save-Baseline -archive -errorlog -BaselineFileName "Get-OSInfo" -client "OK" -solution "FIN" -Verbose #Test ParameterSet = FileName Get-OSInfo -filename "OKFINservers.txt" -errorlog -client "OK" -solution "FIN" -Verbose Get-OSInfo -filename "OKFINserverss.txt" -errorlog -client "OK" -solution "FIN" -Verbose #>

About Dejan Mladenović

Post Author Dejan MladenovicHey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals!
I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials
About Me...

My Posts | Website

Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals! I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials About Me...

Recent Posts