Skip to content

Commit 01bc057

Browse files
authored
Merge pull request #548 from SteveL-MSFT/demo
Update WMI adapter to perform query based on provided properties
2 parents ae330c2 + f2da909 commit 01bc057

File tree

5 files changed

+137
-26
lines changed

5 files changed

+137
-26
lines changed

dsc/examples/wmi.dsc.yaml

-10
This file was deleted.

dsc/examples/wmi_inventory.dsc.yaml

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json
2+
resources:
3+
- name: WMI
4+
type: Microsoft.Windows/WMI
5+
properties:
6+
resources:
7+
- name: computer system
8+
type: root.cimv2/Win32_ComputerSystem
9+
properties:
10+
name:
11+
domain:
12+
totalphysicalmemory:
13+
model:
14+
manufacturer:
15+
- name: operating system
16+
type: root.cimv2/Win32_OperatingSystem
17+
properties:
18+
caption:
19+
version:
20+
osarchitecture:
21+
oslanguage:
22+
- name: system enclosure
23+
type: root.cimv2/Win32_SystemEnclosure
24+
properties:
25+
manufacturer:
26+
model:
27+
serialnumber:
28+
- name: bios
29+
type: root.cimv2/Win32_BIOS
30+
properties:
31+
manufacturer:
32+
version:
33+
serialnumber:
34+
- name: network adapter
35+
type: root.cimv2/Win32_NetworkAdapter
36+
properties:
37+
name:
38+
macaddress:
39+
adaptertype:
40+
netconnectionid:
41+
serviceName:
42+
netconnectionstatus: 2

wmi-adapter/Tests/test_wmi_config.dsc.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ resources:
77
resources:
88
- name: Get OS Info
99
type: root.cimv2/Win32_OperatingSystem
10+
properties:
11+
caption:
12+
version:
13+
osarchitecture:
1014
- name: Get BIOS Info
1115
type: root.cimv2/Win32_BIOS
1216
- name: Get Processor Info

wmi-adapter/Tests/wmi.tests.ps1

+10-6
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,22 @@ Describe 'WMI adapter resource tests' {
4040
$r = Get-Content -Raw $configPath | dsc config get
4141
$LASTEXITCODE | Should -Be 0
4242
$res = $r | ConvertFrom-Json
43-
$res.results[0].result.actualState[0].LastBootUpTime | Should -Not -BeNull
44-
$res.results[0].result.actualState[1].BiosCharacteristics | Should -Not -BeNull
45-
$res.results[0].result.actualState[2].NumberOfLogicalProcessors | Should -Not -BeNull
43+
$res.results[0].result.actualState[0].LastBootUpTime | Should -BeNullOrEmpty
44+
$res.results[0].result.actualState[0].Caption | Should -Not -BeNullOrEmpty
45+
$res.results[0].result.actualState[0].Version | Should -Not -BeNullOrEmpty
46+
$res.results[0].result.actualState[0].OSArchitecture | Should -Not -BeNullOrEmpty
4647
}
4748

4849
It 'Example config works' -Skip:(!$IsWindows) {
49-
$configPath = Join-Path $PSScriptRoot '..\..\dsc\examples\wmi.dsc.yaml'
50+
$configPath = Join-Path $PSScriptRoot '..\..\dsc\examples\wmi_inventory.dsc.yaml'
5051
$r = dsc config get -p $configPath
5152
$LASTEXITCODE | Should -Be 0
5253
$r | Should -Not -BeNullOrEmpty
5354
$res = $r | ConvertFrom-Json
54-
$res.results[0].result.actualState[0].Model | Should -Not -BeNullOrEmpty
55-
$res.results[0].result.actualState[1].Description | Should -Not -BeNullOrEmpty
55+
$res.results[0].result.actualState[0].Name | Should -Not -BeNullOrEmpty
56+
$res.results[0].result.actualState[0].BootupState | Should -BeNullOrEmpty
57+
$res.results[0].result.actualState[1].Caption | Should -Not -BeNullOrEmpty
58+
$res.results[0].result.actualState[1].BuildNumber | Should -BeNullOrEmpty
59+
$res.results[0].result.actualState[4].AdapterType | Should -BeLike "Ethernet*"
5660
}
5761
}

wmi-adapter/wmi.resource.ps1

+81-10
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,29 @@ param(
99
$stdinput
1010
)
1111

12+
# catch any un-caught exception and write it to the error stream
13+
trap {
14+
Write-Trace -Level Error -message $_.Exception.Message
15+
exit 1
16+
}
17+
1218
$ProgressPreference = 'Ignore'
1319
$WarningPreference = 'Ignore'
1420
$VerbosePreference = 'Ignore'
1521

