When you land on a Windows box you have never seen before, the first question is always the same: what is this machine, what is it running, and when did it last restart. systeminfo answers all three in one screen, on every Windows install you are likely to meet, with nothing to deploy and nothing to enable.
It is also the tool people quietly get wrong. The output looks like a flat list of label and value pairs, so everyone pipes it through findstr and moves on. It is not flat: four of its fields spill onto indented continuation lines, three of those behind a count on the header line, three fields have a colon inside the label, seven have a colon inside the value, and the numbers arrive with a thousands separator already in them.
Microsoft’s reference documents five switches and shows no output at all. This article covers what the fields actually mean, which filters over-match and by how much, and which extraction method still works on a machine that is not configured like yours.
Applies to: Windows 10 / 11, Windows Server 2016 / 2019 / 2022 / 2025
Quick answer
Run it from any command prompt. No arguments, no elevation, no setup.
rem the whole report, around thirty fields
systeminfo
For one field, anchor the match to the start of the line with /B and pass the label as a literal with /C:. Both matter, and the section on extracting fields measures exactly what happens when you skip them.
rem /B anchors to the start of the line, /C: treats the whole string as one literal
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"System Boot Time"
For anything a script will read, take the CSV form instead and let a real CSV parser handle it. This is the single most useful line in the article.
# one record, with the field labels as property names
systeminfo /fo csv | ConvertFrom-Csv
/s, /u, /p, /fo and /nh are the complete list.
What systeminfo does
It collects operating system configuration, security information, product ID and hardware properties, and prints them as one report. Microsoft’s syntax line is short enough to quote in full.
systeminfo [/s <computer> [/u <domain>\<username> [/p <password>]]] [/fo {TABLE | LIST | CSV}] [/nh]
| Switch | What it does |
|---|---|
/s computer | Name or IP address of a remote computer. Do not use backslashes. Defaults to the local computer. |
/u domain\user | Runs the command with that account’s permissions. Without it, the credentials of the user issuing the command are used. |
/p password | The password for the account given in /u. |
/fo format | TABLE, LIST or CSV. LIST is the default shape you see when you run it bare. |
/nh | Suppresses column headers. Valid only with /fo TABLE or /fo CSV. |
/p sits in the command line, which means it is visible in the process list while the command runs and stays in the CMD history for that session. Prefer running the whole job under an account that already has access, so neither /u nor /p is needed.
Reading the output
Microsoft’s reference carries no sample output on any page. The listing below is a real report posted on Microsoft Q&A by an admin asking why Windows would not show him the Hyper-V features; only the whitespace has been normalised back to the columns systeminfo actually prints. It is worth reading in full before the explanation, because almost every trap in this article is visible in it.
Host Name: DESKTOP-GJA03F2
OS Name: Microsoft Windows 10 Pro
OS Version: 10.0.14393 N/A Build 14393
OS Manufacturer: Microsoft Corporation
OS Configuration: Standalone Workstation
OS Build Type: Multiprocessor Free
Registered Owner: Windows User
Registered Organization:
Product ID: 00331-20210-14994-AA953
Original Install Date: 2021-09-07, 오후 3:44:32
System Boot Time: 2021-09-09, 오전 10:34:55
System Manufacturer: System manufacturer
System Model: System Product Name
System Type: x64-based PC
Processor(s): 1 Processor(s) Installed.
[01]: AMD64 Family 25 Model 33 Stepping 0 AuthenticAMD ~3693 Mhz
BIOS Version: American Megatrends Inc. 3603, 2021-03-20
Windows Directory: C:\Windows
System Directory: C:\Windows\system32
Boot Device: \Device\HarddiskVolume2
System Locale: ko;Korean
Input Locale: ko;Korean
Time Zone: (UTC+09:00) Seoul
Total Physical Memory: 65,442 MB
Available Physical Memory: 54,224 MB
Virtual Memory: Max Size: 75,170 MB
Virtual Memory: Available: 62,953 MB
Virtual Memory: In Use: 12,217 MB
Page File Location(s): C:\pagefile.sys
Domain: WORKGROUP
Logon Server: \\DESKTOP-GJA03F2
Hotfix(s): 9 Hotfix(s) Installed.
[01]: KB3194623
[02]: KB3199986
[03]: KB3202790
[04]: KB4033631
[05]: KB4049411
[06]: KB4093137
[07]: KB4132216
[08]: KB4134659
[09]: KB4093119
Network Card(s): 1 NIC(s) Installed.
[01]: Intel(R) I211 Gigabit Network Connection
Connection Name: Ethernet
DHCP Enabled: Yes
DHCP Server: 172.23.238.129
IP address(es)
[01]: 211.213.99.166
[02]: fe80::6ce3:a5d4:ba74:67a5
Hyper-V Requirements: VM Monitor Mode Extensions: Yes
Virtualization Enabled In Firmware: No
Second Level Address Translation: Yes
Data Execution Prevention Available: Yes
Most of those labels explain themselves. These are the ones that carry more than they appear to.
| Field | What it actually tells you |
|---|---|
OS Version | The build number is the part that identifies the release. “Microsoft Windows 10 Pro” covers ten years of builds; 10.0.14393 pins it to one. |
OS Configuration | Standalone Workstation, Member Server, Primary Domain Controller. The fastest way to tell what role a server is playing. |
System Boot Time | Uptime, without touching anything. A number that disagrees with the change record is the start of an interesting conversation. |
System Manufacturer and System Model | Physical or virtual, and which hypervisor. VMware, Inc. / VMware7,1 and Microsoft Corporation / Virtual Machine are the two you will see most. |
Domain | WORKGROUP means the machine is not domain joined at all, which is worth knowing before you spend an hour on a Kerberos theory. |
Logon Server | The domain controller that authenticated the current session, not a configured setting. On the sample above it is the machine itself, because there is no domain. |
Hotfix(s) | A count, then one indented entry per KB. Useful as a rough patch level, not as a patch audit: see the limitations at the end. |
Hyper-V Requirements | A four-line firmware diagnostic, and the reason a lot of people run this command at all. |
The structural fact that matters most is not in that table. Four fields are not single lines at all: Processor(s), Hotfix(s), Network Card(s) and Hyper-V Requirements each print a header line and then spill onto indented continuation lines. In the sample above that is 1, 9, 7 and 3 continuation lines respectively. Every parsing mistake later in this article traces back to those indented lines.
Virtual Memory: fields have a colon inside the label, and seven other fields have a colon inside the value. There is no single colon in the output that reliably separates label from value, which is why the naive split fails in a way that is measured further down.
Practical examples
1. Identify a machine you have just been given
The problem: someone hands you an RDP session and a vague description. You need the build, the role and the hardware before you touch anything.
The solution: five labels answer it. Pass each one as its own /C: string so they are matched literally rather than as a pattern.
systeminfo | findstr /B /C:"OS Name" /C:"OS Version" /C:"OS Configuration" /C:"System Manufacturer" /C:"System Model"
Against the sample report above that returns exactly those five lines and nothing else. Drop the /B and you also pick up any line whose value happens to contain one of those words, which is the subject of the next section.
2. Get uptime without rebooting anything
The problem: a service is misbehaving and you want to know whether the box restarted overnight.
The solution: read System Boot Time. It is the one field people reach for most, and it is also the one you should stop parsing as soon as a script is involved, for reasons covered in the hidden gems.
systeminfo | findstr /B /C:"System Boot Time"
When you need the answer as a number rather than as text, get it from CIM, which returns a real DateTime and does not care how the machine formats dates.
# LastBootUpTime comes back as a DateTime, so the subtraction just works
$boot = (Get-CimInstance Win32_OperatingSystem).LastBootUpTime
$up = (Get-Date) - $boot
"Booted {0} | up {1}d {2}h {3}m" -f $boot, [int]$up.TotalDays, $up.Hours, $up.Minutes
3. Decide whether a host is physical or virtual
The problem: an inventory spreadsheet says a server is physical and you do not believe it.
The solution: the manufacturer string is set by the firmware, so a hypervisor cannot hide behind a hostname.
systeminfo | findstr /B /C:"System Manufacturer" /C:"System Model" /C:"BIOS Version"
A BIOS Version naming VMware or a Hyper-V UEFI release settles it even when the manufacturer field has been customised by an OEM image.
4. Take a rough patch level
The problem: you want to know roughly how far behind a machine is before opening the update history.
The solution: the count sits on the header line and the KB numbers sit on the indented lines below it, so the two need different filters. Neither line contains the other’s search word, which is what makes them cleanly separable.
rem the header line only: "9 Hotfix(s) Installed."
systeminfo | findstr /B /C:"Hotfix"
rem and this way round for the KB numbers, because the entries are indented
systeminfo | findstr /C:"KB"
Get-HotFix, and the update history itself, are the tools for a real answer.
5. Inventory a list of machines into one CSV
The problem: forty servers, and someone wants build numbers and RAM in a spreadsheet by lunchtime.
The solution: /s queries a remote machine without any PowerShell remoting setup, and /fo csv means the result needs no parsing at all. Put the hostnames one per line in a text file first.
# hosts.txt is one hostname per line
Get-Content .\hosts.txt | ForEach-Object {
$name = $_
try {
systeminfo /s $name /fo csv 2>$null |
ConvertFrom-Csv |
Select-Object 'Host Name', 'OS Name', 'OS Version', 'Total Physical Memory', 'System Boot Time'
}
catch {
# keep unreachable hosts in the report instead of silently losing them
[pscustomobject]@{ 'Host Name' = $name; 'OS Name' = 'UNREACHABLE' }
}
} | Export-Csv .\inventory.csv -NoTypeInformation
Nothing in that loop is left behind on the machines it touched, and the only file it creates is the CSV in the folder you ran it from.
Extracting fields without breaking
Every figure in this section was measured against the sample report above, so you can rerun any of them yourself.
Start with the filter everybody writes first. findstr matches substrings anywhere on the line, and the output is full of labels that are prefixes of other labels and values that contain label words.
rem returns 4 lines, and only two of them are what you meant
systeminfo | findstr /C:"Name"
Host Name: DESKTOP-GJA03F2
OS Name: Microsoft Windows 10 Pro
System Model: System Product Name
Connection Name: Ethernet
The third line matched because the value ends in the word Name. The fourth is an indented sub-field of the network card block. Adding /B anchors the match to the start of the line, which removes both, and also demonstrates why you must then give the full label: no line begins with the bare word Name, so findstr /B /C:"Name" returns nothing at all.
/C:"Name" returns 4 lines, /B /C:"Name" returns 0, and /B /C:"OS Name" returns exactly 1. Anchoring turns a fuzzy filter into an exact one, at the cost of having to type the label in full.
The same anchor is what separates a header line from its continuation lines, and it works in both directions. The nine KB entries are indented, so /B excludes them; without /B you get them and not the header.
| Filter | Lines returned from the sample | Why |
|---|---|---|
findstr /C:"Name" | 4 | Two real labels, one value ending in “Name”, one indented sub-field |
findstr /B /C:"Name" | 0 | No line starts with the bare word |
findstr /C:"Memory" | 5 | Two physical memory fields plus all three Virtual Memory fields |
findstr /B /C:"Hotfix" | 1 | The header line carrying the count |
findstr /C:"KB" | 9 | The indented entries |
findstr /B /C:"KB" | 0 | The entries are indented, so nothing starts with KB |
Now the split. The obvious way to turn the report into label and value pairs in CMD is for /f with a colon delimiter, taking the first token as the label and everything after it as the value.
rem run this from a prompt; in a .bat file the variable is %%a, not %a
for /f "tokens=1,* delims=:" %a in ('systeminfo') do @echo [%a] %b
That handles the seven fields whose values contain a colon correctly, because * takes the rest of the line verbatim: Time Zone keeps (UTC+09:00) Seoul, System Boot Time keeps its clock time, and Windows Directory keeps C:\Windows. Where it fails is the other direction.
Virtual Memory: fields have a colon inside the label, so the first token stops early. All three come back as the key Virtual Memory with values Max Size: 75,170 MB, Available: 62,953 MB and In Use: 12,217 MB. Load that into a hashtable or a dictionary and two of the three are silently overwritten.
And when you do reach a number, it is not one yet. Memory is printed with a thousands separator, so a direct numeric cast fails on every locale that uses one.
# "65,442 MB" is a string with a separator in it, not a number
$raw = '65,442 MB'
$mb = [int]($raw -replace '[^\d]','')
"{0} MB = {1} GB" -f $mb, [math]::Round($mb/1024, 1)
65442 MB = 63.9 GB
Every one of those problems disappears if you stop parsing the list form. /fo csv emits a header row and one data row, and a CSV parser already knows how to handle a quoted field that contains a comma. The naive alternative does not.
# splitting a CSV row on every comma finds 7 fields where there are 4,
# because the memory value and the hotfix list both contain commas
$row = '"DESKTOP-GJA03F2","Microsoft Windows 10 Pro","65,442 MB","KB3194623,KB3199986,KB3202790"'
($row -split ',').Count # 7
# ConvertFrom-Csv gets it right, and gives you named properties
$o = systeminfo /fo csv | ConvertFrom-Csv
$o.'Total Physical Memory'
$o.'OS Version'
Note the quoted property names. The labels become property names verbatim, spaces and parentheses included, so $o.'Host Name' and $o.'Hotfix(s)' need the quotes and $o.HostName does not exist.
Hidden gems
The find in your PATH may not be Windows find
A step in Microsoft’s WSL setup documentation had people run systeminfo | find "System Type" to check their build. Someone opened an issue on the documentation repository because it did not work for them:
/usr/bin/find: 'System Type': No such file or directory
Their PATH had a Unix find ahead of the Windows one, installed by Cygwin or a similar toolchain, and the Unix find treats the argument as a directory to search rather than as a string to match. The suggested workaround in the thread was the absolute path, systeminfo | c:\windows\system32\find "System Type".
findstr instead. There is no Unix command by that name, so it cannot be shadowed the way find, sort and more can on a developer workstation. That is the real reason every example on this page uses it.
The labels are English, the values are not
Look again at the reproduced report. System Locale is ko;Korean, and both timestamps carry Korean markers, yet every label down the left is in English. Label language and value formatting are two different things, and only one of them is stable.
Original Install Date: 2021-09-07, 오후 3:44:32
System Boot Time: 2021-09-09, 오전 10:34:55
The practical consequence is narrow but sharp: a findstr filter keyed on an English label survived this machine, but any code that parsed that timestamp with a fixed format string would have failed on it. If a script needs the boot time as a value rather than as text, take it from Win32_OperatingSystem as shown earlier and never touch the string.
Hyper-V Requirements is a firmware diagnostic
This is why the admin in the reproduced thread was running the command. Windows would not offer him Virtual Machine Platform or Windows Hypervisor Platform, and the answer was sitting in the second line of the block:
Hyper-V Requirements: VM Monitor Mode Extensions: Yes
Virtualization Enabled In Firmware: No
Second Level Address Translation: Yes
Data Execution Prevention Available: Yes
Three of the four requirements were met and the fourth was a UEFI setting, so no amount of clicking in Windows Features was going to help. The accepted answer was to go into the firmware and turn virtualization on.
A hypervisor has been detected. Features required for Hyper-V will not be displayed. That is not a fault and not a refusal. Something is already using the hypervisor, commonly Hyper-V itself, WSL 2 or a virtualization-based security feature, so the four requirement lines have nothing left to report.
A count on a header line is still a field you can read
Three of the four multi-line fields put a number in front of their list, which means you can answer “how many” without parsing the list at all. In CSV form those same fields arrive as one comma-joined string, so the count comes from a split instead.
# the header line carries the count: "9 Hotfix(s) Installed."
$o = systeminfo /fo csv | ConvertFrom-Csv
($o.'Hotfix(s)' -split ',').Count
The same shape gives you the NIC count and the processor count, which is often all an inventory row needs. A machine that reports two processors and eight NICs is telling you something about its role before you look at anything else.
PowerShell equivalents
Get-ComputerInfo is the native equivalent and returns a single object with typed properties, so nothing has to be parsed. Microsoft documents it as Windows only, available from Windows PowerShell 5.1 onwards, with a -Property parameter that accepts wildcards.
# -Property takes wildcards, which is the fastest way to find a property you half remember
Get-ComputerInfo -Property 'Os*Version', 'CsName', 'CsManufacturer', 'CsModel'
# every property with "bios" in the name
Get-ComputerInfo -Property '*bios*'
| Task | CMD | PowerShell |
|---|---|---|
| Whole report | systeminfo | Get-ComputerInfo |
| Machine-readable | systeminfo /fo csv | Get-ComputerInfo (already objects) |
| OS build | findstr /B /C:"OS Version" | (Get-ComputerInfo).OsVersion |
| Boot time | findstr /B /C:"System Boot Time" | (Get-CimInstance Win32_OperatingSystem).LastBootUpTime |
| Installed hotfixes | findstr /C:"KB" | Get-HotFix |
| A remote host | systeminfo /s SRV01 | Get-CimInstance -ComputerName SRV01 |
There is one reason to keep reaching for the old tool. Get-ComputerInfo has no remote parameter at all, so querying another machine means PowerShell remoting must already be configured and working. systeminfo /s has its own remote path and needs none of that, which is why it is still the faster answer on a network you have just been handed.
# no remoting configured: this still works
systeminfo /s SRV-APP-01 /fo csv | ConvertFrom-Csv | Select-Object 'Host Name', 'OS Version'
Where this matters
- Taking over an undocumented estate: one command per host gives you build, role, hardware and domain membership, which is enough to build a first inventory before anything is installed.
- A vendor asks what you are running: the OS Version build number and the hotfix count are usually the two things they actually need, and both are one filter away.
- An application will not enable virtualization features: the Hyper-V Requirements block says whether the blocker is firmware, hardware or another hypervisor, which decides whether you reboot into UEFI or stop looking.
- An unexplained restart: System Boot Time against the change record, then the event log for the reason.
- A capacity question: Total Physical Memory across a fleet, exported once, beats asking forty people.
- You suspect an inventory record is wrong: System Manufacturer comes from the firmware, so it does not inherit whatever a spreadsheet claims.
Tips and limitations
- The hotfix list is not a patch audit. A machine serviced by cumulative updates can report a short list and still be fully current, so use it as a signal and confirm with
Get-HotFixor the update history. - Four fields are multi-line:
Processor(s),Hotfix(s),Network Card(s)andHyper-V Requirements. Any line-by-line parser has to decide what to do with indented continuation lines before it does anything else. - Microsoft documents the switches only in their slash form, and
/nhis valid only with/fo TABLEor/fo CSV. It does nothing to the default list output. - Values are formatted for the machine, not for your script. Memory carries a thousands separator and timestamps follow the system locale, so cast and parse defensively or take the value from CIM instead.
- A password on the command line is exposed to the process list. Prefer running under an account that already has access over passing
/uand/p. - The report describes the operating system’s view of the hardware. On a virtual machine every hardware figure is what the hypervisor presented, which is the answer you usually want, but it is not the physical host.
Get-ComputerInfois Windows only and has no remote parameter. When remoting is not set up,systeminfo /sis the tool that still works.
Official documentation
- systeminfo: Windows Commands | Microsoft Learn
- Get-ComputerInfo | Microsoft Learn
- findstr: Windows Commands | Microsoft Learn
- for /f: Windows Commands | Microsoft Learn
Related tools
- System tools: the rest of the local diagnostic utilities on this site, in one place.
- Event log analyzer: when System Boot Time shows a restart you did not plan, this is where the reason is.
Related guides
- Windows command aliases with doskey: turns the filters on this page into two-word commands you actually remember.
- WMIC vs PowerShell: where the deprecated tool sat, and why CIM is the place to get typed values.
- tasklist and taskkill in Windows: the same inventory instinct applied to processes rather than to the host.
- certutil for encoding and decoding: how to get a captured report off a machine that has no file share.
- Windows Command Line (CMD) Cheat Sheet: the one-line forms of these commands alongside the rest of the set.
- PowerShell Commands Cheat Sheet: the object-based equivalents, including Get-ComputerInfo.
- findstr and find in Windows: the ten metacharacters behind the anchored filters on this page, and the shadowed find in detail.