@cfour-hi/dsh-plugin-devicex 0.0.0-stage → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,501 @@
1
+ # Device X - Windows hardware inventory (CIM/PnP).
2
+ #
3
+ # Emits exactly one JSON document on stdout (no other stdout text).
4
+ # Read-only: no admin rights, no network calls, no external modules.
5
+ $ErrorActionPreference = 'Stop'
6
+
7
+ $errors = @()
8
+
9
+ function To-LongOrNull($value) {
10
+ if ($null -eq $value) { return $null }
11
+ try { return [long]$value } catch { return $null }
12
+ }
13
+
14
+ function ConvertFrom-IdList($value) {
15
+ # WmiMonitorID string fields are arrays of ASCII code units ended by 0.
16
+ if ($null -eq $value) { return $null }
17
+ try {
18
+ $characters = @()
19
+ foreach ($item in @($value)) {
20
+ $code = [int]$item
21
+ if ($code -le 0) { break }
22
+ $characters += [char]$code
23
+ }
24
+ $text = (-join $characters).Trim()
25
+ if ($text.Length -gt 0) { return $text }
26
+ return $null
27
+ } catch { return $null }
28
+ }
29
+
30
+ function Get-GpuRegistryMemoryBytes {
31
+ # Win32_VideoController.AdapterRAM is UInt32 and wraps/zeroes for cards with
32
+ # more than 4 GB. The display class registry keys store the exact byte size in
33
+ # `HardwareInformation.qwMemorySize` (QWORD), keyed by DriverDesc (which is
34
+ # normally identical to Win32_VideoController.Name).
35
+ $memoryByName = @{}
36
+ $classRoot = 'HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}'
37
+ try {
38
+ $classKeys = @(Get-ChildItem -Path $classRoot -ErrorAction Stop)
39
+ } catch {
40
+ return $memoryByName
41
+ }
42
+ foreach ($classKey in $classKeys) {
43
+ if ([string]$classKey.PSChildName -notmatch '^\d{4}$') { continue }
44
+ try {
45
+ $properties = Get-ItemProperty -Path $classKey.PSPath -ErrorAction Stop
46
+ $memory = To-LongOrNull $properties.'HardwareInformation.qwMemorySize'
47
+ if ($null -eq $memory -or $memory -le 0) { continue }
48
+ $description = [string]$properties.DriverDesc
49
+ if ($description) { $memoryByName[$description] = $memory }
50
+ } catch { }
51
+ }
52
+ return $memoryByName
53
+ }
54
+
55
+ # --------------------------------------------------------------------- CPU --
56
+ $cpu = $null
57
+ try {
58
+ $processors = @(Get-CimInstance -ClassName Win32_Processor -ErrorAction Stop)
59
+ if ($processors.Count -gt 0) {
60
+ $first = $processors[0]
61
+ $physicalCores = 0
62
+ $logicalCores = 0
63
+ $l2CacheKB = 0
64
+ $l3CacheKB = 0
65
+ foreach ($processor in $processors) {
66
+ if ($null -ne $processor.NumberOfCores) { $physicalCores += [int]$processor.NumberOfCores }
67
+ if ($null -ne $processor.NumberOfLogicalProcessors) { $logicalCores += [int]$processor.NumberOfLogicalProcessors }
68
+ if ($null -ne $processor.L2CacheSize) { $l2CacheKB += [long]$processor.L2CacheSize }
69
+ if ($null -ne $processor.L3CacheSize) { $l3CacheKB += [long]$processor.L3CacheSize }
70
+ }
71
+ $cpu = [ordered]@{
72
+ name = [string]$first.Name
73
+ manufacturer = [string]$first.Manufacturer
74
+ physicalCores = $physicalCores
75
+ logicalCores = $logicalCores
76
+ maxClockSpeedMHz = To-LongOrNull $first.MaxClockSpeed
77
+ architecture = To-LongOrNull $first.Architecture
78
+ l2CacheKB = $l2CacheKB
79
+ l3CacheKB = $l3CacheKB
80
+ }
81
+ }
82
+ } catch { $errors += ('Win32_Processor: ' + $_.Exception.Message) }
83
+
84
+ # ------------------------------------------------------------------ memory --
85
+ $modules = @()
86
+ $totalMemoryBytes = $null
87
+ try {
88
+ $physicalModules = @(Get-CimInstance -ClassName Win32_PhysicalMemory -ErrorAction Stop)
89
+ foreach ($module in $physicalModules) {
90
+ $modules += [ordered]@{
91
+ capacityBytes = To-LongOrNull $module.Capacity
92
+ speedMHz = To-LongOrNull $module.Speed
93
+ configuredSpeedMHz = To-LongOrNull $module.ConfiguredClockSpeed
94
+ manufacturer = [string]$module.Manufacturer
95
+ partNumber = [string]$module.PartNumber
96
+ deviceLocator = [string]$module.DeviceLocator
97
+ smbiosType = To-LongOrNull $module.SMBIOSMemoryType
98
+ }
99
+ }
100
+ } catch { $errors += ('Win32_PhysicalMemory: ' + $_.Exception.Message) }
101
+
102
+ $arrayMaxCapacityBytes = $null
103
+ try {
104
+ $memoryArrays = @(Get-CimInstance -ClassName Win32_PhysicalMemoryArray -ErrorAction Stop)
105
+ if ($memoryArrays.Count -gt 0 -and $null -ne $memoryArrays[0].MaxCapacityEx) {
106
+ $maxKb = To-LongOrNull $memoryArrays[0].MaxCapacityEx
107
+ if ($null -ne $maxKb) { $arrayMaxCapacityBytes = $maxKb * 1024 }
108
+ }
109
+ } catch { $arrayMaxCapacityBytes = $null }
110
+
111
+ try {
112
+ $computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
113
+ $totalMemoryBytes = To-LongOrNull $computerSystem.TotalPhysicalMemory
114
+ } catch { $errors += ('Win32_ComputerSystem: ' + $_.Exception.Message) }
115
+
116
+ if ($null -eq $totalMemoryBytes -and $modules.Count -gt 0) {
117
+ $sum = [long]0
118
+ $anyModule = $false
119
+ foreach ($module in $modules) {
120
+ if ($null -ne $module.capacityBytes) { $sum += [long]$module.capacityBytes; $anyModule = $true }
121
+ }
122
+ if ($anyModule) { $totalMemoryBytes = $sum }
123
+ }
124
+
125
+ $memory = [ordered]@{
126
+ totalBytes = $totalMemoryBytes
127
+ arrayMaxCapacityBytes = $arrayMaxCapacityBytes
128
+ modules = $modules
129
+ }
130
+
131
+ # ------------------------------------------------------- GPU and displays --
132
+ $gpuMemoryByName = Get-GpuRegistryMemoryBytes
133
+ $videoControllers = @()
134
+ try {
135
+ $adapters = @(Get-CimInstance -ClassName Win32_VideoController -ErrorAction Stop)
136
+ foreach ($adapter in $adapters) {
137
+ $adapterName = [string]$adapter.Name
138
+ $adapterRamBytes = To-LongOrNull $adapter.AdapterRAM
139
+ $adapterRamSource = $null
140
+ if ($null -ne $adapterRamBytes) { $adapterRamSource = 'cim' }
141
+ $registryMemory = $null
142
+ if ($adapterName -and $gpuMemoryByName.ContainsKey($adapterName)) {
143
+ $registryMemory = $gpuMemoryByName[$adapterName]
144
+ }
145
+ if ($null -ne $registryMemory -and $registryMemory -gt 0) {
146
+ $adapterRamBytes = $registryMemory
147
+ $adapterRamSource = 'registry'
148
+ } elseif ($null -ne $adapterRamBytes -and $adapterRamBytes -ge 4000000000) {
149
+ # UInt32 AdapterRAM saturates at 4 GB; do not report a bogus number.
150
+ $adapterRamBytes = $null
151
+ $adapterRamSource = 'cim-capped'
152
+ $errors += ('GPU memory for "' + $adapterName + '" is truncated at 4 GB (Win32_VideoController AdapterRAM); registry qwMemorySize unavailable')
153
+ }
154
+ $videoControllers += [ordered]@{
155
+ name = $adapterName
156
+ adapterRamBytes = $adapterRamBytes
157
+ adapterRamSource = $adapterRamSource
158
+ driverVersion = [string]$adapter.DriverVersion
159
+ videoProcessor = [string]$adapter.VideoProcessor
160
+ currentWidth = To-LongOrNull $adapter.CurrentHorizontalResolution
161
+ currentHeight = To-LongOrNull $adapter.CurrentVerticalResolution
162
+ currentRefreshHz = To-LongOrNull $adapter.CurrentRefreshRate
163
+ status = [string]$adapter.Status
164
+ }
165
+ }
166
+ } catch { $errors += ('Win32_VideoController: ' + $_.Exception.Message) }
167
+
168
+ $monitors = @()
169
+ try {
170
+ $monitorIds = @(Get-CimInstance -Namespace 'root/wmi' -ClassName WmiMonitorID -ErrorAction Stop)
171
+ foreach ($monitor in $monitorIds) {
172
+ $monitors += [ordered]@{
173
+ name = ConvertFrom-IdList $monitor.UserFriendlyName
174
+ manufacturer = ConvertFrom-IdList $monitor.ManufacturerName
175
+ serial = ConvertFrom-IdList $monitor.SerialNumberID
176
+ active = [bool]$monitor.Active
177
+ }
178
+ }
179
+ } catch { $errors += ('WmiMonitorID: ' + $_.Exception.Message); $monitors = @() }
180
+
181
+ # ---------------------------------------------------------------- storage --
182
+ $physicalDisks = @()
183
+ try {
184
+ $storageDisks = @(Get-PhysicalDisk -ErrorAction Stop)
185
+ foreach ($disk in $storageDisks) {
186
+ $mediaType = [string]$disk.MediaType
187
+ $physicalDisks += [ordered]@{
188
+ name = [string]$disk.FriendlyName
189
+ model = [string]$disk.Model
190
+ sizeBytes = To-LongOrNull $disk.Size
191
+ mediaType = $mediaType
192
+ smartStatus = [string]$disk.HealthStatus
193
+ serial = [string]$disk.SerialNumber
194
+ interfaceType = [string]$disk.BusType
195
+ }
196
+ }
197
+ } catch { $errors += ('Get-PhysicalDisk: ' + $_.Exception.Message); $physicalDisks = @() }
198
+
199
+ $diskDrives = @()
200
+ try {
201
+ $drives = @(Get-CimInstance -ClassName Win32_DiskDrive -ErrorAction Stop)
202
+ foreach ($drive in $drives) {
203
+ $diskDrives += [ordered]@{
204
+ model = [string]$drive.Model
205
+ sizeBytes = To-LongOrNull $drive.Size
206
+ mediaType = [string]$drive.MediaType
207
+ interfaceType = [string]$drive.InterfaceType
208
+ serialNumber = [string]$drive.SerialNumber
209
+ }
210
+ }
211
+ } catch { $errors += ('Win32_DiskDrive: ' + $_.Exception.Message) }
212
+
213
+ $volumes = @()
214
+ try {
215
+ $logicalDisks = @(Get-CimInstance -ClassName Win32_LogicalDisk -ErrorAction Stop)
216
+ foreach ($logicalDisk in $logicalDisks) {
217
+ $driveType = 0
218
+ if ($null -ne $logicalDisk.DriveType) { $driveType = [int]$logicalDisk.DriveType }
219
+ if ($driveType -ne 2 -and $driveType -ne 3) { continue }
220
+ $volumes += [ordered]@{
221
+ deviceId = [string]$logicalDisk.DeviceID
222
+ name = [string]$logicalDisk.VolumeName
223
+ fs = [string]$logicalDisk.FileSystem
224
+ totalBytes = To-LongOrNull $logicalDisk.Size
225
+ freeBytes = To-LongOrNull $logicalDisk.FreeSpace
226
+ driveType = $driveType
227
+ }
228
+ }
229
+ } catch { $errors += ('Win32_LogicalDisk: ' + $_.Exception.Message) }
230
+
231
+ # ---------------------------------------------------------------- battery --
232
+ $battery = $null
233
+ try {
234
+ $batteries = @(Get-CimInstance -ClassName Win32_Battery -ErrorAction Stop)
235
+ if ($batteries.Count -gt 0) {
236
+ $batteryDevice = $batteries[0]
237
+ $percent = $null
238
+ if ($null -ne $batteryDevice.EstimatedChargeRemaining) { $percent = [int]$batteryDevice.EstimatedChargeRemaining }
239
+ $condition = $null
240
+ if ($batteryDevice.Status) {
241
+ $condition = [string]$batteryDevice.Status
242
+ if ($condition -eq 'OK') { $condition = 'Normal' }
243
+ }
244
+ $designMwh = To-LongOrNull $batteryDevice.DesignCapacity
245
+ $fullMwh = To-LongOrNull $batteryDevice.FullChargeCapacity
246
+ $voltageMv = To-LongOrNull $batteryDevice.DesignVoltage
247
+ if ($null -eq $designMwh -or $null -eq $fullMwh) {
248
+ try {
249
+ $staticBattery = @(Get-CimInstance -Namespace 'root/wmi' -ClassName BatteryStaticData -ErrorAction Stop)
250
+ if ($staticBattery.Count -gt 0) {
251
+ if ($null -eq $designMwh -and $null -ne $staticBattery[0].DesignedCapacity) {
252
+ $designMwh = [double]$staticBattery[0].DesignedCapacity
253
+ }
254
+ if ($null -eq $voltageMv -and $null -ne $staticBattery[0].DesignedVoltage) {
255
+ $voltageMv = [double]$staticBattery[0].DesignedVoltage
256
+ }
257
+ }
258
+ $fullBattery = @(Get-CimInstance -Namespace 'root/wmi' -ClassName BatteryFullChargedCapacity -ErrorAction Stop)
259
+ if ($fullBattery.Count -gt 0 -and $null -eq $fullMwh -and $null -ne $fullBattery[0].BatteryFullChargedCapacity) {
260
+ $fullMwh = [double]$fullBattery[0].BatteryFullChargedCapacity
261
+ }
262
+ } catch { }
263
+ }
264
+ $designCapacityMah = $null
265
+ $maxCapacityMah = $null
266
+ $healthPercent = $null
267
+ if ($null -ne $designMwh -and $null -ne $voltageMv -and $voltageMv -gt 0) {
268
+ $designCapacityMah = [int][math]::Round(([double]$designMwh * 1000.0) / [double]$voltageMv)
269
+ }
270
+ if ($null -ne $fullMwh -and $null -ne $voltageMv -and $voltageMv -gt 0) {
271
+ $maxCapacityMah = [int][math]::Round(([double]$fullMwh * 1000.0) / [double]$voltageMv)
272
+ }
273
+ if ($null -ne $designMwh -and $null -ne $fullMwh -and $designMwh -gt 0) {
274
+ $healthPercent = [int][math]::Round(([double]$fullMwh / [double]$designMwh) * 100.0)
275
+ }
276
+ $temperatureC = $null
277
+ try {
278
+ $wmib = Get-CimInstance -Namespace 'root/wmi' -ClassName BatteryStatus -ErrorAction Stop
279
+ if ($wmib -and $null -ne $wmib.Temperature) {
280
+ $temperatureC = [math]::Round(([double]$wmib.Temperature / 10.0) - 273.15, 1)
281
+ }
282
+ } catch { $temperatureC = $null }
283
+ $cycleCount = $null
284
+ try {
285
+ $cycleData = Get-CimInstance -Namespace 'root/wmi' -ClassName BatteryCycleCount -ErrorAction Stop
286
+ if ($cycleData -and $null -ne $cycleData.CycleCount) { $cycleCount = [int]$cycleData.CycleCount }
287
+ } catch { $cycleCount = $null }
288
+ $battery = [ordered]@{
289
+ present = $true
290
+ percent = $percent
291
+ condition = $condition
292
+ cycleCount = $cycleCount
293
+ designCapacityMah = $designCapacityMah
294
+ maxCapacityMah = $maxCapacityMah
295
+ temperatureC = $temperatureC
296
+ healthPercent = $healthPercent
297
+ }
298
+ }
299
+ } catch { $errors += ('Win32_Battery: ' + $_.Exception.Message) }
300
+
301
+ # -------------------------------------------------------------------- USB --
302
+ $usb = @()
303
+ try {
304
+ $usbDevices = @(Get-PnpDevice -Class USB -PresentOnly -ErrorAction Stop)
305
+ foreach ($device in $usbDevices) {
306
+ $instanceId = [string]$device.InstanceId
307
+ if ($instanceId -notmatch 'VID_([0-9A-Fa-f]{4})&PID_([0-9A-Fa-f]{4})') { continue }
308
+ $vendorId = $matches[1].ToUpperInvariant()
309
+ $productId = $matches[2].ToUpperInvariant()
310
+ $serial = $null
311
+ if ($instanceId -match '^[^\\]+\\[^\\]+\\([^\\]+)$') {
312
+ if ($matches[1] -notmatch '&') { $serial = $matches[1] }
313
+ }
314
+ $usb += [ordered]@{
315
+ name = [string]$device.FriendlyName
316
+ vendor = $vendorId
317
+ productId = $productId
318
+ serial = $serial
319
+ speed = $null
320
+ bus = $null
321
+ }
322
+ }
323
+ } catch { $errors += ('Get-PnpDevice USB: ' + $_.Exception.Message) }
324
+
325
+ # -------------------------------------------------------------- Bluetooth --
326
+ $bluetoothControllers = @()
327
+ $bluetoothDevices = @()
328
+ try {
329
+ $bluetoothPnp = @(Get-PnpDevice -Class Bluetooth -PresentOnly -ErrorAction Stop)
330
+ foreach ($device in $bluetoothPnp) {
331
+ $instanceId = [string]$device.InstanceId
332
+ $friendlyName = [string]$device.FriendlyName
333
+ $deviceStatus = [string]$device.Status
334
+ if ($instanceId -match '^(BTHENUM|BTHLE)\\') {
335
+ $address = $null
336
+ if ($instanceId -match 'Dev_([0-9A-Fa-f]{12})') {
337
+ $hex = $matches[1].ToUpperInvariant()
338
+ $pairs = @()
339
+ $index = 0
340
+ while ($index -lt 12) {
341
+ $pairs += $hex.Substring($index, 2)
342
+ $index += 2
343
+ }
344
+ $address = ($pairs -join ':')
345
+ }
346
+ $deviceType = $null
347
+ if ($friendlyName -match '(?i)headphone|headset|speaker|audio|earbud') { $deviceType = 'audio' }
348
+ elseif ($friendlyName -match '(?i)keyboard|mouse|trackpad|gamepad|controller') { $deviceType = 'input' }
349
+ $bluetoothDevices += [ordered]@{
350
+ name = $friendlyName
351
+ address = $address
352
+ connected = ($deviceStatus -eq 'OK')
353
+ batteryPercent = $null
354
+ type = $deviceType
355
+ }
356
+ } else {
357
+ $state = 'off'
358
+ if ($deviceStatus -eq 'OK') { $state = 'on' }
359
+ $bluetoothControllers += [ordered]@{
360
+ name = $friendlyName
361
+ address = $null
362
+ chipset = $friendlyName
363
+ firmware = $null
364
+ state = $state
365
+ }
366
+ }
367
+ }
368
+ } catch { $errors += ('Get-PnpDevice Bluetooth: ' + $_.Exception.Message) }
369
+
370
+ # ------------------------------------------------------------------ audio --
371
+ $audio = @()
372
+ try {
373
+ $audioEndpoints = @(Get-PnpDevice -Class AudioEndpoint -PresentOnly -ErrorAction Stop)
374
+ foreach ($endpoint in $audioEndpoints) {
375
+ $instanceId = [string]$endpoint.InstanceId
376
+ $friendlyName = [string]$endpoint.FriendlyName
377
+ $kind = $null
378
+ if ($instanceId -match '\{[0-9A-Fa-f-]{36}\}') {
379
+ $guid = $matches[0]
380
+ if (Test-Path -LiteralPath ('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\' + $guid)) {
381
+ $kind = 'output'
382
+ } elseif (Test-Path -LiteralPath ('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\' + $guid)) {
383
+ $kind = 'input'
384
+ }
385
+ }
386
+ if (-not $kind) {
387
+ if ($friendlyName -match '(?i)microphone|mic\b|capture|input') { $kind = 'input' } else { $kind = 'output' }
388
+ }
389
+ $audio += [ordered]@{
390
+ name = $friendlyName
391
+ kind = $kind
392
+ manufacturer = $null
393
+ default = $null
394
+ }
395
+ }
396
+ } catch { $errors += ('Get-PnpDevice AudioEndpoint: ' + $_.Exception.Message) }
397
+
398
+ if ($audio.Count -eq 0) {
399
+ try {
400
+ $soundDevices = @(Get-CimInstance -ClassName Win32_SoundDevice -ErrorAction Stop)
401
+ foreach ($soundDevice in $soundDevices) {
402
+ $audio += [ordered]@{
403
+ name = [string]$soundDevice.Name
404
+ kind = 'output'
405
+ manufacturer = [string]$soundDevice.Manufacturer
406
+ default = $null
407
+ }
408
+ }
409
+ } catch { $errors += ('Win32_SoundDevice: ' + $_.Exception.Message) }
410
+ }
411
+
412
+ # ---------------------------------------------------------------- cameras --
413
+ $cameras = @()
414
+ try {
415
+ $cameraDevices = @(Get-PnpDevice -Class Camera,Image -PresentOnly -ErrorAction Stop)
416
+ foreach ($camera in $cameraDevices) {
417
+ $cameras += [ordered]@{
418
+ name = [string]$camera.FriendlyName
419
+ modelId = $null
420
+ uniqueId = [string]$camera.InstanceId
421
+ }
422
+ }
423
+ } catch { $errors += ('Get-PnpDevice Camera/Image: ' + $_.Exception.Message) }
424
+
425
+ # ---------------------------------------------------------------- drivers --
426
+ # driverProblems: PnP devices whose ConfigManagerErrorCode is non-zero (code 28
427
+ # = drivers not installed is the common "missing driver" case). drivers: the
428
+ # signed-driver inventory, with the same non-zero code joined in by DeviceID.
429
+ $driverProblems = @()
430
+ $problemByDeviceId = @{}
431
+ try {
432
+ $problemDevices = @(Get-CimInstance -ClassName Win32_PnPEntity -ErrorAction Stop)
433
+ foreach ($device in $problemDevices) {
434
+ if ($null -eq $device.ConfigManagerErrorCode) { continue }
435
+ $errorCode = [int]$device.ConfigManagerErrorCode
436
+ if ($errorCode -eq 0) { continue }
437
+ if ($driverProblems.Count -lt 50) {
438
+ $driverProblems += [ordered]@{
439
+ name = [string]$device.Name
440
+ code = [string]$errorCode
441
+ class = [string]$device.PNPClass
442
+ }
443
+ }
444
+ $problemDeviceId = [string]$device.DeviceID
445
+ if ($problemDeviceId) { $problemByDeviceId[$problemDeviceId] = [string]$errorCode }
446
+ }
447
+ } catch { $errors += ('Win32_PnPEntity: ' + $_.Exception.Message) }
448
+
449
+ $drivers = @()
450
+ try {
451
+ $signedDrivers = @(Get-CimInstance -ClassName Win32_PnPSignedDriver -ErrorAction Stop)
452
+ foreach ($driver in $signedDrivers) {
453
+ if ($drivers.Count -ge 250) { break }
454
+ $deviceName = [string]$driver.DeviceName
455
+ if (-not $deviceName) { continue }
456
+ $driverDate = $null
457
+ if ($null -ne $driver.DriverDate) {
458
+ try { $driverDate = ([datetime]$driver.DriverDate).ToString('yyyy-MM-dd') } catch { $driverDate = $null }
459
+ }
460
+ $driverDeviceId = [string]$driver.DeviceID
461
+ $driverProblem = $null
462
+ if ($driverDeviceId -and $problemByDeviceId.ContainsKey($driverDeviceId)) {
463
+ $driverProblem = [string]$problemByDeviceId[$driverDeviceId]
464
+ }
465
+ $drivers += [ordered]@{
466
+ name = $deviceName
467
+ class = [string]$driver.DeviceClass
468
+ manufacturer = [string]$driver.Manufacturer
469
+ version = [string]$driver.DriverVersion
470
+ date = $driverDate
471
+ signer = [string]$driver.DriverProviderName
472
+ inf = [string]$driver.InfName
473
+ deviceId = $driverDeviceId
474
+ kind = 'pnp'
475
+ problem = $driverProblem
476
+ }
477
+ }
478
+ } catch { $errors += ('Win32_PnPSignedDriver: ' + $_.Exception.Message) }
479
+
480
+ # -------------------------------------------------------------------- emit --
481
+ $result = [ordered]@{
482
+ generatedAt = ([DateTimeOffset]::UtcNow).ToUnixTimeMilliseconds()
483
+ cpu = $cpu
484
+ memory = $memory
485
+ videoControllers = $videoControllers
486
+ monitors = $monitors
487
+ physicalDisks = $physicalDisks
488
+ diskDrives = $diskDrives
489
+ volumes = $volumes
490
+ battery = $battery
491
+ usb = $usb
492
+ bluetoothControllers = $bluetoothControllers
493
+ bluetoothDevices = $bluetoothDevices
494
+ audio = $audio
495
+ cameras = $cameras
496
+ drivers = $drivers
497
+ driverProblems = $driverProblems
498
+ errors = $errors
499
+ }
500
+
501
+ $result | ConvertTo-Json -Depth 8 -Compress