diff --git a/powershell-adapter/Tests/win_powershellgroup.tests.ps1 b/powershell-adapter/Tests/win_powershellgroup.tests.ps1 index 88c4efcb6..077170815 100644 --- a/powershell-adapter/Tests/win_powershellgroup.tests.ps1 +++ b/powershell-adapter/Tests/win_powershellgroup.tests.ps1 @@ -373,6 +373,7 @@ class PSClassResource { $LASTEXITCODE | Should -Be 0 $out.type | Should -Contain 'PSClassResource/PSClassResource' $out | Where-Object -Property type -EQ PSClassResource/PSClassResource | Select-Object -ExpandProperty implementedAs | Should -Be 1 # Class-based + ($out | Where-Object -Property type -EQ 'PSClassResource/PSClassResource').capabilities | Should -BeIn @('get', 'test', 'set', 'export') } It 'Get works with class-based PS DSC resources' -Skip:(!$IsWindows) { diff --git a/powershell-adapter/psDscAdapter/win_psDscAdapter.psm1 b/powershell-adapter/psDscAdapter/win_psDscAdapter.psm1 index a10a940ad..162bf08f0 100644 --- a/powershell-adapter/psDscAdapter/win_psDscAdapter.psm1 +++ b/powershell-adapter/psDscAdapter/win_psDscAdapter.psm1 @@ -1,7 +1,7 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. -$script:CurrentCacheSchemaVersion = 1 +$script:CurrentCacheSchemaVersion = 2 function Write-DscTrace { param( @@ -230,6 +230,7 @@ function Invoke-DscCacheRefresh { if ($classBased -and ($classBased.CustomAttributes.AttributeType.Name -eq 'DscResourceAttribute')) { "Detected class-based resource: $($dscResource.Name) => Type: $($classBased.BaseType.FullName)" | Write-DscTrace $dscResourceInfo.ImplementationDetail = 'ClassBased' + $dscResourceInfo.Methods = GetClassBasedCapabilities -filePath $dscResource.Path } # fill in resource files (and their last-write-times) that will be used for up-do-date checks @@ -239,10 +240,10 @@ function Invoke-DscCacheRefresh { } $dscResourceCacheEntries.Add([dscResourceCacheEntry]@{ - Type = "$moduleName/$($dscResource.Name)" - DscResourceInfo = $DscResourceInfo - LastWriteTimes = $lastWriteTimes - }) + Type = "$moduleName/$($dscResource.Name)" + DscResourceInfo = $DscResourceInfo + LastWriteTimes = $lastWriteTimes + }) } if ($namedModules.Count -gt 0) { @@ -584,6 +585,61 @@ function ValidateMethod { return $method } +function GetClassBasedCapabilities { + param ( + [Parameter(Mandatory = $true)] + [string] $filePath + ) + + if (".psd1" -notcontains ([System.IO.Path]::GetExtension($filePath))) { + return @('get', 'set', 'test') + } + + $module = $filePath.Replace('.psd1', '.psm1') + + if (Test-Path $module -ErrorAction Ignore) { + [System.Management.Automation.Language.Token[]] $tokens = $null + [System.Management.Automation.Language.ParseError[]] $errors = $null + $ast = [System.Management.Automation.Language.Parser]::ParseFile($module, [ref]$tokens, [ref]$errors) + foreach ($e in $errors) { + $e | Out-String | Write-DscTrace -Operation Error + } + + $typeDefinitions = $ast.FindAll( + { + $typeAst = $args[0] -as [System.Management.Automation.Language.TypeDefinitionAst] + return $null -ne $typeAst; + }, + $false); + + + $capabilities = @() + $availableMethods = @('get', 'set', 'setHandlesExist', 'whatIf', 'test', 'delete', 'export') + foreach ($typeDefinitionAst in $typeDefinitions) { + foreach ($a in $typeDefinitionAst.Attributes) { + if ($a.TypeName.Name -eq 'DscResource') { + $methods = $typeDefinitionAst.Members | Where-Object { $_ -is [System.Management.Automation.Language.FunctionMemberAst] -and $_.Name -in $availableMethods } + + foreach ($method in $methods.Name) { + # We go through each method to properly case handle the method names. + switch ($method) { + 'Get' { $capabilities += 'get' } + 'Set' { $capabilities += 'set' } + 'Test' { $capabilities += 'test' } + 'WhatIf' { $capabilities += 'whatIf' } + 'SetHandlesExist' { $capabilities += 'setHandlesExist' } + 'Delete' { $capabilities += 'delete' } + 'Export' { $capabilities += 'export' } + } + } + } + } + } + + return $capabilities + } +} + # cached resource class dscResourceCacheEntry { [string] $Type @@ -626,4 +682,5 @@ class DscResourceInfo { [string] $ImplementedAs [string] $CompanyName [psobject[]] $Properties + [string[]] $Methods }