diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 index ab9d19ea..f561c68a 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 @@ -8,8 +8,14 @@ enum EnumPropEnumeration { Expected } +class BaseTestClass +{ + [DscProperty()] + [string] $BaseProperty +} + [DscResource()] -class TestClassResource +class TestClassResource : BaseTestClass { [DscProperty(Key)] [string] $Name diff --git a/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 b/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 index edf83910..d6219a7c 100644 --- a/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 @@ -81,4 +81,13 @@ Describe 'PowerShell adapter resource tests' { $res.actualState.result.count | Should -Be 5 $res.actualState.result| % {$_.Name | Should -Not -BeNullOrEmpty} } + + It 'Verify inheritance works in class-based resources' { + + $r = dsc resource list '*' -a Microsoft.DSC/PowerShell + $LASTEXITCODE | Should -Be 0 + $resources = $r | ConvertFrom-Json + $t = $resources | ? {$_.Type -eq 'TestClassResource/TestClassResource'} + $t.properties | Should -Contain "BaseProperty" + } } diff --git a/powershell-adapter/psDscAdapter/psDscAdapter.psm1 b/powershell-adapter/psDscAdapter/psDscAdapter.psm1 index 0cb5fafe..bd37be59 100644 --- a/powershell-adapter/psDscAdapter/psDscAdapter.psm1 +++ b/powershell-adapter/psDscAdapter/psDscAdapter.psm1 @@ -49,6 +49,57 @@ function Get-DSCResourceModules return $dscModulePsd1List } +function Add-AstMembers { + param( + $AllTypeDefinitions, + $TypeAst, + $Properties + ) + + foreach($TypeConstraint in $TypeAst.BaseTypes) { + $t = $AllTypeDefinitions | Where-Object {$_.Name -eq $TypeConstraint.TypeName.Name} + if ($t) { + Add-AstMembers $AllTypeDefinitions $t $Properties + } + } + + foreach ($member in $TypeAst.Members) + { + $property = $member -as [System.Management.Automation.Language.PropertyMemberAst] + if (($property -eq $null) -or ($property.IsStatic)) + { + continue; + } + $skipProperty = $true + $isKeyProperty = $false + foreach($attr in $property.Attributes) + { + if ($attr.TypeName.Name -eq 'DscProperty') + { + $skipProperty = $false + foreach($attrArg in $attr.NamedArguments) + { + if ($attrArg.ArgumentName -eq 'Key') + { + $isKeyProperty = $true + break + } + } + } + } + if ($skipProperty) + { + continue; + } + + [DscResourcePropertyInfo]$prop = [DscResourcePropertyInfo]::new() + $prop.Name = $property.Name + $prop.PropertyType = $property.PropertyType.TypeName.Name + $prop.IsMandatory = $isKeyProperty + $Properties.Add($prop) + } +} + function FindAndParseResourceDefinitions { [CmdletBinding(HelpUri = '')] @@ -68,7 +119,6 @@ function FindAndParseResourceDefinitions } "Loading resources from file '$filePath'" | Write-DscTrace -Operation Trace - #TODO: Handle class inheritance #TODO: Ensure embedded instances in properties are working correctly [System.Management.Automation.Language.Token[]] $tokens = $null [System.Management.Automation.Language.ParseError[]] $errors = $null @@ -78,76 +128,38 @@ function FindAndParseResourceDefinitions $e | Out-String | Write-DscTrace -Operation Error } - $resourceDefinitions = $ast.FindAll( + $typeDefinitions = $ast.FindAll( { $typeAst = $args[0] -as [System.Management.Automation.Language.TypeDefinitionAst] - if ($typeAst) - { - foreach($a in $typeAst.Attributes) - { - if ($a.TypeName.Name -eq 'DscResource') - { - return $true; - } - } - } - - return $false; + return $typeAst -ne $null; }, $false); $resourceList = [System.Collections.Generic.List[DscResourceInfo]]::new() - foreach($typeDefinitionAst in $resourceDefinitions) + foreach($typeDefinitionAst in $typeDefinitions) { - $DscResourceInfo = [DscResourceInfo]::new() - $DscResourceInfo.Name = $typeDefinitionAst.Name - $DscResourceInfo.ResourceType = $typeDefinitionAst.Name - $DscResourceInfo.FriendlyName = $typeDefinitionAst.Name - $DscResourceInfo.ImplementationDetail = 'ClassBased' - $DscResourceInfo.Module = $filePath - $DscResourceInfo.Path = $filePath - #TODO: ModuleName, Version and ParentPath should be taken from psd1 contents - $DscResourceInfo.ModuleName = [System.IO.Path]::GetFileNameWithoutExtension($filePath) - $DscResourceInfo.ParentPath = [System.IO.Path]::GetDirectoryName($filePath) - - $DscResourceInfo.Properties = [System.Collections.Generic.List[DscResourcePropertyInfo]]::new() - foreach ($member in $typeDefinitionAst.Members) + foreach($a in $typeDefinitionAst.Attributes) { - $property = $member -as [System.Management.Automation.Language.PropertyMemberAst] - if (($property -eq $null) -or ($property.IsStatic)) + if ($a.TypeName.Name -eq 'DscResource') { - continue; - } - $skipProperty = $true - $isKeyProperty = $false - foreach($attr in $property.Attributes) - { - if ($attr.TypeName.Name -eq 'DscProperty') - { - $skipProperty = $false - foreach($attrArg in $attr.NamedArguments) - { - if ($attrArg.ArgumentName -eq 'Key') - { - $isKeyProperty = $true - } - } - } - } - if ($skipProperty) - { - continue; + $DscResourceInfo = [DscResourceInfo]::new() + $DscResourceInfo.Name = $typeDefinitionAst.Name + $DscResourceInfo.ResourceType = $typeDefinitionAst.Name + $DscResourceInfo.FriendlyName = $typeDefinitionAst.Name + $DscResourceInfo.ImplementationDetail = 'ClassBased' + $DscResourceInfo.Module = $filePath + $DscResourceInfo.Path = $filePath + #TODO: ModuleName, Version and ParentPath should be taken from psd1 contents + $DscResourceInfo.ModuleName = [System.IO.Path]::GetFileNameWithoutExtension($filePath) + $DscResourceInfo.ParentPath = [System.IO.Path]::GetDirectoryName($filePath) + + $DscResourceInfo.Properties = [System.Collections.Generic.List[DscResourcePropertyInfo]]::new() + Add-AstMembers $typeDefinitions $typeDefinitionAst $DscResourceInfo.Properties + + $resourceList.Add($DscResourceInfo) } - - [DscResourcePropertyInfo]$prop = [DscResourcePropertyInfo]::new() - $prop.Name = $property.Name - $prop.PropertyType = $property.PropertyType.TypeName.Name - $prop.IsMandatory = $isKeyProperty - $DscResourceInfo.Properties.Add($prop) } - - $resourceList.Add($DscResourceInfo) } return $resourceList