Skip to content

Implement export Windows PowerShell adapter #848

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jun 3, 2025
Merged
24 changes: 24 additions & 0 deletions powershell-adapter/Tests/win_powershellgroup.tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,22 @@ class PSClassResource {
[void] Set() {

}

static [PSClassResource[]] Export()
{
$resultList = [System.Collections.Generic.List[PSClassResource]]::new()
$resultCount = 5
if ($env:PSClassResourceResultCount) {
$resultCount = $env:PSClassResourceResultCount
}
1..$resultCount | %{
$obj = New-Object PSClassResource
$obj.Name = "Object$_"
$resultList.Add($obj)
}

return $resultList.ToArray()
}
}
'@

Expand Down Expand Up @@ -350,4 +366,12 @@ class PSClassResource {
$LASTEXITCODE | Should -Be 0
$out.afterstate.InDesiredState | Should -Be $true
}

It 'Export works with class-based PS DSC resources' -Skip:(!$IsWindows) {

$out = dsc resource export -r PSClassResource/PSClassResource | ConvertFrom-Json
$LASTEXITCODE | Should -Be 0
$out | Should -Not -BeNullOrEmpty
$out.resources.count | Should -Be 5
}
}
45 changes: 42 additions & 3 deletions powershell-adapter/psDscAdapter/win_psDscAdapter.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -438,9 +438,21 @@ function Invoke-DscOperation {
$addToActualState.properties = [psobject]@{'InDesiredState' = $Result }
}
'Export' {
$t = $dscResourceInstance.GetType()
$method = $t.GetMethod('Export')
$resultArray = $method.Invoke($null, $null)
$method = ValidateMethod -operation $Operation -class $dscResourceInstance
$resultArray = @()
$raw_obj_array = $method.Invoke($null, $null)
foreach ($raw_obj in $raw_obj_array) {
$Result_obj = @{}
$ValidProperties | ForEach-Object {
if ($raw_obj.$_ -is [System.Enum]) {
$Result_obj[$_] = $raw_obj.$_.ToString()
}
else {
$Result_obj[$_] = $raw_obj.$_
}
}
$resultArray += $Result_obj
}
$addToActualState = $resultArray
}
}
Expand Down Expand Up @@ -532,6 +544,33 @@ function GetTypeInstanceFromModule {
return $instance
}

# ValidateMethod checks if the specified method exists in the class
function ValidateMethod {
param (
[Parameter(Mandatory = $true)]
[ValidateSet('Export', 'WhatIf')]
[string] $operation,
[Parameter(Mandatory = $true)]
[object] $class
)

$t = $class.GetType()
$methods = $t.GetMethods() | Where-Object -Property Name -EQ $operation
$method = foreach ($mt in $methods) {
if ($mt.GetParameters().Count -eq 0) {
$mt
break
}
}

if ($null -eq $method) {
"Method '$operation' not implemented by resource '$($t.Name)'" | Write-DscTrace -Operation Error
exit 1
}

return $method
}

# cached resource
class dscResourceCacheEntry {
[string] $Type
Expand Down
158 changes: 86 additions & 72 deletions powershell-adapter/windowspowershell.dsc.resource.json
Original file line number Diff line number Diff line change
@@ -1,41 +1,14 @@
{
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"type": "Microsoft.Windows/WindowsPowerShell",
"version": "0.1.0",
"kind": "adapter",
"description": "Resource adapter to classic DSC Powershell resources in Windows PowerShell.",
"tags": [
"PowerShell"
],
"adapter": {
"list": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"./psDscAdapter/powershell.resource.ps1 List"
]
},
"config": "full"
},
"get": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Get"
],
"input": "stdin"
},
"set": {
"$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json",
"type": "Microsoft.Windows/WindowsPowerShell",
"version": "0.1.0",
"kind": "adapter",
"description": "Resource adapter to classic DSC Powershell resources in Windows PowerShell.",
"tags": [
"PowerShell"
],
"adapter": {
"list": {
"executable": "powershell",
"args": [
"-NoLogo",
Expand All @@ -44,39 +17,80 @@
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Set"
],
"input": "stdin",
"preTest": true
},
"test": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Test"
],
"input": "stdin",
"return": "state"
},
"validate": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Validate"
]
},
"exitCodes": {
"0": "Success",
"1": "Error"
}
"./psDscAdapter/powershell.resource.ps1 List"
]
},
"config": "full"
},
"get": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Get"
],
"input": "stdin"
},
"set": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Set"
],
"input": "stdin",
"preTest": true
},
"test": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Test"
],
"input": "stdin",
"return": "state"
},
"export": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Export"
],
"input": "stdin",
"return": "state"
},
"validate": {
"executable": "powershell",
"args": [
"-NoLogo",
"-NonInteractive",
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"$Input | ./psDscAdapter/powershell.resource.ps1 Validate"
]
},
"exitCodes": {
"0": "Success",
"1": "Error"
}
}
Loading