@@ -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+
3885function 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