|
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