yuzu

wmi

What it doesWindows Management Instrumentation — WQL queries and instance enumeration
Version1.1.0
KindCollector · read-only · on-demand
PlatformsWindows ✅ · macOS ⛔ unsupported · Linux ⛔ unsupported
Actionsget_instance (definition windows.wmi.get_instance) · query (definition windows.wmi.query)
Securitysecurable Infrastructure · operation Read · risk Medium · dispatch ReadOnly · approval gate None
Rolesexecute: endpoint-admin, endpoint-operator · author: content-author

How it works

query runs an operator-supplied WQL statement and get_instance builds SELECT * FROM <class> from a class name — both funnel through the same shared helper, yuzu::shared::wmi::run_bounded_wmi_query (agents/shared/wmi_bounded.hpp). Before either reaches WMI, the plugin validates its own inputs: query requires the statement to start with SELECT (wmi_plugin.cpp:38-49, is_select_only) and get_instance requires the class name to be alphanumeric/underscore only (wmi_plugin.cpp:52-59, is_valid_wmi_class); both then check the target namespace against a fixed allow-list of root\cimv2, root\wmi, root\standardcimv2 (wmi_plugin.cpp:62-80, is_valid_wmi_namespace). Only after both checks pass does the helper connect (WBEM_FLAG_CONNECT_USE_MAX_WAIT) and enumerate results with a per-call timeout and a whole-enumeration deadline — never Next(WBEM_INFINITE, ...) (the wmi_bounded.hpp header banner and the run_bounded_wmi_query doc comment). get_instance additionally caps the helper to one row and a 5s deadline (wmi_plugin.cpp:192-195), so it always returns at most the first matching instance, never an enumeration of every instance of the class.

The plugin deliberately does not expose WMI method invocation: wmi_bounded.hpp ships an exec_object_method helper whose only production caller is the bitlocker plugin’s fixed per-volume method calls, with an explicit warning that its caller must add its own namespace/method allow-listing before wiring it up (the exec_object_method doc comment in wmi_bounded.hpp) — wmi_plugin.cpp never calls it. It is also deliberately Windows-only: execute() returns a fixed error string on every other OS without touching any OS API (wmi_plugin.cpp:126-128).

flowchart LR
  OP[Operator / workflow] --> SRV[Server<br/>authz: Infrastructure.Read]
  SRV -- gRPC mTLS --> HOST[Agent plugin host] --> EX[wmi.execute]
  EX --> VAL[SELECT-only / class-name /<br/>namespace allow-list checks]
  VAL --> WIN[Windows leg<br/>IWbemLocator/IWbemServices COM<br/>bounded connect + semisync Next]
  EX -.->|non-Windows| ERR[fixed error row<br/>no OS call made]
  WIN --> ROWS[row/property lines +<br/>UNDECLARED result status] --> RS[(ResponseStore)] --> API[REST /api/responses]

OS capability

ActionWindowsmacOSLinux
get_instance✅ supported · rung 1 · wmi⛔ unsupported⛔ unsupported
query✅ supported · rung 1 · wmi⛔ unsupported⛔ unsupported

Privileges and prerequisites

