Skip to content

Commit

Permalink
Merge pull request #279 from anmenaga/wmi_provider
Browse files Browse the repository at this point in the history
WMI resource provider
  • Loading branch information
SteveL-MSFT authored Nov 28, 2023
2 parents b7d5b60 + 667b916 commit 52329a5
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 2 deletions.
1 change: 1 addition & 0 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ $projects = @(
"tools/test_group_resource",
"y2j"
"powershellgroup"
"wmigroup"
"resources/brew"
"tools/dsctest"
)
Expand Down
3 changes: 2 additions & 1 deletion dsc_lib/src/configure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ impl Configurator {

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

let input = serde_json::to_string(&resource.properties)?;
let schema = match dsc_resource.schema() {
Expand Down
3 changes: 2 additions & 1 deletion dsc_lib/src/dscresources/command_resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,8 @@ fn verify_json(resource: &ResourceManifest, cwd: &str, json: &str) -> Result<(),
debug!("resource_type - {}", resource.resource_type);

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

let schema = get_schema(resource, cwd)?;
let schema: Value = serde_json::from_str(&schema)?;
Expand Down
13 changes: 13 additions & 0 deletions wmigroup/Tests/test_wmi_config.dsc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example configuration for reading data from Windows WMI
$schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/10/config/document.json
resources:
- name: Get info from WMI
type: DSC/WMIGroup
properties:
resources:
- name: Get OS Info
type: root.cimv2/Win32_OperatingSystem
- name: Get BIOS Info
type: root.cimv2/Win32_BIOS
- name: Get Processor Info
type: root.cimv2/Win32_Processor
54 changes: 54 additions & 0 deletions wmigroup/Tests/wmigroup.tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

Describe 'PowerShellGroup resource tests' {

BeforeAll {
if ($IsWindows)
{
$OldPSModulePath = $env:PSModulePath
$env:PSModulePath += ";" + $PSScriptRoot

$configPath = Join-path $PSScriptRoot "test_wmi_config.dsc.yaml"

$dscPath = (get-command dsc -CommandType Application).Path
$dscFolder = Split-Path -Path $dscPath
$wmiGroupOptoutFile = Join-Path $dscFolder "wmigroup.dsc.resource.json.optout"
$wmiGroupOptinFile = Join-Path $dscFolder "wmigroup.dsc.resource.json"
Rename-Item -Path $wmiGroupOptoutFile -NewName $wmiGroupOptinFile
}
}
AfterAll {
if ($IsWindows)
{
$env:PSModulePath = $OldPSModulePath
Rename-Item -Path $wmiGroupOptinFile -NewName $wmiGroupOptoutFile
}
}

It 'List shows WMI resources' -Skip:(!$IsWindows){

$r = dsc resource list *OperatingSystem*
$LASTEXITCODE | Should -Be 0
$res = $r | ConvertFrom-Json
$res.Count | Should -BeGreaterOrEqual 1
}

It 'Get works on an individual WMI resource' -Skip:(!$IsWindows){

$r = dsc resource get -r root.cimv2/Win32_OperatingSystem
$LASTEXITCODE | Should -Be 0
$res = $r | ConvertFrom-Json
$res.actualState.CreationClassName | Should -Be "Win32_OperatingSystem"
}

It 'Get works on a config with WMI resources' -Skip:(!$IsWindows){

$r = Get-Content -Raw $configPath | dsc config get
$LASTEXITCODE | Should -Be 0
$res = $r | ConvertFrom-Json
$res.results[0].result.actualState[0].LastBootUpTime | Should -Not -BeNull
$res.results[0].result.actualState[1].BiosCharacteristics | Should -Not -BeNull
$res.results[0].result.actualState[2].NumberOfLogicalProcessors | Should -Not -BeNull
}
}
2 changes: 2 additions & 0 deletions wmigroup/copy_files.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
wmigroup.resource.ps1
wmigroup.dsc.resource.json.optout
37 changes: 37 additions & 0 deletions wmigroup/wmigroup.dsc.resource.json.optout
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$schema": "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/bundled/resource/manifest.json",
"type": "DSC/WMIGroup",
"version": "0.1.0",
"description": "Resource provider to WMI resources.",
"tags": [
"PowerShell"
],
"provider": {
"list": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-Command",
"./wmigroup.resource.ps1 List"
]
},
"config": "full"
},
"get": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-Command",
"$Input | ./wmigroup.resource.ps1 Get"
],
"input": "stdin"
},
"exitCodes": {
"0": "Success",
"1": "Error"
}
}
129 changes: 129 additions & 0 deletions wmigroup/wmigroup.resource.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.

[CmdletBinding()]
param(
[ValidateSet('List','Get','Set','Test')]
$Operation = 'List',
[Parameter(ValueFromPipeline)]
$stdinput
)

$ProgressPreference = 'Ignore'
$WarningPreference = 'Ignore'
$VerbosePreference = 'Ignore'

if ($Operation -eq 'List')
{
$clases = Get-CimClass

foreach ($r in $clases)
{
$version_string = "";
$author_string = "";
$moduleName = "";

$propertyList = @()
foreach ($p in $r.CimClassProperties)
{
if ($p.Name)
{
$propertyList += $p.Name
}
}

$namespace = $r.CimSystemProperties.Namespace.ToLower().Replace('/','.')
$classname = $r.CimSystemProperties.ClassName
$fullResourceTypeName = "$namespace/$classname"
$requiresString = "DSC/WMIGroup"

$z = [pscustomobject]@{
type = $fullResourceTypeName;
version = $version_string;
path = "";
directory = "";
implementedAs = "";
author = $author_string;
properties = $propertyList;
requires = $requiresString
}

$z | ConvertTo-Json -Compress
}
}
elseif ($Operation -eq 'Get')
{
$inputobj_pscustomobj = $null
if ($stdinput)
{
$inputobj_pscustomobj = $stdinput | ConvertFrom-Json
}

$result = @()

if ($inputobj_pscustomobj.resources) # we are processing a config batch
{
foreach($r in $inputobj_pscustomobj.resources)
{
$type_fields = $r.type -split "/"
$wmi_namespace = $type_fields[0].Replace('.','\')
$wmi_classname = $type_fields[1]

#TODO: add filtering based on supplied properties of $r
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname

if ($wmi_instances)
{
$instance_result = @{}
$wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances
$wmi_instance.psobject.properties | %{
if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim")))
{
$instance_result[$_.Name] = $_.Value
}
}

$result += @($instance_result)
}
else
{
$errmsg = "Can not find type " + $r.type + "; please ensure that Get-CimInstance returns this resource type"
Write-Error $errmsg
exit 1
}
}
}
else # we are processing an individual resource call
{
$type_fields = $inputobj_pscustomobj.type -split "/"
$wmi_namespace = $type_fields[0].Replace('.','\')
$wmi_classname = $type_fields[1]

#TODO: add filtering based on supplied properties of $inputobj_pscustomobj
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname

if ($wmi_instances)
{
$wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances
$result = @{}
$wmi_instance.psobject.properties | %{
if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim")))
{
$result[$_.Name] = $_.Value
}
}
}
else
{
$errmsg = "Can not find type " + $inputobj_pscustomobj.type + "; please ensure that Get-CimInstance returns this resource type"
Write-Error $errmsg
exit 1
}
}

$result | ConvertTo-Json -Compress
}
else
{
Write-Error "ERROR: Unsupported operation requested from wmigroup.resource.ps1"
}

0 comments on commit 52329a5

Please sign in to comment.