Determining Device Type with WMI: A Comprehensive Guide to Windows Management Instrumentation Classes
In modern IT environments, the ability to programmatically identify a device's form factor—whether it's a desktop, laptop, tablet, or server—is crucial for effective system management. This capability enables administrators to apply appropriate configurations, power settings, and security policies based on the physical characteristics of the device.
The purpose of this article is to explore multiple Windows Management Instrumentation (WMI) classes that can be used to determine a device's form factor. We'll start with the basic approach using Win32_Battery, then progress to more reliable methods using Win32_SystemEnclosure and Win32_ComputerSystem, providing technical details and practical code examples for each.
A common initial approach to determining whether a device is a laptop or desktop involves checking for the presence of a battery. The logic is straightforward: systems with batteries are likely portable devices (laptops, tablets), while those without are likely stationary (desktops, servers).
For this purpose, we can use the Win32_Battery WMI class, which represents batteries connected to the computer system.
[Dynamic, Provider("CIMWin32"), UUID("{8502C4B9-5FBB-11D2-AAC1-006008C78BC7}"), AMENDMENT]
class Win32_Battery : CIM_Battery
{
uint16 Availability;
uint32 BatteryRechargeTime;
uint16 BatteryStatus;
string Caption;
uint16 Chemistry;
uint32 ConfigManagerErrorCode;
boolean ConfigManagerUserConfig;
string CreationClassName;
string Description;
uint32 DesignCapacity;
uint64 DesignVoltage;
string DeviceID;
boolean ErrorCleared;
string ErrorDescription;
uint16 EstimatedChargeRemaining;
uint32 EstimatedRunTime;
uint32 ExpectedBatteryLife;
uint32 ExpectedLife;
uint32 FullChargeCapacity;
datetime InstallDate;
uint32 LastErrorCode;
uint32 MaxRechargeTime;
string Name;
string PNPDeviceID;
uint16 PowerManagementCapabilities[];
boolean PowerManagementSupported;
string SmartBatteryVersion;
string Status;
uint16 StatusInfo;
string SystemCreationClassName;
string SystemName;
uint32 TimeOnBattery;
uint32 TimeToFullCharge;
};
The Win32_Battery class contains numerous properties that provide detailed information about the system's battery. Some of the most relevant properties for our purpose include:
- Availability: Indicates the primary status of the battery
- BatteryStatus: Current status of the battery (e.g., charging, discharging)
- DesignCapacity: Design capacity of the battery in mWh
- EstimatedChargeRemaining: Estimated percentage of charge remaining
- FullChargeCapacity: Full charge capacity of the battery in mWh
- TimeToFullCharge: Estimated time to full charge in minutes
Here's a PowerShell script that uses the Win32_Battery WMI class to determine if a device is likely a laptop:
function Test-IsLaptopByBattery {
$battery = Get-WmiObject -Class Win32_Battery
if ($battery) {
Write-Output "Battery detected. This is likely a laptop or portable device."
Write-Output "Battery details:"
Write-Output " - Status: $($battery.BatteryStatus)"
Write-Output " - Charge remaining: $($battery.EstimatedChargeRemaining)%"
Write-Output " - Full charge capacity: $($battery.FullChargeCapacity) mWh"
return $true
} else {
Write-Output "No battery detected. This is likely a desktop or server."
return $false
}
}
# Call the function
Test-IsLaptopByBatteryWhile the battery detection method is simple to implement, it has several significant limitations:
-
Uninterruptible Power Supplies (UPS): Desktop systems connected to a UPS may report a
Win32_Batteryinstance, leading to false positives. -
Faulty or Removed Batteries: Laptops with completely dead, removed, or malfunctioning batteries may not report any
Win32_Batteryinstances, resulting in false negatives. -
Virtual Machines: The behavior of
Win32_Batteryin virtual environments varies widely:- Some hypervisors don't expose battery information to VMs at all
- Others may pass through the host's battery information
- Some may provide simulated battery data for testing purposes
-
Form Factor Granularity: This method only provides a binary classification (has battery/doesn't have battery) and cannot distinguish between different portable form factors (laptop vs. tablet vs. convertible).
-
Modern Desktop Configurations: All-in-one desktops with built-in batteries or backup power systems may report as laptops.
For these reasons, while Win32_Battery is useful for monitoring battery status, it's not the most reliable method for determining a device's physical form factor. Let's explore more robust alternatives.
The Win32_SystemEnclosure WMI class is widely considered the industry standard for determining a device's physical form factor. This class represents the properties associated with a physical system enclosure and inherits from the CIM_Chassis class.
[Dynamic, Provider("CIMWin32"), UUID("{FAF76B94-798C-11D2-AAD1-006008C78BC7}"), AMENDMENT]
class Win32_SystemEnclosure : CIM_Chassis {
boolean AudibleAlarm;
string BreachDescription;
string CableManagementStrategy;
string Caption;
uint16 ChassisTypes[];
string CreationClassName;
sint16 CurrentRequiredOrProduced;
real32 Depth;
string Description;
uint16 HeatGeneration;
real32 Height;
boolean HotSwappable;
datetime InstallDate;
boolean LockPresent;
string Manufacturer;
string Model;
string Name;
uint16 NumberOfPowerCords;
string OtherIdentifyingInfo;
string PartNumber;
boolean PoweredOn;
boolean Removable;
boolean Replaceable;
uint16 SecurityBreach;
uint16 SecurityStatus;
string SerialNumber;
string ServiceDescriptions[];
uint16 ServicePhilosophy[];
string SKU;
string SMBIOSAssetTag;
string Status;
string Tag;
string TypeDescriptions[];
string Version;
boolean VisibleAlarm;
real32 Weight;
real32 Width;
};
The key property for our purpose is ChassisTypes, which is an array of unsigned 16-bit integers (uint16[]). This property indicates the type(s) of the system enclosure. While it's defined as an array, most standard PCs will have only one value.
The numeric values in ChassisTypes correspond to specific physical form factors defined by the Distributed Management Task Force (DMTF) and are implemented in the system's BIOS or firmware. Here's a comprehensive mapping of these values:
| Value | Description | Category |
|---|---|---|
| 1 | Other | Special |
| 2 | Unknown | Special |
| 3 | Desktop | Desktop |
| 4 | Low Profile Desktop | Desktop |
| 5 | Pizza Box | Desktop |
| 6 | Mini Tower | Desktop |
| 7 | Tower | Desktop |
| 8 | Portable | Laptop |
| 9 | Laptop | Laptop |
| 10 | Notebook | Laptop |
| 11 | Hand Held | Mobile |
| 12 | Docking Station | Accessory |
| 13 | All in One | Desktop |
| 14 | Sub Notebook | Laptop |
| 15 | Space-Saving | Desktop |
| 16 | Lunch Box | Portable |
| 17 | Main System Chassis | Server |
| 18 | Expansion Chassis | Accessory |
| 19 | SubChassis | Component |
| 20 | Bus Expansion Chassis | Component |
| 21 | Peripheral Chassis | Accessory |
| 22 | RAID Chassis | Storage |
| 23 | Rack Mount Chassis | Server |
| 24 | Sealed-Case PC | Embedded |
| 25 | Multi-system chassis | Server |
| 26 | Compact PCI | Embedded |
| 27 | Advanced TCA | Embedded |
| 28 | Blade | Server |
| 29 | Blade Enclosure | Server |
| 30 | Tablet | Mobile |
| 31 | Convertible | Mobile |
| 32 | Detachable | Mobile |
| 33 | IoT Gateway | Embedded |
| 34 | Embedded PC | Embedded |
| 35 | Mini PC | Desktop |
| 36 | Stick PC | Desktop |
For practical purposes, we can group these values into broader categories:
- Desktop Systems: 3, 4, 5, 6, 7, 13, 15, 35, 36
- Laptop/Portable Systems: 8, 9, 10, 14
- Mobile Devices: 11, 30, 31, 32
- Server Systems: 17, 23, 25, 28, 29
- Embedded Systems: 24, 26, 27, 33, 34
Here's a PowerShell script that uses the Win32_SystemEnclosure WMI class to determine a device's form factor:
function Get-DeviceFormFactor {
$chassisInfo = Get-CimInstance -ClassName Win32_SystemEnclosure
$chassisTypes = $chassisInfo.ChassisTypes
# Initialize form factor variables
$formFactor = "Unknown"
$isLaptop = $false
$isDesktop = $false
$isServer = $false
$isMobile = $false
# Define chassis type groups
$laptopTypes = @(8, 9, 10, 14)
$desktopTypes = @(3, 4, 5, 6, 7, 13, 15, 35, 36)
$serverTypes = @(17, 23, 25, 28, 29)
$mobileTypes = @(11, 30, 31, 32)
# Check each chassis type in the array
foreach ($type in $chassisTypes) {
# Convert type to descriptive string
$typeDescription = switch ($type) {
1 { "Other"; break }
2 { "Unknown"; break }
3 { "Desktop"; $isDesktop = $true; break }
4 { "Low Profile Desktop"; $isDesktop = $true; break }
5 { "Pizza Box"; $isDesktop = $true; break }
6 { "Mini Tower"; $isDesktop = $true; break }
7 { "Tower"; $isDesktop = $true; break }
8 { "Portable"; $isLaptop = $true; break }
9 { "Laptop"; $isLaptop = $true; break }
10 { "Notebook"; $isLaptop = $true; break }
11 { "Hand Held"; $isMobile = $true; break }
12 { "Docking Station"; break }
13 { "All in One"; $isDesktop = $true; break }
14 { "Sub Notebook"; $isLaptop = $true; break }
15 { "Space-Saving"; $isDesktop = $true; break }
16 { "Lunch Box"; break }
17 { "Main System Chassis"; $isServer = $true; break }
18 { "Expansion Chassis"; break }
19 { "SubChassis"; break }
20 { "Bus Expansion Chassis"; break }
21 { "Peripheral Chassis"; break }
22 { "RAID Chassis"; break }
23 { "Rack Mount Chassis"; $isServer = $true; break }
24 { "Sealed-Case PC"; break }
25 { "Multi-system chassis"; $isServer = $true; break }
26 { "Compact PCI"; break }
27 { "Advanced TCA"; break }
28 { "Blade"; $isServer = $true; break }
29 { "Blade Enclosure"; $isServer = $true; break }
30 { "Tablet"; $isMobile = $true; break }
31 { "Convertible"; $isMobile = $true; break }
32 { "Detachable"; $isMobile = $true; break }
33 { "IoT Gateway"; break }
34 { "Embedded PC"; break }
35 { "Mini PC"; $isDesktop = $true; break }
36 { "Stick PC"; $isDesktop = $true; break }
default { "Unknown Type: $type"; break }
}
# Set primary form factor based on first match
if ($formFactor -eq "Unknown") {
if ($isLaptop) { $formFactor = "Laptop" }
elseif ($isDesktop) { $formFactor = "Desktop" }
elseif ($isServer) { $formFactor = "Server" }
elseif ($isMobile) { $formFactor = "Mobile Device" }
}
Write-Output "Chassis Type: $type - $typeDescription"
}
# Return the results
return [PSCustomObject]@{
FormFactor = $formFactor
ChassisTypes = $chassisTypes
ChassisTypeDescriptions = $typeDescription
IsLaptop = $isLaptop
IsDesktop = $isDesktop
IsServer = $isServer
IsMobile = $isMobile
Manufacturer = $chassisInfo.Manufacturer
Model = $chassisInfo.Model
SerialNumber = $chassisInfo.SerialNumber
}
}
# Call the function
$deviceInfo = Get-DeviceFormFactor
Write-Output "This device is a: $($deviceInfo.FormFactor)"This script not only identifies the device type but also provides additional information about the system enclosure, including manufacturer, model, and serial number.
The Win32_SystemEnclosure method offers several advantages over the Win32_Battery approach:
-
Direct Hardware Identification: It directly queries the system's reported chassis type, which is set by the manufacturer based on the hardware design.
-
Granular Classification: It can distinguish between various form factors (desktop, tower, laptop, notebook, tablet, etc.) rather than just a binary portable/non-portable classification.
-
Reliability: It's not affected by the presence or absence of peripherals or power sources.
-
Standardization: The chassis type values are standardized by the DMTF and implemented consistently across manufacturers.
For these reasons, Win32_SystemEnclosure.ChassisTypes is generally considered the most reliable method for determining a device's physical form factor.
While Win32_SystemEnclosure provides the most direct information about the physical chassis, the Win32_ComputerSystem WMI class offers supplementary details about the system role and type, which can further refine our understanding.
This class represents the computer system as a whole, including its role in a network and general system characteristics.
[Dynamic, Provider("CIMWin32"), SupportsUpdate, UUID("{8502C4B0-5FBB-11D2-AAC1-006008C78BC7}"), AMENDMENT]
class Win32_ComputerSystem : CIM_UnitaryComputerSystem {
uint16 AdminPasswordStatus;
boolean AutomaticManagedPagefile;
boolean AutomaticResetBootOption;
boolean AutomaticResetCapability;
uint16 BootOptionOnLimit;
uint16 BootOptionOnWatchDog;
boolean BootROMSupported;
string BootupState;
uint16 BootStatus[];
string Caption;
uint16 ChassisBootupState;
string ChassisSKUNumber;
string CreationClassName;
sint16 CurrentTimeZone;
boolean DaylightInEffect;
string Description;
string DNSHostName;
string Domain;
uint16 DomainRole;
boolean EnableDaylightSavingsTime;
uint16 FrontPanelResetStatus;
boolean HypervisorPresent;
boolean InfraredSupported;
string InitialLoadInfo[];
datetime InstallDate;
uint16 KeyboardPasswordStatus;
string LastLoadInfo;
string Manufacturer;
string Model;
string Name;
string NameFormat;
boolean NetworkServerModeEnabled;
uint32 NumberOfLogicalProcessors;
uint32 NumberOfProcessors;
uint8 OEMLogoBitmap[];
string OEMStringArray[];
boolean PartOfDomain;
sint64 PauseAfterReset;
uint16 PCSystemType;
uint16 PCSystemTypeEx;
uint16 PowerManagementCapabilities[];
boolean PowerManagementSupported;
uint16 PowerOnPasswordStatus;
uint16 PowerState;
uint16 PowerSupplyState;
string PrimaryOwnerContact;
string PrimaryOwnerName;
uint16 ResetCapability;
sint16 ResetCount;
sint16 ResetLimit;
string Roles[];
string Status;
string SupportContactDescription[];
string SystemFamily;
string SystemSKUNumber;
uint16 SystemStartupDelay;
string SystemStartupOptions[];
uint8 SystemStartupSetting;
string SystemType;
uint16 ThermalState;
uint64 TotalPhysicalMemory;
string UserName;
uint16 WakeUpType;
string Workgroup;
};
Two properties within Win32_ComputerSystem are particularly relevant for identifying the system type:
- PCSystemType: Indicates the general type of the computer system.
- PCSystemTypeEx: Provides a more detailed classification, often aligning closely with
PCSystemTypebut potentially offering more specific information on newer hardware.
Here are the common values for these properties:
| Value | PCSystemType Description | PCSystemTypeEx Description |
|---|---|---|
| 0 | Unspecified | Unspecified |
| 1 | Desktop | Desktop |
| 2 | Mobile | Mobile |
| 3 | Workstation | Workstation |
| 4 | Enterprise Server | Enterprise Server |
| 5 | SOHO Server | SOHO Server |
| 6 | Appliance PC | Appliance PC |
| 7 | Performance Server | Performance Server |
| 8 | Slate | Maximum (Tablet) |
| 9 | Maximum | Convertible |
| 10 | Detachable |
Comparison with ChassisTypes:
PCSystemType/PCSystemTypeExoften correlate withChassisTypes(e.g.,PCSystemType= 2 (Mobile) often corresponds toChassisTypesvalues like 9 (Laptop) or 10 (Notebook)).- However, they represent slightly different aspects.
ChassisTypesdescribes the physical enclosure, whilePCSystemTypedescribes the intended role or category of the system. - Discrepancies can occur. For example, a powerful workstation (
PCSystemType= 3) might be housed in a standard Tower chassis (ChassisTypes= 7). PCSystemTypeExintroduced newer values like Slate, Convertible, and Detachable, which directly map to specific mobile form factors.
Other Useful Properties:
- Manufacturer: System manufacturer (e.g., "Dell Inc.", "HP").
- Model: System model name or number (e.g., "Latitude 7400", "EliteBook 840 G5").
- DomainRole: Indicates the system's role in a domain (e.g., Standalone Workstation, Member Workstation, Domain Controller).
- SystemFamily: A string indicating the product family (e.g., "Latitude", "ThinkPad").
function Get-SystemTypeInfo {
$systemInfo = Get-CimInstance -ClassName Win32_ComputerSystem
$pcSystemTypeDescription = switch ($systemInfo.PCSystemType) {
0 { "Unspecified" }
1 { "Desktop" }
2 { "Mobile" }
3 { "Workstation" }
4 { "Enterprise Server" }
5 { "SOHO Server" }
6 { "Appliance PC" }
7 { "Performance Server" }
default { "Unknown Type: $($systemInfo.PCSystemType)" }
}
$pcSystemTypeExDescription = switch ($systemInfo.PCSystemTypeEx) {
0 { "Unspecified" }
1 { "Desktop" }
2 { "Mobile" }
3 { "Workstation" }
4 { "Enterprise Server" }
5 { "SOHO Server" }
6 { "Appliance PC" }
7 { "Performance Server" }
8 { "Slate (Tablet)" }
9 { "Convertible" }
10 { "Detachable" }
default { "Unknown Type: $($systemInfo.PCSystemTypeEx)" }
}
return [PSCustomObject]@{
Manufacturer = $systemInfo.Manufacturer
Model = $systemInfo.Model
SystemFamily = $systemInfo.SystemFamily
PCSystemType = $systemInfo.PCSystemType
PCSystemTypeDescription = $pcSystemTypeDescription
PCSystemTypeEx = $systemInfo.PCSystemTypeEx
PCSystemTypeExDescription = $pcSystemTypeExDescription
DomainRole = $systemInfo.DomainRole
TotalPhysicalMemoryGB = [math]::Round($systemInfo.TotalPhysicalMemory / 1GB, 2)
NumberOfProcessors = $systemInfo.NumberOfProcessors
NumberOfLogicalProcessors = $systemInfo.NumberOfLogicalProcessors
}
}
# Call the function
$sysType = Get-SystemTypeInfo
Write-Output "System Type (PCSystemType): $($sysType.PCSystemTypeDescription)"
Write-Output "System Type (PCSystemTypeEx): $($sysType.PCSystemTypeExDescription)"
Write-Output "Manufacturer: $($sysType.Manufacturer)"
Write-Output "Model: $($sysType.Model)"While Win32_ComputerSystem properties like PCSystemType can provide useful context, they are generally considered less definitive for physical form factor identification than Win32_SystemEnclosure.ChassisTypes. However, combining information from both classes can lead to a more robust and confident determination.
While Win32_SystemEnclosure is the most reliable single source, combining data from multiple WMI classes can provide an even more robust and confident determination of the device form factor, especially when dealing with edge cases or potentially ambiguous hardware reporting.
The idea is to create a prioritized decision-making process:
- Primary Check: Use
Win32_SystemEnclosure.ChassisTypesas the main indicator. - Secondary Check: If
ChassisTypesis ambiguous or unavailable, consultWin32_ComputerSystem.PCSystemTypeExorPCSystemType. - Tertiary Check: Use the presence of
Win32_Batteryas a supporting factor, particularly if the primary and secondary checks suggest a desktop but a battery is present (indicating a potential UPS or an unusual portable device).
Here is a more advanced PowerShell function that attempts to combine these data points:
function Get-DetailedDeviceFormFactor {
[CmdletBinding()]
param()
# Initialize results object
$result = [PSCustomObject]@{
DeterminedFormFactor = "Unknown"
PrimaryIndicator = "None"
SecondaryIndicator = "None"
BatteryPresent = $false
Confidence = "Low"
ChassisTypes = @()
ChassisTypeDescriptions = @()
PCSystemType = $null
PCSystemTypeDescription = "N/A"
PCSystemTypeEx = $null
PCSystemTypeExDescription = "N/A"
Manufacturer = "N/A"
Model = "N/A"
Notes = @()
}
# --- Query WMI Classes ---
try {
$enclosureInfo = Get-CimInstance -ClassName Win32_SystemEnclosure -ErrorAction Stop
$result.Manufacturer = $enclosureInfo.Manufacturer
$result.Model = $enclosureInfo.Model # Often null here, better from ComputerSystem
$result.ChassisTypes = $enclosureInfo.ChassisTypes
} catch {
$result.Notes += "Error querying Win32_SystemEnclosure: $($_.Exception.Message)"
}
try {
$systemInfo = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
$result.PCSystemType = $systemInfo.PCSystemType
$result.PCSystemTypeEx = $systemInfo.PCSystemTypeEx
# Overwrite Manufacturer/Model if available and more specific here
if (-not [string]::IsNullOrWhiteSpace($systemInfo.Manufacturer)) { $result.Manufacturer = $systemInfo.Manufacturer }
if (-not [string]::IsNullOrWhiteSpace($systemInfo.Model)) { $result.Model = $systemInfo.Model }
} catch {
$result.Notes += "Error querying Win32_ComputerSystem: $($_.Exception.Message)"
}
try {
$batteryInfo = Get-CimInstance -ClassName Win32_Battery -ErrorAction SilentlyContinue
if ($batteryInfo) {
$result.BatteryPresent = $true
}
} catch {
# Ignore errors, just means no battery or cannot query
$result.Notes += "Error querying Win32_Battery (ignored): $($_.Exception.Message)"
}
# --- Decision Logic ---
# 1. Analyze ChassisTypes (Primary)
$isLaptopChassis = $false
$isDesktopChassis = $false
$isServerChassis = $false
$isMobileChassis = $false
$laptopChassisTypes = @(8, 9, 10, 14)
$desktopChassisTypes = @(3, 4, 5, 6, 7, 13, 15, 35, 36)
$serverChassisTypes = @(17, 23, 25, 28, 29)
$mobileChassisTypes = @(11, 30, 31, 32)
if ($result.ChassisTypes.Count -gt 0) {
$result.PrimaryIndicator = "Win32_SystemEnclosure.ChassisTypes"
foreach ($type in $result.ChassisTypes) {
$desc = switch ($type) {
1 {"Other"} 2 {"Unknown"} 3 {"Desktop"} 4 {"Low Profile Desktop"} 5 {"Pizza Box"} 6 {"Mini Tower"} 7 {"Tower"} 8 {"Portable"} 9 {"Laptop"} 10 {"Notebook"} 11 {"Hand Held"} 12 {"Docking Station"} 13 {"All in One"} 14 {"Sub Notebook"} 15 {"Space-Saving"} 16 {"Lunch Box"} 17 {"Main System Chassis"} 18 {"Expansion Chassis"} 19 {"SubChassis"} 20 {"Bus Expansion Chassis"} 21 {"Peripheral Chassis"} 22 {"RAID Chassis"} 23 {"Rack Mount Chassis"} 24 {"Sealed-Case PC"} 25 {"Multi-system chassis"} 26 {"Compact PCI"} 27 {"Advanced TCA"} 28 {"Blade"} 29 {"Blade Enclosure"} 30 {"Tablet"} 31 {"Convertible"} 32 {"Detachable"} 33 {"IoT Gateway"} 34 {"Embedded PC"} 35 {"Mini PC"} 36 {"Stick PC"} default {"Unknown Type: $type"}
}
$result.ChassisTypeDescriptions += "$type ($desc)"
if ($laptopChassisTypes -contains $type) { $isLaptopChassis = $true }
if ($desktopChassisTypes -contains $type) { $isDesktopChassis = $true }
if ($serverChassisTypes -contains $type) { $isServerChassis = $true }
if ($mobileChassisTypes -contains $type) { $isMobileChassis = $true }
}
# Determine form factor based on ChassisTypes
if ($isLaptopChassis) { $result.DeterminedFormFactor = "Laptop"; $result.Confidence = "High" }
elseif ($isMobileChassis) { $result.DeterminedFormFactor = "Mobile Device"; $result.Confidence = "High" }
elseif ($isDesktopChassis) { $result.DeterminedFormFactor = "Desktop"; $result.Confidence = "High" }
elseif ($isServerChassis) { $result.DeterminedFormFactor = "Server"; $result.Confidence = "High" }
else { $result.Notes += "ChassisType(s) did not match common Laptop/Desktop/Server/Mobile categories." }
} else {
$result.Notes += "Win32_SystemEnclosure.ChassisTypes was empty or unavailable."
}
# 2. Analyze PCSystemType/Ex (Secondary, if ChassisTypes inconclusive)
if ($result.DeterminedFormFactor -eq "Unknown" -or $result.Confidence -eq "Low") {
$result.SecondaryIndicator = "Win32_ComputerSystem.PCSystemTypeEx / PCSystemType"
$result.PCSystemTypeDescription = switch ($result.PCSystemType) { 0{"Unspecified"} 1{"Desktop"} 2{"Mobile"} 3{"Workstation"} 4{"Enterprise Server"} 5{"SOHO Server"} 6{"Appliance PC"} 7{"Performance Server"} default{"Unknown"} }
$result.PCSystemTypeExDescription = switch ($result.PCSystemTypeEx) { 0{"Unspecified"} 1{"Desktop"} 2{"Mobile"} 3{"Workstation"} 4{"Enterprise Server"} 5{"SOHO Server"} 6{"Appliance PC"} 7{"Performance Server"} 8{"Slate (Tablet)"} 9{"Convertible"} 10{"Detachable"} default{"Unknown"} }
# Use PCSystemTypeEx first if available and specific
if ($result.PCSystemTypeEx -in @(8, 9, 10)) { # Slate, Convertible, Detachable
$result.DeterminedFormFactor = "Mobile Device"
$result.Confidence = "Medium"
} elseif ($result.PCSystemTypeEx -eq 2) { # Mobile
$result.DeterminedFormFactor = "Laptop"
$result.Confidence = "Medium"
} elseif ($result.PCSystemTypeEx -in @(1, 3)) { # Desktop, Workstation
$result.DeterminedFormFactor = "Desktop"
$result.Confidence = "Medium"
} elseif ($result.PCSystemTypeEx -in @(4, 5, 7)) { # Servers
$result.DeterminedFormFactor = "Server"
$result.Confidence = "Medium"
} else {
# Fallback to PCSystemType
if ($result.PCSystemType -eq 2) { # Mobile
$result.DeterminedFormFactor = "Laptop"
$result.Confidence = "Medium"
} elseif ($result.PCSystemType -in @(1, 3)) { # Desktop, Workstation
$result.DeterminedFormFactor = "Desktop"
$result.Confidence = "Medium"
} elseif ($result.PCSystemType -in @(4, 5, 7)) { # Servers
$result.DeterminedFormFactor = "Server"
$result.Confidence = "Medium"
} else {
$result.Notes += "PCSystemType/Ex did not provide a clear Laptop/Desktop/Server/Mobile category."
}
}
}
# 3. Battery Check (Tertiary / Confirmation)
if ($result.BatteryPresent) {
if ($result.DeterminedFormFactor -eq "Desktop" -and $result.Confidence -ne "Low") {
$result.Notes += "Desktop form factor indicated, but a battery is present (possible UPS or All-in-One?). Confidence slightly reduced."
if ($result.Confidence -eq "High") { $result.Confidence = "Medium" }
} elseif ($result.DeterminedFormFactor -eq "Unknown") {
$result.DeterminedFormFactor = "Laptop" # Assume laptop if battery present and others failed
$result.Confidence = "Low"
$result.Notes += "Primary/Secondary indicators failed. Assuming Laptop due to battery presence."
}
} else { # No Battery
if (($result.DeterminedFormFactor -eq "Laptop" -or $result.DeterminedFormFactor -eq "Mobile Device") -and $result.Confidence -ne "Low") {
$result.Notes += "Portable form factor indicated, but no battery detected (possible faulty/removed battery?). Confidence slightly reduced."
if ($result.Confidence -eq "High") { $result.Confidence = "Medium" }
}
}
# Final check for Unknown
if ($result.DeterminedFormFactor -eq "Unknown") {
$result.Notes += "Could not reliably determine form factor."
}
return $result
}
# Example Usage
$detailedInfo = Get-DetailedDeviceFormFactor
$detailedInfo | Format-List- Permissions: Running WMI queries, especially remotely, requires appropriate permissions.
- Remote Execution: Wrap
Get-CimInstancecalls withinInvoke-Commandfor remote systems. - WMI Corruption: WMI repositories can become corrupted. Handle potential exceptions during queries.
- Virtual Machines: VMs remain challenging. The
HypervisorPresentproperty inWin32_ComputerSystemcan detect virtualization, but the reported chassis/system types might still be inaccurate or generic. - Non-Standard Hardware: Some niche or custom hardware might report unusual or non-standard values.
This comprehensive approach, while more complex, significantly increases the accuracy of device form factor detection by leveraging multiple data points and applying a logical decision process.
Accurately determining a device's form factor has numerous practical applications in system administration and automation:
- System Inventory & Asset Management: Categorizing hardware assets correctly for reporting and lifecycle management.
- Configuration Management: Applying different settings (e.g., power plans, security policies, software installations) based on whether a device is a desktop, laptop, or server using tools like Group Policy, SCCM/Intune, or PowerShell DSC.
- Power Management: Implementing more aggressive power-saving settings on laptops compared to desktops.
- Software Deployment Targeting: Ensuring specific software (e.g., VPN clients, docking station drivers) is deployed only to relevant device types.
- Security Policy Application: Enforcing stricter security measures (e.g., BitLocker encryption requirements) on portable devices.
- User Experience Customization: Tailoring scripts or application behavior based on the device type.
While the simple approach of checking for a battery using Win32_Battery might seem intuitive for distinguishing laptops from desktops, it suffers from significant limitations and potential inaccuracies. A far more reliable method involves querying the Win32_SystemEnclosure WMI class and analyzing its ChassisTypes property, which directly reflects the physical design of the system's enclosure as reported by the hardware manufacturer.
Supplementing this with information from Win32_ComputerSystem, particularly the PCSystemType and PCSystemTypeEx properties, can provide additional context and help resolve ambiguities. For the highest level of confidence, combining data from all three classes (Win32_SystemEnclosure, Win32_ComputerSystem, and Win32_Battery) using a prioritized logic allows for robust form factor detection even in the presence of edge cases like UPS units or virtual machines.
By leveraging the appropriate WMI classes and understanding their nuances, administrators can accurately identify device types and implement more targeted, efficient, and effective management strategies across their Windows environments.
- Win32_Battery class - Win32 apps | Microsoft Learn: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-battery
- Win32_SystemEnclosure class - Win32 apps | Microsoft Learn: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-systemenclosure
- Win32_ComputerSystem class - Win32 apps | Microsoft Learn: https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-computersystem
- How Can I Determine if a Computer is a Laptop or a Desktop Machine? - Scripting Blog [archived]: https://devblogs.microsoft.com/scripting/how-can-i-determine-if-a-computer-is-a-laptop-or-a-desktop-machine/
- Chassis Types (Windows Drivers) | Microsoft Learn: (While specific driver docs might exist, the values are generally aligned with the SystemEnclosure class documentation)
- CIM_Chassis (Standard CIM Classes) | Microsoft Learn: https://learn.microsoft.com/en-us/previous-versions/windows/desktop/cimwin32a/cim-chassis
(Note: Always refer to the latest Microsoft documentation for the most up-to-date information on WMI classes and their properties.)