|
1 | 1 | # Copyright (c) Microsoft Corporation.
|
2 | 2 | # Licensed under the MIT License.
|
3 |
| - |
4 | 3 | [CmdletBinding()]
|
5 | 4 | param(
|
6 |
| - [ValidateSet('List','Get','Set','Test','Validate')] |
7 |
| - $Operation = 'List', |
8 |
| - [Parameter(ValueFromPipeline)] |
9 |
| - $stdinput |
| 5 | + [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'Operation to perform. Choose from List, Get, Set, Test, Validate.')] |
| 6 | + [ValidateSet('List', 'Get', 'Set', 'Test', 'Validate')] |
| 7 | + [string]$Operation, |
| 8 | + [Parameter(Mandatory = $false, Position = 1, ValueFromPipeline = $true, HelpMessage = 'Configuration or resource input in JSON format.')] |
| 9 | + [string]$jsonInput = '@{}' |
10 | 10 | )
|
11 | 11 |
|
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 |
| - |
18 |
| -$ProgressPreference = 'Ignore' |
19 |
| -$WarningPreference = 'Ignore' |
20 |
| -$VerbosePreference = 'Ignore' |
21 |
| - |
22 |
| -function Write-Trace { |
23 |
| - param( |
24 |
| - [string]$message, |
25 |
| - [string]$level = 'Error' |
26 |
| - ) |
27 |
| - |
28 |
| - $trace = [pscustomobject]@{ |
29 |
| - $level.ToLower() = $message |
30 |
| - } | ConvertTo-Json -Compress |
31 |
| - |
32 |
| - $host.ui.WriteErrorLine($trace) |
33 |
| -} |
34 |
| - |
35 |
| -if ($Operation -eq 'List') |
36 |
| -{ |
37 |
| - $clases = Get-CimClass |
38 |
| - |
39 |
| - foreach ($r in $clases) |
40 |
| - { |
41 |
| - $version_string = ""; |
42 |
| - $author_string = ""; |
43 |
| - |
44 |
| - $propertyList = @() |
45 |
| - foreach ($p in $r.CimClassProperties) |
46 |
| - { |
47 |
| - if ($p.Name) |
48 |
| - { |
49 |
| - $propertyList += $p.Name |
50 |
| - } |
51 |
| - } |
52 |
| - |
53 |
| - $namespace = $r.CimSystemProperties.Namespace.ToLower().Replace('/','.') |
54 |
| - $classname = $r.CimSystemProperties.ClassName |
55 |
| - $fullResourceTypeName = "$namespace/$classname" |
56 |
| - $requiresString = "Microsoft.Windows/WMI" |
| 12 | +# Import private functions |
| 13 | +$wmiAdapter = Import-Module "$PSScriptRoot/wmiAdapter.psm1" -Force -PassThru |
57 | 14 |
|
58 |
| - $z = [pscustomobject]@{ |
59 |
| - type = $fullResourceTypeName; |
60 |
| - kind = 'resource'; |
61 |
| - version = $version_string; |
62 |
| - capabilities = @('get'); |
63 |
| - path = ""; |
64 |
| - directory = ""; |
65 |
| - implementedAs = ""; |
66 |
| - author = $author_string; |
67 |
| - properties = $propertyList; |
68 |
| - requireAdapter = $requiresString |
69 |
| - } |
| 15 | +if ('Validate' -ne $Operation) { |
| 16 | + # initialize OUTPUT as array |
| 17 | + $result = [System.Collections.Generic.List[Object]]::new() |
70 | 18 |
|
71 |
| - $z | ConvertTo-Json -Compress |
72 |
| - } |
| 19 | + Write-DscTrace -Operation Debug -Message "jsonInput=$jsonInput" |
73 | 20 | }
|
74 |
| -elseif ($Operation -eq 'Get') |
75 |
| -{ |
76 |
| - $inputobj_pscustomobj = $null |
77 |
| - if ($stdinput) |
78 |
| - { |
79 |
| - $inputobj_pscustomobj = $stdinput | ConvertFrom-Json |
80 |
| - } |
81 | 21 |
|
82 |
| - $result = @() |
| 22 | +# Adding some debug info to STDERR |
| 23 | +'PSVersion=' + $PSVersionTable.PSVersion.ToString() | Write-DscTrace |
| 24 | +'PSPath=' + $PSHome | Write-DscTrace |
| 25 | +'PSModulePath=' + $env:PSModulePath | Write-DscTrace |
83 | 26 |
|
84 |
| - foreach ($r in $inputobj_pscustomobj.resources) |
85 |
| - { |
86 |
| - $type_fields = $r.type -split "/" |
87 |
| - $wmi_namespace = $type_fields[0].Replace('.','\') |
88 |
| - $wmi_classname = $type_fields[1] |
| 27 | +switch ($Operation) { |
| 28 | + 'List' { |
| 29 | + $clases = Get-CimClass |
89 | 30 |
|
90 |
| - # TODO: identify key properties and add WHERE clause to the query |
91 |
| - if ($r.properties) |
92 |
| - { |
93 |
| - $query = "SELECT $($r.properties.psobject.properties.name -join ',') FROM $wmi_classname" |
94 |
| - $where = " WHERE " |
95 |
| - $useWhere = $false |
96 |
| - $first = $true |
97 |
| - foreach ($property in $r.properties.psobject.properties) |
98 |
| - { |
99 |
| - # TODO: validate property against the CIM class to give better error message |
100 |
| - if ($null -ne $property.value) |
101 |
| - { |
102 |
| - $useWhere = $true |
103 |
| - if ($first) |
104 |
| - { |
105 |
| - $first = $false |
106 |
| - } |
107 |
| - else |
108 |
| - { |
109 |
| - $where += " AND " |
110 |
| - } |
| 31 | + foreach ($r in $clases) { |
| 32 | + $version_string = "" |
| 33 | + $author_string = "" |
| 34 | + $description = "" |
111 | 35 |
|
112 |
| - if ($property.TypeNameOfValue -eq "System.String") |
113 |
| - { |
114 |
| - $where += "$($property.Name) = '$($property.Value)'" |
115 |
| - } |
116 |
| - else |
117 |
| - { |
118 |
| - $where += "$($property.Name) = $($property.Value)" |
119 |
| - } |
| 36 | + $propertyList = @() |
| 37 | + foreach ($p in $r.CimClassProperties) { |
| 38 | + if ($p.Name) { |
| 39 | + $propertyList += $p.Name |
120 | 40 | }
|
121 | 41 | }
|
122 |
| - if ($useWhere) |
123 |
| - { |
124 |
| - $query += $where |
125 |
| - } |
126 |
| - Write-Trace -Level Trace -message "Query: $query" |
127 |
| - $wmi_instances = Get-CimInstance -Namespace $wmi_namespace -Query $query -ErrorAction Stop |
| 42 | + |
| 43 | + $namespace = $r.CimSystemProperties.Namespace.ToLower().Replace('/', '.') |
| 44 | + $classname = $r.CimSystemProperties.ClassName |
| 45 | + $fullResourceTypeName = "$namespace/$classname" |
| 46 | + $requiresString = "Microsoft.Windows/WMI" |
| 47 | + |
| 48 | + # OUTPUT dsc is expecting the following properties |
| 49 | + [resourceOutput]@{ |
| 50 | + type = $fullResourceTypeName |
| 51 | + kind = 'resource' |
| 52 | + version = $version_string |
| 53 | + capabilities = @('get', 'set', 'test') |
| 54 | + path = "" |
| 55 | + directory = "" |
| 56 | + implementedAs = "" |
| 57 | + author = $author_string |
| 58 | + properties = $propertyList |
| 59 | + requireAdapter = $requiresString |
| 60 | + description = $description |
| 61 | + } | ConvertTo-Json -Compress |
128 | 62 | }
|
129 |
| - else |
130 |
| - { |
131 |
| - $wmi_instances = Get-CimInstance -Namespace $wmi_namespace -ClassName $wmi_classname -ErrorAction Stop |
| 63 | + } |
| 64 | + { @('Get', 'Set', 'Test') -contains $_ } { |
| 65 | + $desiredState = $wmiAdapter.invoke( { param($jsonInput) Get-DscResourceObject -jsonInput $jsonInput }, $jsonInput ) |
| 66 | + if ($null -eq $desiredState) { |
| 67 | + "Failed to create configuration object from provided input JSON." | Write-DscTrace -Operation Error |
| 68 | + exit 1 |
132 | 69 | }
|
133 | 70 |
|
134 |
| - if ($wmi_instances) |
135 |
| - { |
136 |
| - $instance_result = [ordered]@{} |
137 |
| - # TODO: for a `Get`, they key property must be provided so a specific instance is returned rather than just the first |
138 |
| - $wmi_instance = $wmi_instances[0] # for 'Get' we return just first matching instance; for 'export' we return all instances |
139 |
| - $wmi_instance.psobject.properties | %{ |
140 |
| - if (($_.Name -ne "type") -and (-not $_.Name.StartsWith("Cim"))) |
141 |
| - { |
142 |
| - if ($r.properties) |
143 |
| - { |
144 |
| - if ($r.properties.psobject.properties.name -contains $_.Name) |
145 |
| - { |
146 |
| - $instance_result[$_.Name] = $_.Value |
147 |
| - } |
148 |
| - } |
149 |
| - else |
150 |
| - { |
151 |
| - $instance_result[$_.Name] = $_.Value |
152 |
| - } |
153 |
| - } |
| 71 | + foreach ($ds in $desiredState) { |
| 72 | + # process the INPUT (desiredState) for each resource as dscresourceInfo and return the OUTPUT as actualState |
| 73 | + $actualstate = $wmiAdapter.Invoke( { param($op, $ds) Invoke-DscWmi -Operation $op -DesiredState $ds }, $Operation, $ds) |
| 74 | + if ($null -eq $actualState) { |
| 75 | + "Incomplete GET for resource $($ds.Type)" | Write-DscTrace -Operation Error |
| 76 | + exit 1 |
154 | 77 | }
|
155 | 78 |
|
156 |
| - $result += [pscustomobject]@{ name = $r.name; type = $r.type; properties = $instance_result } |
| 79 | + $result += $actualstate |
157 | 80 | }
|
158 |
| - } |
159 | 81 |
|
160 |
| - @{result = $result } | ConvertTo-Json -Depth 10 -Compress |
161 |
| -} |
162 |
| -elseif ($Operation -eq 'Validate') |
163 |
| -{ |
164 |
| - # TODO: this is placeholder |
165 |
| - @{ valid = $true } | ConvertTo-Json |
| 82 | + # OUTPUT json to stderr for debug, and to stdout |
| 83 | + "jsonOutput=$($result | ConvertTo-Json -Depth 10 -Compress)" | Write-DscTrace -Operation Debug |
| 84 | + return (@{ result = $result } | ConvertTo-Json -Depth 10 -Compress) |
| 85 | + } |
| 86 | + 'Validate' { |
| 87 | + # TODO: VALIDATE not implemented |
| 88 | + |
| 89 | + # OUTPUT |
| 90 | + @{ valid = $true } | ConvertTo-Json |
| 91 | + } |
| 92 | + Default { |
| 93 | + Write-DscTrace -Operation Error -Message 'Unsupported operation. Please use one of the following: List, Get, Set, Test, Export, Validate' |
| 94 | + } |
166 | 95 | }
|
167 |
| -else |
168 |
| -{ |
169 |
| - Write-Trace "ERROR: Unsupported operation requested from wmigroup.resource.ps1" |
| 96 | + |
| 97 | +# output format for resource list |
| 98 | +class resourceOutput { |
| 99 | + [string] $type |
| 100 | + [string] $kind |
| 101 | + [string] $version |
| 102 | + [string[]] $capabilities |
| 103 | + [string] $path |
| 104 | + [string] $directory |
| 105 | + [string] $implementedAs |
| 106 | + [string] $author |
| 107 | + [string[]] $properties |
| 108 | + [string] $requireAdapter |
| 109 | + [string] $description |
170 | 110 | }
|
0 commit comments