Skip to content

Commit 7fd2f90

Browse files
committed
Start implementing set
1 parent 582167e commit 7fd2f90

File tree

1 file changed

+171
-60
lines changed

1 file changed

+171
-60
lines changed

wmi-adapter/wmiAdapter.psm1

Lines changed: 171 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,53 @@ function Get-DscResourceObject {
3535
return $desiredState
3636
}
3737

38+
function GetWmiInstance {
39+
[CmdletBinding()]
40+
param
41+
(
42+
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
43+
[psobject]$DesiredState
44+
)
45+
46+
$type_fields = $DesiredState.type -split "/"
47+
$wmi_namespace = $type_fields[0].Replace('.', '\')
48+
$wmi_classname = $type_fields[1]
49+
50+
if ($DesiredState.properties) {
51+
$props = $DesiredState.properties.psobject.Properties | Where-Object { $_.Name -notin @('methodName', 'parameters') }
52+
$query = "SELECT $($props.Name -join ',') FROM $wmi_classname"
53+
$where = " WHERE "
54+
$useWhere = $false
55+
$first = $true
56+
foreach ($property in $props) {
57+
# TODO: validate property against the CIM class to give better error message
58+
if ($null -ne $property.value) {
59+
$useWhere = $true
60+
if ($first) {
61+
$first = $false
62+
} else {
63+
$where += " AND "
64+
}
65+
66+
if ($property.TypeNameOfValue -eq "System.String") {
67+
$where += "$($property.Name) = '$($property.Value)'"
68+
} else {
69+
$where += "$($property.Name) = $($property.Value)"
70+
}
71+
}
72+
}
73+
if ($useWhere) {
74+
$query += $where
75+
}
76+
"Query: $query" | Write-DscTrace -Operation Debug
77+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -Query $query -ErrorAction Stop
78+
} else {
79+
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname -ErrorAction Stop
80+
}
81+
82+
return $wmi_instances
83+
}
84+
3885
function GetCimSpace {
3986
[CmdletBinding()]
4087
param
@@ -58,43 +105,10 @@ function GetCimSpace {
58105

59106
foreach ($r in $DesiredState) {
60107

61-
$type_fields = $r.type -split "/"
62-
$wmi_namespace = $type_fields[0].Replace('.', '\')
63-
$wmi_classname = $type_fields[1]
64-
65108
switch ($Operation) {
66109
'Get' {
67110
# TODO: identify key properties and add WHERE clause to the query
68-
if ($r.properties) {
69-
$query = "SELECT $($r.properties.psobject.properties.name -join ',') FROM $wmi_classname"
70-
$where = " WHERE "
71-
$useWhere = $false
72-
$first = $true
73-
foreach ($property in $r.properties.psobject.properties) {
74-
# TODO: validate property against the CIM class to give better error message
75-
if ($null -ne $property.value) {
76-
$useWhere = $true
77-
if ($first) {
78-
$first = $false
79-
} else {
80-
$where += " AND "
81-
}
82-
83-
if ($property.TypeNameOfValue -eq "System.String") {
84-
$where += "$($property.Name) = '$($property.Value)'"
85-
} else {
86-
$where += "$($property.Name) = $($property.Value)"
87-
}
88-
}
89-
}
90-
if ($useWhere) {
91-
$query += $where
92-
}
93-
"Query: $query" | Write-DscTrace -Operation Debug
94-
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -Query $query -ErrorAction Stop
95-
} else {
96-
$wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname -ErrorAction Stop
97-
}
111+
$wmi_instances = GetWmiInstance -DesiredState $DesiredState
98112

99113
if ($wmi_instances) {
100114
$instance_result = [ordered]@{}
@@ -119,8 +133,14 @@ function GetCimSpace {
119133

120134
}
121135
'Set' {
122-
# TODO: implement set
136+
$wmi_instance = ValidateCimMethodAndArguments -DesiredState $r
137+
InvokeCimMethod -CimInstance $wmi_instance.CimInstance -MethodName $wmi_instance.MethodName -Arguments $wmi_instance.Parameters
123138

139+
$result += [PSCustomObject]@{
140+
name = $r.name
141+
type = $r.type
142+
properties = $null # Set operation does not return properties
143+
}
124144
}
125145
'Test' {
126146
# TODO: implement test
@@ -140,7 +160,7 @@ function ValidateCimMethodAndArguments {
140160

141161
$methodName = $DesiredState.properties.psobject.properties | Where-Object -Property Name -EQ 'methodName' | Select-Object -ExpandProperty Value
142162
if (-not $methodName) {
143-
"'methodName' property is required for invoking a WMI method." | Write-DscTrace -Operation Error
163+
"'methodName' property is required for invoking a WMI/CIM method." | Write-DscTrace -Operation Error
144164
exit 1
145165
}
146166

@@ -149,16 +169,125 @@ function ValidateCimMethodAndArguments {
149169

150170
$cimClass = Get-CimClass -Namespace $namespace -ClassName $className -MethodName $methodName
151171

172+
$arguments = @{}
152173
if ($cimClass) {
153-
$properties = $DesiredState.properties.psobject.properties | Where-Object -Property Name -NE 'methodName'
154-
$parameters = $cimClass.CimClassMethods | Where-Object -Property Name -EQ $methodName | Select-Object -ExpandProperty CimMethodParameters
174+
$parameters = ($DesiredState.properties.psobject.properties | Where-Object -Property Name -EQ 'parameters').Value
175+
$cimClassParameters = $cimClass.CimClassMethods | Where-Object -Property Name -EQ $methodName | Select-Object -ExpandProperty Parameters
176+
177+
foreach ($param in $parameters.psobject.Properties.name) {
178+
if ($cimClassParameters.Name -notcontains $param) {
179+
"'$param' is not a valid parameter for method '$methodName' in class '$className'." | Write-DscTrace -Operation Warn
180+
} else {
181+
$arguments += @{
182+
$param = $parameters.$param
183+
}
184+
}
185+
}
186+
187+
$cimInstance = GetWmiInstance -DesiredState $DesiredState
155188

156-
foreach ($prop in $properties) {
157-
189+
$i = [PSCustomObject]@{
190+
CimInstance = $cimInstance
191+
Parameters = $arguments
192+
MethodName = $methodName
158193
}
159194
}
160195

161-
return $cimClass
196+
return $i
197+
}
198+
199+
function InvokeCimMethod
200+
{
201+
[CmdletBinding()]
202+
[OutputType([Microsoft.Management.Infrastructure.CimMethodResult])]
203+
param
204+
(
205+
206+
[Parameter(Mandatory = $true)]
207+
[Microsoft.Management.Infrastructure.CimInstance]
208+
$CimInstance,
209+
210+
[Parameter(Mandatory = $true)]
211+
[System.String]
212+
$MethodName,
213+
214+
[Parameter()]
215+
[System.Collections.Hashtable]
216+
$Arguments
217+
)
218+
219+
$invokeCimMethodParameters = @{
220+
MethodName = $MethodName
221+
ErrorAction = 'Stop'
222+
}
223+
224+
if ($PSBoundParameters.ContainsKey('Arguments') -and $null -ne [string]::IsNullOrEmpty($Arguments))
225+
{
226+
$invokeCimMethodParameters['Arguments'] = $Arguments
227+
}
228+
229+
try
230+
{
231+
$invokeCimMethodResult = $CimInstance | Invoke-CimMethod @invokeCimMethodParameters
232+
}
233+
catch [Microsoft.Management.Infrastructure.CimException]
234+
{
235+
$errMsg = $_.Exception.Message.Trim("")
236+
if ($errMsg -eq 'Invalid method')
237+
{
238+
"Retrying without instance" | Write-DscTrace -Operation Trace
239+
$invokeCimMethodResult = Invoke-CimMethod @invokeCimMethodParameters -ClassName $CimInstance[0].CimClass.CimClassName
240+
}
241+
}
242+
catch
243+
{
244+
"Could not execute 'Invoke-CimMethod' with error message: " + $_.Exception.Message | Write-DscTrace -Operation Error
245+
exit 1
246+
}
247+
248+
<#
249+
Successfully calling the method returns $invokeCimMethodResult.HRESULT -eq 0.
250+
If an general error occur in the Invoke-CimMethod, like calling a method
251+
that does not exist, returns $null in $invokeCimMethodResult.
252+
#>
253+
if ($invokeCimMethodResult.HRESULT)
254+
{
255+
$res = $invokeCimMethodResult.HRESULT
256+
}
257+
else
258+
{
259+
$res = $invokeCimMethodResult.ReturnValue
260+
}
261+
if ($invokeCimMethodResult -and $res -ne 0)
262+
{
263+
if ($invokeCimMethodResult | Get-Member -Name 'ExtendedErrors')
264+
{
265+
<#
266+
The returned object property ExtendedErrors is an array
267+
so that needs to be concatenated.
268+
#>
269+
$errorMessage = $invokeCimMethodResult.ExtendedErrors -join ';'
270+
}
271+
else
272+
{
273+
$errorMessage = $invokeCimMethodResult.Error
274+
}
275+
276+
$hResult = $invokeCimMethodResult.ReturnValue
277+
278+
if ($invokeCimMethodResult.HRESULT)
279+
{
280+
$hResult = $invokeCimMethodResult.HRESULT
281+
}
282+
283+
$errmsg = 'Method {0}() failed with an error. Error: {1} (HRESULT:{2})' -f @(
284+
$MethodName
285+
$errorMessage
286+
$hResult
287+
)
288+
$errMsg | Write-DscTrace -Operation Error
289+
exit 1
290+
}
162291
}
163292

164293

@@ -176,17 +305,7 @@ function Invoke-DscWmi {
176305
$DesiredState
177306
)
178307

179-
switch ($Operation) {
180-
'Get' {
181-
$addToActualState = GetCimSpace -Operation $Operation -DesiredState $DesiredState
182-
}
183-
'Set' {
184-
# TODO: Implement Set operation
185-
}
186-
'Test' {
187-
# TODO: Implement Test operation
188-
}
189-
}
308+
$addToActualState = GetCimSpace -Operation $Operation -DesiredState $DesiredState
190309

191310
return $addToActualState
192311
}
@@ -195,12 +314,4 @@ class dscResourceObject {
195314
[string] $name
196315
[string] $type
197316
[PSCustomObject] $properties
198-
}
199-
200-
$inputObject = [DscResourceObject]@{
201-
name = 'root.cimv2/Win32_Process'
202-
type = 'root.cimv2/Win32_Process'
203-
properties = [PSCustomObject]@{
204-
methodName = 'Create'
205-
}
206317
}

0 commit comments

Comments
 (0)