22+
function Write-Trace {
23+
param(
24+
[string]$message,
25+
[string]$level = 'Error'
26+
)
27+
28+
$trace = [pscustomobject]@{
29+
$level = $message
30+
} | ConvertTo-Json -Compress
31+
32+
$host.ui.WriteErrorLine($trace)
33+
}
34+
1635
function IsConfiguration($obj) {
1736
if ($null -ne $obj.metadata -and $null -ne $obj.metadata.'Microsoft.DSC' -and $obj.metadata.'Microsoft.DSC'.context -eq 'Configuration') {
1837
return $true
@@ -29,7 +48,6 @@ if ($Operation -eq 'List')
2948
{
3049
$version_string = "";
3150
$author_string = "";
32-
$moduleName = "";
3351

3452
$propertyList = @()
3553
foreach ($p in $r.CimClassProperties)
@@ -79,17 +97,69 @@ elseif ($Operation -eq 'Get')
7997
$wmi_namespace = $type_fields[0].Replace('.','\')
8098
$wmi_classname = $type_fields[1]
8199

82-
#TODO: add filtering based on supplied properties of $r
83-
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname
100+
# TODO: identify key properties and add WHERE clause to the query
101+
if ($r.properties)
102+
{
103+
$query = "SELECT $($r.properties.psobject.properties.name -join ',') FROM $wmi_classname"
104+
$where = " WHERE "
105+
$useWhere = $false
106+
$first = $true
107+
foreach ($property in $r.properties.psobject.properties)
108+
{
109+
# TODO: validate property against the CIM class to give better error message
110+
if ($null -ne $property.value)
111+
{
112+
$useWhere = $true
113+
if ($first)
114+
{
115+
$first = $false
116+
}
117+
else
118+
{
119+
$where += " AND "
120+
}
121+
122+
if ($property.TypeNameOfValue -eq "System.String")
123+
{
124+
$where += "$($property.Name) = '$($property.Value)'"
125+
}
126+
else
127+
{
128+
$where += "$($property.Name) = $($property.Value)"
129+
}
130+
}
131+
}
132+
if ($useWhere)
133+
{
134+
$query += $where
135+
}
136+
Write-Trace -Level Trace -message "Query: $query"
137+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -Query $query -ErrorAction Stop
138+
}
139+
else
140+
{
141+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname -ErrorAction Stop
142+
}
84143

85144
if ($wmi_instances)
86145
{
87146
$instance_result = @{}
147+
# TODO: for a `Get`, they key property must be provided so a specific instance is returned rather than just the first
88148
$wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances
89149
$wmi_instance.psobject.properties | %{
90150
if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim")))
91151
{
92-
$instance_result[$_.Name] = $_.Value
152+
if ($r.properties)
153+
{
154+
if ($r.properties.psobject.properties.name -contains $_.Name)
155+
{
156+
$instance_result[$_.Name] = $_.Value
157+
}
158+
}
159+
else
160+
{
161+
$instance_result[$_.Name] = $_.Value
162+
}
93163
}
94164
}
95165

@@ -98,7 +168,7 @@ elseif ($Operation -eq 'Get')
98168
else
99169
{
100170
$errmsg = "Can not find type " + $r.type + "; please ensure that Get-CimInstance returns this resource type"
101-
Write-Error $errmsg
171+
Write-Trace $errmsg
102172
exit 1
103173
}
104174
}
@@ -110,11 +180,12 @@ elseif ($Operation -eq 'Get')
110180
$wmi_classname = $type_fields[1]
111181

112182
#TODO: add filtering based on supplied properties of $inputobj_pscustomobj
113-
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname
183+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname -ErrorAction Stop
114184

115185
if ($wmi_instances)
116186
{
117-
$wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances
187+
# TODO: there's duplicate code here between configuration and non-configuration execution and should be refactored into a helper
188+
$wmi_instance = $wmi_instances[0]
118189
$result = @{}
119190
$wmi_instance.psobject.properties | %{
120191
if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim")))
@@ -126,7 +197,7 @@ elseif ($Operation -eq 'Get')
126197
else
127198
{
128199
$errmsg = "Can not find type " + $inputobj_pscustomobj.type + "; please ensure that Get-CimInstance returns this resource type"
129-
Write-Error $errmsg
200+
Write-Trace $errmsg
130201
exit 1
131202
}
132203
}
@@ -140,5 +211,5 @@ elseif ($Operation -eq 'Validate')
140211
}
141212
else
142213
{
143-
Write-Error "ERROR: Unsupported operation requested from wmigroup.resource.ps1"
144-
}
214+
Write-Trace "ERROR: Unsupported operation requested from wmigroup.resource.ps1"
215+
}

0 commit comments

Comments
 (0)