OSRuns asExtra grant neededMeasuredIf the read is refused
Windowsagent service account (LocalSystem today, #1442 — docs/agent-privilege-model.md:12)Not established by a capture: the only Windows sample was taken as SYSTEM (docs/samples/windows.txt:1), which succeeds; no unprivileged Windows capture exists for this plugin. WMI’s own DCOM ACL, not an agent-side grant, decides access.2026-09-07, bare-metal, SYSTEM (docs/samples/windows.txt:1)A denied connect/query surfaces as error|<token> and rc 1, e.g. wbem_locator_failed or wmi_connect_failed_<hr>; a fault while reading an object’s properties fails the whole query as wmi_property_enum_failed_<hr> rather than returning a row with a silently dropped property (connect_bounded in wmi_bounded.hpp, wmi_plugin.cpp:151-155) — there is no distinct permission-denied status
macOSn/a — leg not implementedn/a2026-09-07, bare-metal, euid 501 (unprivileged) (docs/samples/macos.txt:1)Always error|WMI not available on this platform, rc 1, regardless of privilege (wmi_plugin.cpp:126-128)
Linuxn/a — leg not implementedn/a2026-09-06, container, euid 0 (docs/samples/linux.txt:1)Always error|WMI not available on this platform, rc 1, regardless of privilege (wmi_plugin.cpp:126-128)

No external binaries and no subprocesses — the Windows leg talks to the local WMI service (WinMgmt) over in-process COM/RPC only (connect_bounded in wmi_bounded.hpp); no other network access.

Data contract

Inputs

DefinitionParameterTypeRequiredDefaultConstraintsDescription
windows.wmi.get_instanceclassstringyes--WMI class name, alphanumeric and underscores only (e.g., Win32_OperatingSystem) — the plugin runs SELECT * FROM <class> against it.
windows.wmi.get_instancenamespacestringno--WMI namespace to query — one of root\cimv2 (default), root\wmi, or root\standardcimv2; any other value is rejected.
windows.wmi.querywqlstringyes--A WQL SELECT statement (e.g., “SELECT * FROM Win32_OperatingSystem”). Only SELECT statements are allowed; anything else is rejected before the query runs.
windows.wmi.querynamespacestringno--WMI namespace to query — one of root\cimv2 (default), root\wmi, or root\standardcimv2; any other value is rejected.

Outputs

Both actions emit pipe-delimited lines, not the two-column property/value shape the definition YAML’s result.columns implies on its own: query writes one row<N>|<property>|<value> line per returned property (wmi_plugin.cpp:159-160) followed by a terminal rows|<count> line (wmi_plugin.cpp:168) and, if the shared helper’s row cap was hit, an error|row_cap_exceeded line before it (wmi_plugin.cpp:163-168); get_instance writes one property|<name>|<value> line per property of the single matched instance, with no trailing count line (wmi_plugin.cpp:201-203). A property is omitted from either action’s output entirely — never emitted with an empty value — when its VARIANT type isn’t one variant_to_string knows how to stringify, including VT_NULL/VT_EMPTY (variant_to_string / extract_row in wmi_bounded.hpp).

windows.wmi.get_instance — property|value

FieldTypeValuesAvailableExampleDescription
propertystring-WindowsBootDeviceThe non-system WMI property name for one property of the first matching instance; null/empty/array-typed properties are omitted rather than reported as empty. Values: free text (WMI property name).
valuestring-Windows\Device\HarddiskVolume1The stringified WMI property value — BSTR text passed through, numeric VARIANTs formatted as decimal text, booleans as true/false. Values: free text.

windows.wmi.query — property|value

FieldTypeValuesAvailableExampleDescription
propertystring-WindowsCaptionThe non-system WMI property name for one output row; null/empty/array-typed properties are omitted rather than reported as empty. Values: free text (WMI property name).
valuestring-WindowsMicrosoft Windows 11 ProThe stringified WMI property value — BSTR text passed through, numeric VARIANTs formatted as decimal text, booleans as true/false. Values: free text.

Result status

This plugin does not set a typed result status (no set_result_status/yuzu_ctx_set_result_status call anywhere in wmi_plugin.cpp — confirmed by grep); the agent records UNDECLARED and every sample shows UNDECLARED / UNKNOWN / (docs/samples/windows.txt:5,62; docs/samples/macos.txt:4,9; docs/samples/linux.txt:4,9). A validation failure, a query failure, or an unsupported-OS call is distinguishable only by the error|... row and the exit code, never by this status field.

Where the data goes

Sample output

Windows — captured: windows Microsoft Windows NT 10.0.26200.0 x64 · bare-metal · 2026-09-07 · SYSTEM · leg-hash a8a6121c1219

== action=query wql="SELECT Caption FROM Win32_OperatingSystem"
row0|Caption|Microsoft Windows 11 Pro
rows|1
[result_status] UNDECLARED / UNKNOWN

== action=get_instance class=Win32_OperatingSystem
property|BootDevice|\Device\HarddiskVolume1
property|BuildNumber|26200
property|BuildType|Multiprocessor Free
property|CSCreationClassName|Win32_ComputerSystem
property|CSName|DESKTOP-04DNSIG
property|Caption|Microsoft Windows 11 Pro
property|CodeSet|1252
property|CountryCode|44
property|CreationClassName|Win32_OperatingSystem
property|CurrentTimeZone|60
property|DataExecutionPrevention_32BitApplications|true
property|DataExecutionPrevention_Available|true
… 12 of 54 rows shown
[result_status] UNDECLARED / UNKNOWN

macOS — captured: macos macOS 26.6.2 arm64 · bare-metal · 2026-09-07 · euid 501 (jsmith) · leg-hash a8a6121c1219

== action=query wql="SELECT Caption FROM Win32_OperatingSystem"
error|WMI not available on this platform
[result_status] UNDECLARED / UNKNOWN
[rc] 1

== action=get_instance class=Win32_OperatingSystem
error|WMI not available on this platform
[result_status] UNDECLARED / UNKNOWN
[rc] 1

Linux — captured: linux Debian GNU/Linux 13 (trixie) aarch64 · container · 2026-09-06 · euid 0 · leg-hash a8a6121c1219

== action=query wql="SELECT Caption FROM Win32_OperatingSystem"
error|WMI not available on this platform
[result_status] UNDECLARED / UNKNOWN
[rc] 1

== action=get_instance class=Win32_OperatingSystem
error|WMI not available on this platform
[result_status] UNDECLARED / UNKNOWN
[rc] 1

Caveats and known gaps

  1. No unprivileged Windows capture exists. The only Windows sample ran as SYSTEM (docs/samples/windows.txt:1); whether either action works, and what it returns, under NT SERVICE\YuzuAgent or a non-admin token is not measured by anything in this repo.
  2. get_instance never reports truncation. query surfaces error|row_cap_exceeded when the shared helper’s row cap is hit (wmi_plugin.cpp:163-167), but get_instance sets row_cap = 1 deliberately (wmi_plugin.cpp:192-195) and never inspects qres.truncated, so a class with more properties than the helper can enumerate before its own cap looks identical to a class that genuinely has one property.
  3. This plugin never sets a typed result status. Every capture shows UNDECLARED / UNKNOWN / regardless of success or failure (docs/samples/windows.txt:5,62); a consumer must parse the error| row and exit code, not the status field, to tell success from failure.
  4. Method invocation is dormant, not exposed. agents/shared/wmi_bounded.hpp ships exec_object_method for calling a WMI instance method, whose only production caller (bitlocker, fixed method names, no action input) predates this gate, with an explicit warning that the first caller must add its own namespace/method allow-list (the exec_object_method doc comment in wmi_bounded.hpp) — do not wire it into this plugin without adding that gate.
  5. No row-index or discriminator column in the definition schema. query’s real output is row<N>|property|value, but content/definitions/wmi.yaml’s result.columns only declares property/value for both actions — the row index is not modeled as a column.

Source and tests