@@ -20,6 +20,170 @@ function Import-PSDSCModule {
20
20
$PSDesiredStateConfiguration = Import-Module $m - Force - PassThru
21
21
}
22
22
23
+ function Get-DSCResourceModules
24
+ {
25
+ $listPSModuleFolders = $env: PSModulePath.Split ([IO.Path ]::PathSeparator)
26
+ $dscModulePsd1List = [System.Collections.Generic.HashSet [System.String ]]::new()
27
+ foreach ($folder in $listPSModuleFolders )
28
+ {
29
+ if (! (Test-Path $folder ))
30
+ {
31
+ continue
32
+ }
33
+
34
+ foreach ($moduleFolder in Get-ChildItem $folder - Directory)
35
+ {
36
+ $addModule = $false
37
+ foreach ($psd1 in Get-ChildItem - Recurse - Filter " $ ( $moduleFolder.Name ) .psd1" - Path $moduleFolder.fullname - Depth 2 )
38
+ {
39
+ $containsDSCResource = select-string - LiteralPath $psd1 - pattern ' ^[^#]*\bDscResourcesToExport\b.*'
40
+ if ($null -ne $containsDSCResource )
41
+ {
42
+ $dscModulePsd1List.Add ($psd1 ) | Out-Null
43
+ break
44
+ }
45
+ }
46
+ }
47
+ }
48
+
49
+ return $dscModulePsd1List
50
+ }
51
+
52
+ function FindAndParseResourceDefinitions
53
+ {
54
+ [CmdletBinding (HelpUri = ' ' )]
55
+ param (
56
+ [Parameter (Mandatory = $true )]
57
+ [string ]$filePath
58
+ )
59
+
60
+ if (-not (Test-Path $filePath ))
61
+ {
62
+ return
63
+ }
64
+
65
+ if (([System.IO.Path ]::GetExtension($filePath ) -ne " .psm1" ) -and ([System.IO.Path ]::GetExtension($filePath ) -ne " .ps1" ))
66
+ {
67
+ return
68
+ }
69
+
70
+ " Loading resources from '$filePath '" | Write-DscTrace - Operation Trace
71
+ # TODO: Handle class inheritance
72
+ # TODO: Ensure embedded instances in properties are working correctly
73
+ [System.Management.Automation.Language.Token []] $tokens = $null
74
+ [System.Management.Automation.Language.ParseError []] $errors = $null
75
+ $ast = [System.Management.Automation.Language.Parser ]::ParseFile($filePath , [ref ]$tokens , [ref ]$errors )
76
+ foreach ($e in $errors )
77
+ {
78
+ $e | Out-String | Write-DscTrace - Operation Error
79
+ }
80
+
81
+ $resourceDefinitions = $ast.FindAll (
82
+ {
83
+ $typeAst = $args [0 ] -as [System.Management.Automation.Language.TypeDefinitionAst ]
84
+ if ($typeAst )
85
+ {
86
+ foreach ($a in $typeAst.Attributes )
87
+ {
88
+ if ($a.TypeName.Name -eq ' DscResource' )
89
+ {
90
+ return $true ;
91
+ }
92
+ }
93
+ }
94
+
95
+ return $false ;
96
+ },
97
+ $false );
98
+
99
+ $resourceList = [System.Collections.Generic.List [DscResourceInfo ]]::new()
100
+
101
+ foreach ($typeDefinitionAst in $resourceDefinitions )
102
+ {
103
+ $DscResourceInfo = [DscResourceInfo ]::new()
104
+ $DscResourceInfo.Name = $typeDefinitionAst.Name
105
+ $DscResourceInfo.ResourceType = $typeDefinitionAst.Name
106
+ $DscResourceInfo.FriendlyName = $typeDefinitionAst.Name
107
+ $DscResourceInfo.ImplementationDetail = ' ClassBased'
108
+ $DscResourceInfo.Module = $filePath
109
+ $DscResourceInfo.Path = $filePath
110
+ # TODO: ModuleName, Version and ParentPath should be taken from psd1 contents
111
+ $DscResourceInfo.ModuleName = [System.IO.Path ]::GetFileNameWithoutExtension($filePath )
112
+ $DscResourceInfo.ParentPath = [System.IO.Path ]::GetDirectoryName($filePath )
113
+
114
+ $DscResourceInfo.Properties = [System.Collections.Generic.List [DscResourcePropertyInfo ]]::new()
115
+ foreach ($member in $typeDefinitionAst.Members )
116
+ {
117
+ $property = $member -as [System.Management.Automation.Language.PropertyMemberAst ]
118
+ if (($property -eq $null ) -or ($property.IsStatic ))
119
+ {
120
+ continue ;
121
+ }
122
+ $skipProperty = $true
123
+ $isKeyProperty = $false
124
+ foreach ($attr in $property.Attributes )
125
+ {
126
+ if ($attr.TypeName.Name -eq ' DscProperty' )
127
+ {
128
+ $skipProperty = $false
129
+ foreach ($attrArg in $attr.NamedArguments )
130
+ {
131
+ if ($attrArg.ArgumentName -eq ' Key' )
132
+ {
133
+ $isKeyProperty = $true
134
+ }
135
+ }
136
+ }
137
+ }
138
+ if ($skipProperty )
139
+ {
140
+ continue ;
141
+ }
142
+
143
+ [DscResourcePropertyInfo ]$prop = [DscResourcePropertyInfo ]::new()
144
+ $prop.Name = $property.Name
145
+ $prop.PropertyType = $property.PropertyType.TypeName.Name
146
+ $prop.IsMandatory = $isKeyProperty
147
+ $DscResourceInfo.Properties.Add ($prop )
148
+ }
149
+
150
+ $resourceList.Add ($DscResourceInfo )
151
+ }
152
+
153
+ return $resourceList
154
+ }
155
+
156
+ function LoadPowerShellClassResourcesFromModule
157
+ {
158
+ [CmdletBinding (HelpUri = ' ' )]
159
+ param (
160
+ [Parameter (Mandatory = $true )]
161
+ [PSModuleInfo ]$moduleInfo
162
+ )
163
+
164
+ if ($moduleInfo.RootModule )
165
+ {
166
+ $scriptPath = Join-Path $moduleInfo.ModuleBase $moduleInfo.RootModule
167
+ }
168
+ else
169
+ {
170
+ $scriptPath = $moduleInfo.Path ;
171
+ }
172
+
173
+ $Resources = FindAndParseResourceDefinitions $scriptPath
174
+
175
+ if ($moduleInfo.NestedModules )
176
+ {
177
+ foreach ($nestedModule in $moduleInfo.NestedModules )
178
+ {
179
+ $resourcesOfNestedModules = LoadPowerShellClassResourcesFromModule $nestedModule
180
+ $Resources.AddRange ($resourcesOfNestedModules )
181
+ }
182
+ }
183
+
184
+ return $Resources
185
+ }
186
+
23
187
<# public function Invoke-DscCacheRefresh
24
188
. SYNOPSIS
25
189
This function caches the results of the Get-DscResource call to optimize performance.
@@ -46,12 +210,8 @@ function Invoke-DscCacheRefresh {
46
210
# PS 6+ on Windows
47
211
Join-Path $env: LocalAppData " dsc\PSAdapterCache.json"
48
212
} else {
49
- # either WinPS or PS 6+ on Linux/Mac
50
- if ($PSVersionTable.PSVersion.Major -le 5 ) {
51
- Join-Path $env: LocalAppData " dsc\WindowsPSAdapterCache.json"
52
- } else {
53
- Join-Path $env: HOME " .dsc" " PSAdapterCache.json"
54
- }
213
+ # PS 6+ on Linux/Mac
214
+ Join-Path $env: HOME " .dsc" " PSAdapterCache.json"
55
215
}
56
216
57
217
if (Test-Path $cacheFilePath ) {
@@ -113,33 +273,18 @@ function Invoke-DscCacheRefresh {
113
273
# create a list object to store cache of Get-DscResource
114
274
[dscResourceCacheEntry []]$dscResourceCacheEntries = [System.Collections.Generic.List [Object ]]::new()
115
275
116
- Import-PSDSCModule
117
- $DscResources = Get-DscResource
118
-
119
- foreach ($dscResource in $DscResources ) {
120
- # resources that shipped in Windows should only be used with Windows PowerShell
121
- if ($dscResource.ParentPath -like " $env: windir \System32\*" -and $PSVersionTable.PSVersion.Major -gt 5 ) {
122
- continue
123
- }
124
-
125
- if ( $dscResource.ImplementationDetail ) {
126
- # only support known dscResourceType
127
- if ([dscResourceType ].GetEnumNames() -notcontains $dscResource.ImplementationDetail ) {
128
- ' WARNING: implementation detail not found: ' + $dscResource.ImplementationDetail | Write-DscTrace
129
- continue
130
- }
131
- }
132
-
133
- $DscResourceInfo = [DscResourceInfo ]::new()
134
- $dscResource.PSObject.Properties | ForEach-Object - Process {
135
- if ($null -ne $_.Value ) {
136
- $DscResourceInfo .$ ($_.Name ) = $_.Value
137
- }
138
- else {
139
- $DscResourceInfo .$ ($_.Name ) = ' '
140
- }
276
+ $DscResources = [System.Collections.Generic.List [DscResourceInfo ]]::new()
277
+ $dscResourceModulePsd1s = Get-DSCResourceModules
278
+ if ($null -ne $dscResourceModulePsd1s ) {
279
+ $modules = Get-Module - ListAvailable - Name ($dscResourceModulePsd1s )
280
+ foreach ($mod in $modules )
281
+ {
282
+ [System.Collections.Generic.List [DscResourceInfo ]]$r = LoadPowerShellClassResourcesFromModule - moduleInfo $mod
283
+ $DscResources.AddRange ($r )
141
284
}
285
+ }
142
286
287
+ foreach ($dscResource in $DscResources ) {
143
288
$moduleName = $dscResource.ModuleName
144
289
145
290
# fill in resource files (and their last-write-times) that will be used for up-do-date checks
@@ -150,7 +295,7 @@ function Invoke-DscCacheRefresh {
150
295
151
296
$dscResourceCacheEntries += [dscResourceCacheEntry ]@ {
152
297
Type = " $moduleName /$ ( $dscResource.Name ) "
153
- DscResourceInfo = $DscResourceInfo
298
+ DscResourceInfo = $dscResource
154
299
LastWriteTimes = $lastWriteTimes
155
300
}
156
301
}
@@ -342,6 +487,14 @@ enum dscResourceType {
342
487
Composite
343
488
}
344
489
490
+ class DscResourcePropertyInfo
491
+ {
492
+ [string ] $Name
493
+ [string ] $PropertyType
494
+ [bool ] $IsMandatory
495
+ [System.Collections.Generic.List [string ]] $Values
496
+ }
497
+
345
498
# dsc resource type (settable clone)
346
499
class DscResourceInfo {
347
500
[dscResourceType ] $ImplementationDetail
@@ -355,5 +508,5 @@ class DscResourceInfo {
355
508
[string ] $ParentPath
356
509
[string ] $ImplementedAs
357
510
[string ] $CompanyName
358
- [psobject [ ]] $Properties
511
+ [System.Collections.Generic.List [ DscResourcePropertyInfo ]] $Properties
359
512
}
0 commit comments