Skip to content

Commit 52329a5

Browse files
authored
Merge pull request #279 from anmenaga/wmi_provider
WMI resource provider
2 parents b7d5b60 + 667b916 commit 52329a5

File tree

8 files changed

+240
-2
lines changed

8 files changed

+240
-2
lines changed

build.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ $projects = @(
119119
"tools/test_group_resource",
120120
"y2j"
121121
"powershellgroup"
122+
"wmigroup"
122123
"resources/brew"
123124
"tools/dsctest"
124125
)

dsc_lib/src/configure/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ impl Configurator {
334334

335335
debug!("resource_type {}", &resource.resource_type);
336336
//TODO: remove this after schema validation for classic PS resources is implemented
337-
if resource.resource_type == "DSC/PowerShellGroup" {continue;}
337+
if (resource.resource_type == "DSC/PowerShellGroup")
338+
|| (resource.resource_type == "DSC/WMIGroup") {continue;}
338339

339340
let input = serde_json::to_string(&resource.properties)?;
340341
let schema = match dsc_resource.schema() {

dsc_lib/src/dscresources/command_resource.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ fn verify_json(resource: &ResourceManifest, cwd: &str, json: &str) -> Result<(),
481481
debug!("resource_type - {}", resource.resource_type);
482482

483483
//TODO: remove this after schema validation for classic PS resources is implemented
484-
if resource.resource_type == "DSC/PowerShellGroup" {return Ok(());}
484+
if (resource.resource_type == "DSC/PowerShellGroup")
485+
|| (resource.resource_type == "DSC/WMIGroup") {return Ok(());}
485486

486487
let schema = get_schema(resource, cwd)?;
487488
let schema: Value = serde_json::from_str(&schema)?;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Example configuration for reading data from Windows WMI
2+
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
3+
resources:
4+
- name: Get info from WMI
5+
type: DSC/WMIGroup
6+
properties:
7+
resources:
8+
- name: Get OS Info
9+
type: root.cimv2/Win32_OperatingSystem
10+
- name: Get BIOS Info
11+
type: root.cimv2/Win32_BIOS
12+
- name: Get Processor Info
13+
type: root.cimv2/Win32_Processor

wmigroup/Tests/wmigroup.tests.ps1

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
Describe 'PowerShellGroup resource tests' {
5+
6+
BeforeAll {
7+
if ($IsWindows)
8+
{
9+
$OldPSModulePath = $env:PSModulePath
10+
$env:PSModulePath += ";" + $PSScriptRoot
11+
12+
$configPath = Join-path $PSScriptRoot "test_wmi_config.dsc.yaml"
13+
14+
$dscPath = (get-command dsc -CommandType Application).Path
15+
$dscFolder = Split-Path -Path $dscPath
16+
$wmiGroupOptoutFile = Join-Path $dscFolder "wmigroup.dsc.resource.json.optout"
17+
$wmiGroupOptinFile = Join-Path $dscFolder "wmigroup.dsc.resource.json"
18+
Rename-Item -Path $wmiGroupOptoutFile -NewName $wmiGroupOptinFile
19+
}
20+
}
21+
AfterAll {
22+
if ($IsWindows)
23+
{
24+
$env:PSModulePath = $OldPSModulePath
25+
Rename-Item -Path $wmiGroupOptinFile -NewName $wmiGroupOptoutFile
26+
}
27+
}
28+
29+
It 'List shows WMI resources' -Skip:(!$IsWindows){
30+
31+
$r = dsc resource list *OperatingSystem*
32+
$LASTEXITCODE | Should -Be 0
33+
$res = $r | ConvertFrom-Json
34+
$res.Count | Should -BeGreaterOrEqual 1
35+
}
36+
37+
It 'Get works on an individual WMI resource' -Skip:(!$IsWindows){
38+
39+
$r = dsc resource get -r root.cimv2/Win32_OperatingSystem
40+
$LASTEXITCODE | Should -Be 0
41+
$res = $r | ConvertFrom-Json
42+
$res.actualState.CreationClassName | Should -Be "Win32_OperatingSystem"
43+
}
44+
45+
It 'Get works on a config with WMI resources' -Skip:(!$IsWindows){
46+
47+
$r = Get-Content -Raw $configPath | dsc config get
48+
$LASTEXITCODE | Should -Be 0
49+
$res = $r | ConvertFrom-Json
50+
$res.results[0].result.actualState[0].LastBootUpTime | Should -Not -BeNull
51+
$res.results[0].result.actualState[1].BiosCharacteristics | Should -Not -BeNull
52+
$res.results[0].result.actualState[2].NumberOfLogicalProcessors | Should -Not -BeNull
53+
}
54+
}

wmigroup/copy_files.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
wmigroup.resource.ps1
2+
wmigroup.dsc.resource.json.optout
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
3+
"type": "DSC/WMIGroup",
4+
"version": "0.1.0",
5+
"description": "Resource provider to WMI resources.",
6+
"tags": [
7+
"PowerShell"
8+
],
9+
"provider": {
10+
"list": {
11+
"executable": "powershell",
12+
"args": [
13+
"-NoLogo",
14+
"-NonInteractive",
15+
"-NoProfile",
16+
"-Command",
17+
"./wmigroup.resource.ps1 List"
18+
]
19+
},
20+
"config": "full"
21+
},
22+
"get": {
23+
"executable": "powershell",
24+
"args": [
25+
"-NoLogo",
26+
"-NonInteractive",
27+
"-NoProfile",
28+
"-Command",
29+
"$Input | ./wmigroup.resource.ps1 Get"
30+
],
31+
"input": "stdin"
32+
},
33+
"exitCodes": {
34+
"0": "Success",
35+
"1": "Error"
36+
}
37+
}

wmigroup/wmigroup.resource.ps1

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
[CmdletBinding()]
5+
param(
6+
[ValidateSet('List','Get','Set','Test')]
7+
$Operation = 'List',
8+
[Parameter(ValueFromPipeline)]
9+
$stdinput
10+
)
11+
12+
$ProgressPreference = 'Ignore'
13+
$WarningPreference = 'Ignore'
14+
$VerbosePreference = 'Ignore'
15+
16+
if ($Operation -eq 'List')
17+
{
18+
$clases = Get-CimClass
19+
20+
foreach ($r in $clases)
21+
{
22+
$version_string = "";
23+
$author_string = "";
24+
$moduleName = "";
25+
26+
$propertyList = @()
27+
foreach ($p in $r.CimClassProperties)
28+
{
29+
if ($p.Name)
30+
{
31+
$propertyList += $p.Name
32+
}
33+
}
34+
35+
$namespace = $r.CimSystemProperties.Namespace.ToLower().Replace('/','.')
36+
$classname = $r.CimSystemProperties.ClassName
37+
$fullResourceTypeName = "$namespace/$classname"
38+
$requiresString = "DSC/WMIGroup"
39+
40+
$z = [pscustomobject]@{
41+
type = $fullResourceTypeName;
42+
version = $version_string;
43+
path = "";
44+
directory = "";
45+
implementedAs = "";
46+
author = $author_string;
47+
properties = $propertyList;
48+
requires = $requiresString
49+
}
50+
51+
$z | ConvertTo-Json -Compress
52+
}
53+
}
54+
elseif ($Operation -eq 'Get')
55+
{
56+
$inputobj_pscustomobj = $null
57+
if ($stdinput)
58+
{
59+
$inputobj_pscustomobj = $stdinput | ConvertFrom-Json
60+
}
61+
62+
$result = @()
63+
64+
if ($inputobj_pscustomobj.resources) # we are processing a config batch
65+
{
66+
foreach($r in $inputobj_pscustomobj.resources)
67+
{
68+
$type_fields = $r.type -split "/"
69+
$wmi_namespace = $type_fields[0].Replace('.','\')
70+
$wmi_classname = $type_fields[1]
71+
72+
#TODO: add filtering based on supplied properties of $r
73+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname
74+
75+
if ($wmi_instances)
76+
{
77+
$instance_result = @{}
78+
$wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances
79+
$wmi_instance.psobject.properties | %{
80+
if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim")))
81+
{
82+
$instance_result[$_.Name] = $_.Value
83+
}
84+
}
85+
86+
$result += @($instance_result)
87+
}
88+
else
89+
{
90+
$errmsg = "Can not find type " + $r.type + "; please ensure that Get-CimInstance returns this resource type"
91+
Write-Error $errmsg
92+
exit 1
93+
}
94+
}
95+
}
96+
else # we are processing an individual resource call
97+
{
98+
$type_fields = $inputobj_pscustomobj.type -split "/"
99+
$wmi_namespace = $type_fields[0].Replace('.','\')
100+
$wmi_classname = $type_fields[1]
101+
102+
#TODO: add filtering based on supplied properties of $inputobj_pscustomobj
103+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname
104+
105+
if ($wmi_instances)
106+
{
107+
$wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances
108+
$result = @{}
109+
$wmi_instance.psobject.properties | %{
110+
if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim")))
111+
{
112+
$result[$_.Name] = $_.Value
113+
}
114+
}
115+
}
116+
else
117+
{
118+
$errmsg = "Can not find type " + $inputobj_pscustomobj.type + "; please ensure that Get-CimInstance returns this resource type"
119+
Write-Error $errmsg
120+
exit 1
121+
}
122+
}
123+
124+
$result | ConvertTo-Json -Compress
125+
}
126+
else
127+
{
128+
Write-Error "ERROR: Unsupported operation requested from wmigroup.resource.ps1"
129+
}

0 commit comments

Comments
 (0)