From 51690f5728a0158411180817e619c57cbd7d01a1 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 10:19:31 +0200 Subject: [PATCH 01/12] Add whatif capability --- .../0.0.1/TestClassResource.psd1 | 1 + .../0.0.1/TestClassResource.psm1 | 31 +- .../Tests/powershellgroup.config.tests.ps1 | 560 +++++++++--------- .../powershell.dsc.resource.json | 188 +++--- .../psDscAdapter/powershell.resource.ps1 | 4 +- .../psDscAdapter/psDscAdapter.psm1 | 70 ++- 6 files changed, 478 insertions(+), 376 deletions(-) diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 index c852f0a10..5262fa648 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 @@ -42,6 +42,7 @@ PrivateData = @{ DscCapabilities = @( 'get' 'test' + 'whatif' ) } } diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 index a0e988ffa..587b08e29 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 @@ -119,6 +119,17 @@ class TestClassResource : BaseTestClass return $resultList.ToArray() } + + [string] WhatIf() { + $out = @{ + Name = $this.Name + _metadata = @{ + whatIIf = "A test message from the WhatIf method of TestClassResource" + } + } + + return ($out | ConvertTo-Json -Depth 10 -Compress) + } } [DscResource()] @@ -146,7 +157,25 @@ class NoExport: BaseTestClass { return $this } -} + + static [NoExport[]] Export() + { + $resultList = [List[NoExport]]::new() + $resultCount = 5 + if ($env:TestClassResourceResultCount) { + $resultCount = $env:TestClassResourceResultCount + } + 1..$resultCount | %{ + $obj = New-Object NoExport + $obj.Name = "Object$_" + $obj.Prop1 = "Property of object$_" + $resultList.Add($obj) + } + + return $resultList.ToArray() + } + } + function Test-World() { diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index 568789549..3a2132f2d 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -23,259 +23,295 @@ Describe 'PowerShell adapter resource tests' { Remove-Item -Force -ea SilentlyContinue -Path $cacheFilePath } - It 'Get works on config with class-based resources' { +# It 'Get works on config with class-based resources' { - $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - - $LASTEXITCODE | Should -Be 0 - $res = $r | ConvertFrom-Json - $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' - $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' - } +# $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $r | ConvertFrom-Json +# $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' +# $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' +# } - It 'Get does not work on config when module does not exist' { +# It 'Get does not work on config when module does not exist' { - $yaml = @' - $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResourceNotExist/TestClassResourceNotExist -'@ - $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" - $LASTEXITCODE | Should -Be 2 - "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." - } - - It 'Test works on config with class-based resources' { - - $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - - $LASTEXITCODE | Should -Be 0 - $res = $r | ConvertFrom-Json - $res.results[0].result.actualState.result[0] | Should -Not -BeNull - } - - It 'Set works on config with class-based resources' { - - $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - - $LASTEXITCODE | Should -Be 0 - $res = $r | ConvertFrom-Json - $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" - } - - It 'Export works on config with class-based resources' { - - $yaml = @' - $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource -'@ - $out = $yaml | dsc config export -f - - $LASTEXITCODE | Should -Be 0 - $res = $out | ConvertFrom-Json - $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - $res.'resources' | Should -Not -BeNullOrEmpty - $res.resources[0].properties.result.count | Should -Be 5 - $res.resources[0].properties.result[0].Name | Should -Be "Object1" - $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" - } - - It 'Export fails when class-based resource does not implement' { - $yaml = @' - $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/NoExport -'@ - $out = $yaml | dsc config export -f - 2>&1 | Out-String - $LASTEXITCODE | Should -Be 2 - $out | Should -Not -BeNullOrEmpty - $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" - } - - It 'Custom psmodulepath in config works' { - - $OldPSModulePath = $env:PSModulePath - Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive - Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" - - try { - $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - psmodulepath: $psmp - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource -"@ - $out = $yaml | dsc config export -f - - $LASTEXITCODE | Should -Be 0 - $res = $out | ConvertFrom-Json - $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - $res.'resources' | Should -Not -BeNullOrEmpty - $res.resources[0].properties.result.count | Should -Be 5 - $res.resources[0].properties.result[0].Name | Should -Be "Object1" - $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" - } - finally { - Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" - $env:PSModulePath = $OldPSModulePath - } - } - - It 'DSCConfigRoot macro is working when config is from a file' { - - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: "[envvar('DSC_CONFIG_ROOT')]" -"@ - - $config_path = "$TestDrive/test_config.dsc.yaml" - $yaml | Set-Content -Path $config_path - - $out = dsc config get --file $config_path - $LASTEXITCODE | Should -Be 0 - $res = $out | ConvertFrom-Json - $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive - $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive - } - - It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { - - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: "[envvar('DSC_CONFIG_ROOT')]" -"@ - $out = $yaml | dsc config get -f - | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path - } - - It 'DSC Configuration Document with key-value pair works' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource1' - HashTableProp: - Name: 'DSCv3' -"@ - - $out = $yaml | dsc config get -f - | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' - } - - It 'Config calling PS Resource directly works for ' -TestCases @( - @{ Operation = 'get' } - @{ Operation = 'set' } - @{ Operation = 'test' } - ) { - param($Operation) - - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource1' - HashTableProp: - Name: 'DSCv3' -"@ - - $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt - $text = $out | Out-String - $out = $out | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) - switch ($Operation) { - 'get' { - $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text - } - 'set' { - $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text - $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text - } - 'test' { - $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text - } - } - } - - It 'Config works with credential object' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource' - Credential: - UserName: 'User' - Password: 'Password' -"@ - $out = dsc config get -i $yaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results.result.actualstate.Credential.UserName | Should -Be 'User' - $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty - } +# $yaml = @' +# $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResourceNotExist/TestClassResourceNotExist +# '@ +# $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" +# $LASTEXITCODE | Should -Be 2 +# "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." +# } + +# It 'Test works on config with class-based resources' { + +# $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $r | ConvertFrom-Json +# $res.results[0].result.actualState.result[0] | Should -Not -BeNull +# } + +# It 'Set works on config with class-based resources' { + +# $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $r | ConvertFrom-Json +# $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" +# } + +# It 'Export works on config with class-based resources' { + +# $yaml = @' +# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# '@ +# $out = $yaml | dsc config export -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $out | ConvertFrom-Json +# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# $res.'resources' | Should -Not -BeNullOrEmpty +# $res.resources[0].properties.result.count | Should -Be 5 +# $res.resources[0].properties.result[0].Name | Should -Be "Object1" +# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" +# } + +# It 'Export fails when class-based resource does not implement' { +# $yaml = @' +# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/NoExport +# '@ +# $out = $yaml | dsc config export -f - 2>&1 | Out-String +# $LASTEXITCODE | Should -Be 2 +# $out | Should -Not -BeNullOrEmpty +# $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" +# } + +# It 'Custom psmodulepath in config works' { + +# $OldPSModulePath = $env:PSModulePath +# Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive +# Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" + +# try { +# $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# psmodulepath: $psmp +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# "@ +# $out = $yaml | dsc config export -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $out | ConvertFrom-Json +# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# $res.'resources' | Should -Not -BeNullOrEmpty +# $res.resources[0].properties.result.count | Should -Be 5 +# $res.resources[0].properties.result[0].Name | Should -Be "Object1" +# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" +# } +# finally { +# Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" +# $env:PSModulePath = $OldPSModulePath +# } +# } + +# It 'DSCConfigRoot macro is working when config is from a file' { + +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: "[envvar('DSC_CONFIG_ROOT')]" +# "@ + +# $config_path = "$TestDrive/test_config.dsc.yaml" +# $yaml | Set-Content -Path $config_path + +# $out = dsc config get --file $config_path +# $LASTEXITCODE | Should -Be 0 +# $res = $out | ConvertFrom-Json +# $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive +# $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive +# } + +# It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { + +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: "[envvar('DSC_CONFIG_ROOT')]" +# "@ +# $out = $yaml | dsc config get -f - | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path +# } + +# It 'DSC Configuration Document with key-value pair works' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource1' +# HashTableProp: +# Name: 'DSCv3' +# "@ + +# $out = $yaml | dsc config get -f - | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' +# } + +# It 'Config calling PS Resource directly works for ' -TestCases @( +# @{ Operation = 'get' } +# @{ Operation = 'set' } +# @{ Operation = 'test' } +# ) { +# param($Operation) + +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource1' +# HashTableProp: +# Name: 'DSCv3' +# "@ + +# $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt +# $text = $out | Out-String +# $out = $out | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) +# switch ($Operation) { +# 'get' { +# $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text +# } +# 'set' { +# $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text +# $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text +# } +# 'test' { +# $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text +# } +# } +# } + +# It 'Config works with credential object' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource' +# Credential: +# UserName: 'User' +# Password: 'Password' +# "@ +# $out = dsc config get -i $yaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results.result.actualstate.Credential.UserName | Should -Be 'User' +# $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty +# } + +# It 'Config does not work when credential properties are missing required fields' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource credential info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource' +# Credential: +# UserName: 'User' +# OtherProperty: 'Password' +# "@ +# $out = dsc config get -i $yaml 2>&1 | Out-String +# $LASTEXITCODE | Should -Be 2 +# $out | Should -Not -BeNullOrEmpty +# $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" +# } + +# It 'Config get is able to return proper enum value' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource' +# Ensure: 'Present' +# "@ + +# $out = dsc config get -i $yaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results.result.actualState.Ensure | Should -Be 'Present' +# } + +# It 'Config export is able to return proper enum value' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# "@ + +# $out = dsc config export -i $yaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.resources[0].properties.result.count | Should -Be 5 +# $out.resources[0].properties.result[0].Name | Should -Be "Object1" +# $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" +# } + + It 'Config whatIf works with class-based resources' { - It 'Config does not work when credential properties are missing required fields' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource credential info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource' - Credential: - UserName: 'User' - OtherProperty: 'Password' -"@ - $out = dsc config get -i $yaml 2>&1 | Out-String - $LASTEXITCODE | Should -Be 2 - $out | Should -Not -BeNullOrEmpty - $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" - } - - It 'Config get is able to return proper enum value' { $yaml = @" `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json resources: @@ -285,29 +321,11 @@ Describe 'PowerShell adapter resource tests' { Name: 'TestClassResource' Ensure: 'Present' "@ - - $out = dsc config get -i $yaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results.result.actualState.Ensure | Should -Be 'Present' - } - - It 'Config export is able to return proper enum value' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource -"@ - - $out = dsc config export -i $yaml | ConvertFrom-Json + dsc -l trace config set -i $yaml -w | ConvertFrom-Json $LASTEXITCODE | Should -Be 0 - $out.resources[0].properties.result.count | Should -Be 5 - $out.resources[0].properties.result[0].Name | Should -Be "Object1" - $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + $out.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" + $out.results.result.afterState.result[0].properties.Name | Should -Be "TestClassResource" + $out.results.result.afterState.result[0].properties.Ensure | Should -Be "Present" } } diff --git a/powershell-adapter/powershell.dsc.resource.json b/powershell-adapter/powershell.dsc.resource.json index e481b0737..15677e0ca 100644 --- a/powershell-adapter/powershell.dsc.resource.json +++ b/powershell-adapter/powershell.dsc.resource.json @@ -1,28 +1,14 @@ { - "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", - "type": "Microsoft.DSC/PowerShell", - "version": "0.1.0", - "kind": "adapter", - "description": "Resource adapter to classic DSC Powershell resources.", - "tags": [ - "PowerShell" - ], - "adapter": { - "list": { - "executable": "pwsh", - "args": [ - "-NoLogo", - "-NonInteractive", - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-Command", - "./psDscAdapter/powershell.resource.ps1 List" - ] - }, - "config": "full" - }, - "get": { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Microsoft.DSC/PowerShell", + "version": "0.1.0", + "kind": "adapter", + "description": "Resource adapter to classic DSC Powershell resources.", + "tags": [ + "PowerShell" + ], + "adapter": { + "list": { "executable": "pwsh", "args": [ "-NoLogo", @@ -31,67 +17,95 @@ "-ExecutionPolicy", "Bypass", "-Command", - "$Input | ./psDscAdapter/powershell.resource.ps1 Get" - ], - "input": "stdin" - }, - "set": { - "executable": "pwsh", - "args": [ - "-NoLogo", - "-NonInteractive", - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-Command", - "$Input | ./psDscAdapter/powershell.resource.ps1 Set" - ], - "input": "stdin", - "implementsPretest": true - }, - "test": { - "executable": "pwsh", - "args": [ - "-NoLogo", - "-NonInteractive", - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-Command", - "$Input | ./psDscAdapter/powershell.resource.ps1 Test" - ], - "input": "stdin", - "return": "state" - }, - "export": { - "executable": "pwsh", - "args": [ - "-NoLogo", - "-NonInteractive", - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-Command", - "$Input | ./psDscAdapter/powershell.resource.ps1 Export" - ], - "input": "stdin", - "return": "state" - }, - "validate": { - "executable": "pwsh", - "args": [ - "-NoLogo", - "-NonInteractive", - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-Command", - "$Input | ./psDscAdapter/powershell.resource.ps1 Validate" - ], - "input": "stdin" - }, - "exitCodes": { - "0": "Success", - "1": "Error" - } + "./psDscAdapter/powershell.resource.ps1 List" + ] + }, + "config": "full" + }, + "get": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$Input | ./psDscAdapter/powershell.resource.ps1 Get" + ], + "input": "stdin" + }, + "set": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$Input | ./psDscAdapter/powershell.resource.ps1 Set" + ], + "input": "stdin", + "implementsPretest": true + }, + "test": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$Input | ./psDscAdapter/powershell.resource.ps1 Test" + ], + "input": "stdin", + "return": "state" + }, + "export": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$Input | ./psDscAdapter/powershell.resource.ps1 Export" + ], + "input": "stdin", + "return": "state" + }, + "whatIf": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$Input | ./psDscAdapter/powershell.resource.ps1 WhatIf" + ], + "input": "stdin", + "return": "state" + }, + "validate": { + "executable": "pwsh", + "args": [ + "-NoLogo", + "-NonInteractive", + "-NoProfile", + "-ExecutionPolicy", + "Bypass", + "-Command", + "$Input | ./psDscAdapter/powershell.resource.ps1 Validate" + ], + "input": "stdin" + }, + "exitCodes": { + "0": "Success", + "1": "Error" } +} \ No newline at end of file diff --git a/powershell-adapter/psDscAdapter/powershell.resource.ps1 b/powershell-adapter/psDscAdapter/powershell.resource.ps1 index d5417775e..99a00e101 100644 --- a/powershell-adapter/psDscAdapter/powershell.resource.ps1 +++ b/powershell-adapter/psDscAdapter/powershell.resource.ps1 @@ -3,7 +3,7 @@ [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, HelpMessage = 'Operation to perform. Choose from List, Get, Set, Test, Export, Validate, ClearCache.')] - [ValidateSet('List', 'Get', 'Set', 'Test', 'Export', 'Validate', 'ClearCache')] + [ValidateSet('List', 'Get', 'Set', 'Test', 'Export', 'WhatIf', 'Validate', 'ClearCache')] [string]$Operation, [Parameter(Mandatory = $false, Position = 1, ValueFromPipeline = $true, HelpMessage = 'Configuration or resource input in JSON format.')] [string]$jsonInput = '@{}' @@ -135,7 +135,7 @@ switch ($Operation) { } | ConvertTo-Json -Compress } } - { @('Get','Set','Test','Export') -contains $_ } { + { @('Get','Set','Test','Export', 'WhatIf') -contains $_ } { $desiredState = $psDscAdapter.invoke( { param($jsonInput) Get-DscResourceObject -jsonInput $jsonInput }, $jsonInput ) if ($null -eq $desiredState) { Write-DscTrace -Operation Error -message 'Failed to create configuration object from provided input JSON.' diff --git a/powershell-adapter/psDscAdapter/psDscAdapter.psm1 b/powershell-adapter/psDscAdapter/psDscAdapter.psm1 index ffee99d94..33b0f7d36 100644 --- a/powershell-adapter/psDscAdapter/psDscAdapter.psm1 +++ b/powershell-adapter/psDscAdapter/psDscAdapter.psm1 @@ -377,7 +377,7 @@ function Get-DscResourceObject { function Invoke-DscOperation { param( [Parameter(Mandatory)] - [ValidateSet('Get', 'Set', 'Test', 'Export')] + [ValidateSet('Get', 'Set', 'Test', 'Export', 'WhatIf')] [string]$Operation, [Parameter(Mandatory, ValueFromPipeline = $true)] [dscResourceObject]$DesiredState, @@ -464,19 +464,7 @@ function Invoke-DscOperation { $addToActualState.properties = [psobject]@{'InDesiredState' = $Result } } 'Export' { - $t = $dscResourceInstance.GetType() - $methods = $t.GetMethods() | Where-Object { $_.Name -eq 'Export' } - $method = foreach ($mt in $methods) { - if ($mt.GetParameters().Count -eq 0) { - $mt - break - } - } - - if ($null -eq $method) { - "Export method not implemented by resource '$($DesiredState.Type)'" | Write-DscTrace -Operation Error - exit 1 - } + $method = ValidateMethod -operation $Operation -class $dscResourceInstance $resultArray = @() $raw_obj_array = $method.Invoke($null, $null) foreach ($raw_obj in $raw_obj_array) { @@ -493,10 +481,14 @@ function Invoke-DscOperation { } $addToActualState = $resultArray } + 'WhatIf' { + $method = ValidateMethod -operation $Operation -class $dscResourceInstance + $raw_obj = $dscResourceInstance.WhatIf() + $addToActualState.properties = $raw_obj + } } } catch { - 'Exception: ' + $_.Exception.Message | Write-DscTrace -Operation Error exit 1 } @@ -529,6 +521,54 @@ 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 +} + +function GetResultProperties { + param ( + [Parameter(Mandatory = $true)] + [psobject] $raw_obj, + [Parameter(Mandatory = $true)] + [string[]] $ValidProperties + ) + + $result = @{} + $ValidProperties | ForEach-Object { + if ($raw_obj.$_ -is [System.Enum]) { + $result[$_] = $raw_obj.$_.ToString() + } + else { + $result[$_] = $raw_obj.$_ + } + } + + return $result +} + # cached resource class dscResourceCacheEntry { [string] $Type From cfb2459d529733a3610e2c0601d3038cbf6b5f7a Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 12:47:21 +0200 Subject: [PATCH 02/12] Add execution_type --- dsc_lib/src/dscresources/dscresource.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/dsc_lib/src/dscresources/dscresource.rs b/dsc_lib/src/dscresources/dscresource.rs index c4119c697..b367e41d2 100644 --- a/dsc_lib/src/dscresources/dscresource.rs +++ b/dsc_lib/src/dscresources/dscresource.rs @@ -94,7 +94,7 @@ impl DscResource { } } - fn create_config_for_adapter(self, adapter: &str, input: &str) -> Result { + fn create_config_for_adapter(self, adapter: &str, input: &str, execution_type: &ExecutionKind) -> Result { // create new configuration with adapter and use this as the resource let mut configuration = Configuration::new(); let mut property_map = Map::new(); @@ -115,7 +115,8 @@ impl DscResource { }; configuration.resources.push(adapter_resource); let config_json = serde_json::to_string(&configuration)?; - let configurator = Configurator::new(&config_json, crate::progress::ProgressFormat::None)?; + let mut configurator = Configurator::new(&config_json, crate::progress::ProgressFormat::None)?; + configurator.context.execution_type = execution_type.clone(); Ok(configurator) } } @@ -218,7 +219,7 @@ impl Invoke for DscResource { fn get(&self, filter: &str) -> Result { debug!("{}", t!("dscresources.dscresource.invokeGet", resource = self.type_name)); if let Some(adapter) = &self.require_adapter { - let mut configurator = self.clone().create_config_for_adapter(adapter, filter)?; + let mut configurator = self.clone().create_config_for_adapter(adapter, filter, &ExecutionKind::Actual)?; let result = configurator.invoke_get()?; let GetResult::Resource(ref resource_result) = result.results[0].result else { return Err(DscError::Operation(t!("dscresources.dscresource.invokeReturnedWrongResult", operation = "get", resource = self.type_name).to_string())); @@ -252,7 +253,7 @@ impl Invoke for DscResource { fn set(&self, desired: &str, skip_test: bool, execution_type: &ExecutionKind) -> Result { debug!("{}", t!("dscresources.dscresource.invokeSet", resource = self.type_name)); if let Some(adapter) = &self.require_adapter { - let mut configurator = self.clone().create_config_for_adapter(adapter, desired)?; + let mut configurator = self.clone().create_config_for_adapter(adapter, desired, &execution_type)?; let result = configurator.invoke_set(false)?; let SetResult::Resource(ref resource_result) = result.results[0].result else { return Err(DscError::Operation(t!("dscresources.dscresource.invokeReturnedWrongResult", operation = "set", resource = self.type_name).to_string())); @@ -295,7 +296,7 @@ impl Invoke for DscResource { fn test(&self, expected: &str) -> Result { debug!("{}", t!("dscresources.dscresource.invokeTest", resource = self.type_name)); if let Some(adapter) = &self.require_adapter { - let mut configurator = self.clone().create_config_for_adapter(adapter, expected)?; + let mut configurator = self.clone().create_config_for_adapter(adapter, expected, &ExecutionKind::Actual)?; let result = configurator.invoke_test()?; let TestResult::Resource(ref resource_result) = result.results[0].result else { return Err(DscError::Operation(t!("dscresources.dscresource.invokeReturnedWrongResult", operation = "test", resource = self.type_name).to_string())); @@ -367,7 +368,7 @@ impl Invoke for DscResource { fn delete(&self, filter: &str) -> Result<(), DscError> { debug!("{}", t!("dscresources.dscresource.invokeDelete", resource = self.type_name)); if let Some(adapter) = &self.require_adapter { - let mut configurator = self.clone().create_config_for_adapter(adapter, filter)?; + let mut configurator = self.clone().create_config_for_adapter(adapter, filter, &ExecutionKind::Actual)?; configurator.invoke_set(false)?; return Ok(()); } @@ -429,7 +430,7 @@ impl Invoke for DscResource { fn export(&self, input: &str) -> Result { debug!("{}", t!("dscresources.dscresource.invokeExport", resource = self.type_name)); if let Some(adapter) = &self.require_adapter { - let mut configurator = self.clone().create_config_for_adapter(adapter, input)?; + let mut configurator = self.clone().create_config_for_adapter(adapter, input, &ExecutionKind::Actual)?; let result = configurator.invoke_export()?; let Some(configuration) = result.result else { return Err(DscError::Operation(t!("dscresources.dscresource.invokeExportReturnedNoResult", resource = self.type_name).to_string())); From 620f52a06b600c7ced0e68947cd7b4ab298fd1ea Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 12:48:37 +0200 Subject: [PATCH 03/12] Run workflow --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 620fdcde6..aca2363bb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,7 +2,7 @@ name: Rust on: push: - branches: [ "main" ] + branches: [ "*" ] pull_request: branches: [ "main" ] paths-ignore: From e63aec30b7ca2b3ab735afe7e57d532017feae41 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 12:57:37 +0200 Subject: [PATCH 04/12] Fix tests --- .vscode/launch.json | 78 +-- dsc_lib/src/dscresources/dscresource.rs | 2 +- .../0.0.1/TestClassResource.psm1 | 4 +- .../Tests/powershellgroup.config.tests.ps1 | 573 +++++++++--------- 4 files changed, 328 insertions(+), 329 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index c0fe66904..00879d03f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,39 +1,39 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug config", - "program": "${workspaceFolder}/config/target/debug/config", - "args": [ - "list", - "r*" - ], - "cwd": "${workspaceFolder}" - }, - { - "name": "(macOS) Attach", - "type": "lldb", - "request": "attach", - "pid": "${command:pickMyProcess}", - }, - { - "name": "(Windows) Attach", - "type": "cppvsdbg", - "request": "attach", - "processId": "${command:pickProcess}", - }, - { - "name": "Debug sshdconfig", - "type": "cppvsdbg", - "request": "launch", - "program": "${workspaceFolder}/sshdconfig/target/debug/sshdconfig.exe", - "args": ["get"], - "cwd": "${workspaceFolder}" - } - ] -} +// { +// // Use IntelliSense to learn about possible attributes. +// // Hover to view descriptions of existing attributes. +// // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +// "version": "0.2.0", +// "configurations": [ +// { +// "type": "lldb", +// "request": "launch", +// "name": "Debug config", +// "program": "${workspaceFolder}/config/target/debug/config", +// "args": [ +// "list", +// "r*" +// ], +// "cwd": "${workspaceFolder}" +// }, +// { +// "name": "(macOS) Attach", +// "type": "lldb", +// "request": "attach", +// "pid": "${command:pickMyProcess}", +// }, +// { +// "name": "(Windows) Attach", +// "type": "cppvsdbg", +// "request": "attach", +// "processId": "${command:pickProcess}", +// }, +// { +// "name": "Debug sshdconfig", +// "type": "cppvsdbg", +// "request": "launch", +// "program": "${workspaceFolder}/sshdconfig/target/debug/sshdconfig.exe", +// "args": ["get"], +// "cwd": "${workspaceFolder}" +// } +// ] +// } diff --git a/dsc_lib/src/dscresources/dscresource.rs b/dsc_lib/src/dscresources/dscresource.rs index b367e41d2..99229e0ae 100644 --- a/dsc_lib/src/dscresources/dscresource.rs +++ b/dsc_lib/src/dscresources/dscresource.rs @@ -253,7 +253,7 @@ impl Invoke for DscResource { fn set(&self, desired: &str, skip_test: bool, execution_type: &ExecutionKind) -> Result { debug!("{}", t!("dscresources.dscresource.invokeSet", resource = self.type_name)); if let Some(adapter) = &self.require_adapter { - let mut configurator = self.clone().create_config_for_adapter(adapter, desired, &execution_type)?; + let mut configurator = self.clone().create_config_for_adapter(adapter, desired, execution_type)?; let result = configurator.invoke_set(false)?; let SetResult::Resource(ref resource_result) = result.results[0].result else { return Err(DscError::Operation(t!("dscresources.dscresource.invokeReturnedWrongResult", operation = "set", resource = self.type_name).to_string())); diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 index 587b08e29..a02e67468 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 @@ -124,11 +124,11 @@ class TestClassResource : BaseTestClass $out = @{ Name = $this.Name _metadata = @{ - whatIIf = "A test message from the WhatIf method of TestClassResource" + whatIf = "A test message from the WhatIf method of TestClassResource" } } - return ($out | ConvertTo-Json -Depth 10 -Compress) + return $out } } diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index 3a2132f2d..d02bd03c7 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -23,292 +23,292 @@ Describe 'PowerShell adapter resource tests' { Remove-Item -Force -ea SilentlyContinue -Path $cacheFilePath } -# It 'Get works on config with class-based resources' { + It 'Get works on config with class-based resources' { -# $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $r | ConvertFrom-Json -# $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' -# $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' -# } + $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - + $LASTEXITCODE | Should -Be 0 + $res = $r | ConvertFrom-Json + $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' + $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' + } -# It 'Get does not work on config when module does not exist' { + It 'Get does not work on config when module does not exist' { -# $yaml = @' -# $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResourceNotExist/TestClassResourceNotExist -# '@ -# $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" -# $LASTEXITCODE | Should -Be 2 -# "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." -# } - -# It 'Test works on config with class-based resources' { - -# $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $r | ConvertFrom-Json -# $res.results[0].result.actualState.result[0] | Should -Not -BeNull -# } - -# It 'Set works on config with class-based resources' { - -# $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $r | ConvertFrom-Json -# $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" -# } - -# It 'Export works on config with class-based resources' { - -# $yaml = @' -# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# '@ -# $out = $yaml | dsc config export -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $out | ConvertFrom-Json -# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# $res.'resources' | Should -Not -BeNullOrEmpty -# $res.resources[0].properties.result.count | Should -Be 5 -# $res.resources[0].properties.result[0].Name | Should -Be "Object1" -# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" -# } - -# It 'Export fails when class-based resource does not implement' { -# $yaml = @' -# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/NoExport -# '@ -# $out = $yaml | dsc config export -f - 2>&1 | Out-String -# $LASTEXITCODE | Should -Be 2 -# $out | Should -Not -BeNullOrEmpty -# $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" -# } - -# It 'Custom psmodulepath in config works' { - -# $OldPSModulePath = $env:PSModulePath -# Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive -# Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" - -# try { -# $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# psmodulepath: $psmp -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# "@ -# $out = $yaml | dsc config export -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $out | ConvertFrom-Json -# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# $res.'resources' | Should -Not -BeNullOrEmpty -# $res.resources[0].properties.result.count | Should -Be 5 -# $res.resources[0].properties.result[0].Name | Should -Be "Object1" -# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" -# } -# finally { -# Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" -# $env:PSModulePath = $OldPSModulePath -# } -# } - -# It 'DSCConfigRoot macro is working when config is from a file' { - -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: "[envvar('DSC_CONFIG_ROOT')]" -# "@ - -# $config_path = "$TestDrive/test_config.dsc.yaml" -# $yaml | Set-Content -Path $config_path - -# $out = dsc config get --file $config_path -# $LASTEXITCODE | Should -Be 0 -# $res = $out | ConvertFrom-Json -# $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive -# $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive -# } - -# It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { - -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: "[envvar('DSC_CONFIG_ROOT')]" -# "@ -# $out = $yaml | dsc config get -f - | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path -# } - -# It 'DSC Configuration Document with key-value pair works' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource1' -# HashTableProp: -# Name: 'DSCv3' -# "@ - -# $out = $yaml | dsc config get -f - | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' -# } - -# It 'Config calling PS Resource directly works for ' -TestCases @( -# @{ Operation = 'get' } -# @{ Operation = 'set' } -# @{ Operation = 'test' } -# ) { -# param($Operation) - -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource1' -# HashTableProp: -# Name: 'DSCv3' -# "@ - -# $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt -# $text = $out | Out-String -# $out = $out | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) -# switch ($Operation) { -# 'get' { -# $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text -# } -# 'set' { -# $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text -# $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text -# } -# 'test' { -# $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text -# } -# } -# } - -# It 'Config works with credential object' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource' -# Credential: -# UserName: 'User' -# Password: 'Password' -# "@ -# $out = dsc config get -i $yaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results.result.actualstate.Credential.UserName | Should -Be 'User' -# $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty -# } - -# It 'Config does not work when credential properties are missing required fields' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource credential info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource' -# Credential: -# UserName: 'User' -# OtherProperty: 'Password' -# "@ -# $out = dsc config get -i $yaml 2>&1 | Out-String -# $LASTEXITCODE | Should -Be 2 -# $out | Should -Not -BeNullOrEmpty -# $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" -# } - -# It 'Config get is able to return proper enum value' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource' -# Ensure: 'Present' -# "@ - -# $out = dsc config get -i $yaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results.result.actualState.Ensure | Should -Be 'Present' -# } - -# It 'Config export is able to return proper enum value' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# "@ - -# $out = dsc config export -i $yaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.resources[0].properties.result.count | Should -Be 5 -# $out.resources[0].properties.result[0].Name | Should -Be "Object1" -# $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" -# } + $yaml = @' + $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResourceNotExist/TestClassResourceNotExist +'@ + $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" + $LASTEXITCODE | Should -Be 2 + "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." + } + + It 'Test works on config with class-based resources' { + + $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - + $LASTEXITCODE | Should -Be 0 + $res = $r | ConvertFrom-Json + $res.results[0].result.actualState.result[0] | Should -Not -BeNull + } + + It 'Set works on config with class-based resources' { + + $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - + $LASTEXITCODE | Should -Be 0 + $res = $r | ConvertFrom-Json + $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" + } + + It 'Export works on config with class-based resources' { + + $yaml = @' + $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource +'@ + $out = $yaml | dsc config export -f - + $LASTEXITCODE | Should -Be 0 + $res = $out | ConvertFrom-Json + $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + $res.'resources' | Should -Not -BeNullOrEmpty + $res.resources[0].properties.result.count | Should -Be 5 + $res.resources[0].properties.result[0].Name | Should -Be "Object1" + $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + } + + It 'Export fails when class-based resource does not implement' { + $yaml = @' + $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/NoExport +'@ + $out = $yaml | dsc config export -f - 2>&1 | Out-String + $LASTEXITCODE | Should -Be 2 + $out | Should -Not -BeNullOrEmpty + $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" + } + + It 'Custom psmodulepath in config works' { + + $OldPSModulePath = $env:PSModulePath + Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive + Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" + + try { + $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + psmodulepath: $psmp + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource +"@ + $out = $yaml | dsc config export -f - + $LASTEXITCODE | Should -Be 0 + $res = $out | ConvertFrom-Json + $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + $res.'resources' | Should -Not -BeNullOrEmpty + $res.resources[0].properties.result.count | Should -Be 5 + $res.resources[0].properties.result[0].Name | Should -Be "Object1" + $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + } + finally { + Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" + $env:PSModulePath = $OldPSModulePath + } + } + + It 'DSCConfigRoot macro is working when config is from a file' { + + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: "[envvar('DSC_CONFIG_ROOT')]" +"@ + + $config_path = "$TestDrive/test_config.dsc.yaml" + $yaml | Set-Content -Path $config_path + + $out = dsc config get --file $config_path + $LASTEXITCODE | Should -Be 0 + $res = $out | ConvertFrom-Json + $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive + $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive + } + + It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { + + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: "[envvar('DSC_CONFIG_ROOT')]" +"@ + $out = $yaml | dsc config get -f - | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path + } + + It 'DSC Configuration Document with key-value pair works' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource1' + HashTableProp: + Name: 'DSCv3' +"@ + + $out = $yaml | dsc config get -f - | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' + } + + It 'Config calling PS Resource directly works for ' -TestCases @( + @{ Operation = 'get' } + @{ Operation = 'set' } + @{ Operation = 'test' } + ) { + param($Operation) + + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource1' + HashTableProp: + Name: 'DSCv3' +"@ + + $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt + $text = $out | Out-String + $out = $out | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) + switch ($Operation) { + 'get' { + $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text + } + 'set' { + $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text + $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text + } + 'test' { + $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text + } + } + } + + It 'Config works with credential object' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource' + Credential: + UserName: 'User' + Password: 'Password' +"@ + $out = dsc config get -i $yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results.result.actualstate.Credential.UserName | Should -Be 'User' + $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty + } + + It 'Config does not work when credential properties are missing required fields' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource credential info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource' + Credential: + UserName: 'User' + OtherProperty: 'Password' +"@ + $out = dsc config get -i $yaml 2>&1 | Out-String + $LASTEXITCODE | Should -Be 2 + $out | Should -Not -BeNullOrEmpty + $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" + } + + It 'Config get is able to return proper enum value' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource' + Ensure: 'Present' +"@ + + $out = dsc config get -i $yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results.result.actualState.Ensure | Should -Be 'Present' + } + + It 'Config export is able to return proper enum value' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource +"@ + + $out = dsc config export -i $yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.resources[0].properties.result.count | Should -Be 5 + $out.resources[0].properties.result[0].Name | Should -Be "Object1" + $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + } It 'Config whatIf works with class-based resources' { @@ -321,11 +321,10 @@ Describe 'PowerShell adapter resource tests' { Name: 'TestClassResource' Ensure: 'Present' "@ - dsc -l trace config set -i $yaml -w | ConvertFrom-Json + $out = dsc -l trace config set -i $yaml -w | ConvertFrom-Json $LASTEXITCODE | Should -Be 0 - $out.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" - $out.results.result.afterState.result[0].properties.Name | Should -Be "TestClassResource" - $out.results.result.afterState.result[0].properties.Ensure | Should -Be "Present" + $out.results.result.afterstate.Result[0].name | Should -Be "TestClassResource" + $out.results.result.afterState.result[0]._metadata.whatIf | Should -Be "A test message from the WhatIf method of TestClassResource" } } From 29c22332a20f7c4b770ba8f15f0564500a44535a Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 13:09:32 +0200 Subject: [PATCH 05/12] Comment out tests --- .../Tests/powershellgroup.config.tests.ps1 | 566 +++++++++--------- 1 file changed, 283 insertions(+), 283 deletions(-) diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index d02bd03c7..e5041b6cb 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -23,292 +23,292 @@ Describe 'PowerShell adapter resource tests' { Remove-Item -Force -ea SilentlyContinue -Path $cacheFilePath } - It 'Get works on config with class-based resources' { +# It 'Get works on config with class-based resources' { - $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - - $LASTEXITCODE | Should -Be 0 - $res = $r | ConvertFrom-Json - $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' - $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' - } +# $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $r | ConvertFrom-Json +# $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' +# $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' +# } - It 'Get does not work on config when module does not exist' { +# It 'Get does not work on config when module does not exist' { - $yaml = @' - $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResourceNotExist/TestClassResourceNotExist -'@ - $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" - $LASTEXITCODE | Should -Be 2 - "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." - } - - It 'Test works on config with class-based resources' { - - $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - - $LASTEXITCODE | Should -Be 0 - $res = $r | ConvertFrom-Json - $res.results[0].result.actualState.result[0] | Should -Not -BeNull - } - - It 'Set works on config with class-based resources' { - - $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - - $LASTEXITCODE | Should -Be 0 - $res = $r | ConvertFrom-Json - $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" - } - - It 'Export works on config with class-based resources' { - - $yaml = @' - $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource -'@ - $out = $yaml | dsc config export -f - - $LASTEXITCODE | Should -Be 0 - $res = $out | ConvertFrom-Json - $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - $res.'resources' | Should -Not -BeNullOrEmpty - $res.resources[0].properties.result.count | Should -Be 5 - $res.resources[0].properties.result[0].Name | Should -Be "Object1" - $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" - } - - It 'Export fails when class-based resource does not implement' { - $yaml = @' - $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/NoExport -'@ - $out = $yaml | dsc config export -f - 2>&1 | Out-String - $LASTEXITCODE | Should -Be 2 - $out | Should -Not -BeNullOrEmpty - $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" - } - - It 'Custom psmodulepath in config works' { - - $OldPSModulePath = $env:PSModulePath - Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive - Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" - - try { - $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - psmodulepath: $psmp - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource -"@ - $out = $yaml | dsc config export -f - - $LASTEXITCODE | Should -Be 0 - $res = $out | ConvertFrom-Json - $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - $res.'resources' | Should -Not -BeNullOrEmpty - $res.resources[0].properties.result.count | Should -Be 5 - $res.resources[0].properties.result[0].Name | Should -Be "Object1" - $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" - } - finally { - Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" - $env:PSModulePath = $OldPSModulePath - } - } - - It 'DSCConfigRoot macro is working when config is from a file' { - - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: "[envvar('DSC_CONFIG_ROOT')]" -"@ - - $config_path = "$TestDrive/test_config.dsc.yaml" - $yaml | Set-Content -Path $config_path - - $out = dsc config get --file $config_path - $LASTEXITCODE | Should -Be 0 - $res = $out | ConvertFrom-Json - $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive - $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive - } - - It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { - - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: "[envvar('DSC_CONFIG_ROOT')]" -"@ - $out = $yaml | dsc config get -f - | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path - } - - It 'DSC Configuration Document with key-value pair works' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource1' - HashTableProp: - Name: 'DSCv3' -"@ - - $out = $yaml | dsc config get -f - | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' - } - - It 'Config calling PS Resource directly works for ' -TestCases @( - @{ Operation = 'get' } - @{ Operation = 'set' } - @{ Operation = 'test' } - ) { - param($Operation) - - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource1' - HashTableProp: - Name: 'DSCv3' -"@ - - $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt - $text = $out | Out-String - $out = $out | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) - switch ($Operation) { - 'get' { - $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text - } - 'set' { - $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text - $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text - } - 'test' { - $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text - } - } - } - - It 'Config works with credential object' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource' - Credential: - UserName: 'User' - Password: 'Password' -"@ - $out = dsc config get -i $yaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results.result.actualstate.Credential.UserName | Should -Be 'User' - $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty - } - - It 'Config does not work when credential properties are missing required fields' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource credential info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource' - Credential: - UserName: 'User' - OtherProperty: 'Password' -"@ - $out = dsc config get -i $yaml 2>&1 | Out-String - $LASTEXITCODE | Should -Be 2 - $out | Should -Not -BeNullOrEmpty - $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" - } - - It 'Config get is able to return proper enum value' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource - properties: - Name: 'TestClassResource' - Ensure: 'Present' -"@ - - $out = dsc config get -i $yaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results.result.actualState.Ensure | Should -Be 'Present' - } - - It 'Config export is able to return proper enum value' { - $yaml = @" - `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Working with class-based resources - type: Microsoft.DSC/PowerShell - properties: - resources: - - name: Class-resource Info - type: TestClassResource/TestClassResource -"@ - - $out = dsc config export -i $yaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.resources[0].properties.result.count | Should -Be 5 - $out.resources[0].properties.result[0].Name | Should -Be "Object1" - $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" - } +# $yaml = @' +# $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResourceNotExist/TestClassResourceNotExist +# '@ +# $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" +# $LASTEXITCODE | Should -Be 2 +# "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." +# } + +# It 'Test works on config with class-based resources' { + +# $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $r | ConvertFrom-Json +# $res.results[0].result.actualState.result[0] | Should -Not -BeNull +# } + +# It 'Set works on config with class-based resources' { + +# $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $r | ConvertFrom-Json +# $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" +# } + +# It 'Export works on config with class-based resources' { + +# $yaml = @' +# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# '@ +# $out = $yaml | dsc config export -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $out | ConvertFrom-Json +# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# $res.'resources' | Should -Not -BeNullOrEmpty +# $res.resources[0].properties.result.count | Should -Be 5 +# $res.resources[0].properties.result[0].Name | Should -Be "Object1" +# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" +# } + +# It 'Export fails when class-based resource does not implement' { +# $yaml = @' +# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/NoExport +# '@ +# $out = $yaml | dsc config export -f - 2>&1 | Out-String +# $LASTEXITCODE | Should -Be 2 +# $out | Should -Not -BeNullOrEmpty +# $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" +# } + +# It 'Custom psmodulepath in config works' { + +# $OldPSModulePath = $env:PSModulePath +# Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive +# Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" + +# try { +# $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# psmodulepath: $psmp +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# "@ +# $out = $yaml | dsc config export -f - +# $LASTEXITCODE | Should -Be 0 +# $res = $out | ConvertFrom-Json +# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# $res.'resources' | Should -Not -BeNullOrEmpty +# $res.resources[0].properties.result.count | Should -Be 5 +# $res.resources[0].properties.result[0].Name | Should -Be "Object1" +# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" +# } +# finally { +# Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" +# $env:PSModulePath = $OldPSModulePath +# } +# } + +# It 'DSCConfigRoot macro is working when config is from a file' { + +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: "[envvar('DSC_CONFIG_ROOT')]" +# "@ + +# $config_path = "$TestDrive/test_config.dsc.yaml" +# $yaml | Set-Content -Path $config_path + +# $out = dsc config get --file $config_path +# $LASTEXITCODE | Should -Be 0 +# $res = $out | ConvertFrom-Json +# $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive +# $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive +# } + +# It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { + +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: "[envvar('DSC_CONFIG_ROOT')]" +# "@ +# $out = $yaml | dsc config get -f - | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path +# } + +# It 'DSC Configuration Document with key-value pair works' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource1' +# HashTableProp: +# Name: 'DSCv3' +# "@ + +# $out = $yaml | dsc config get -f - | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' +# } + +# It 'Config calling PS Resource directly works for ' -TestCases @( +# @{ Operation = 'get' } +# @{ Operation = 'set' } +# @{ Operation = 'test' } +# ) { +# param($Operation) + +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource1' +# HashTableProp: +# Name: 'DSCv3' +# "@ + +# $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt +# $text = $out | Out-String +# $out = $out | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) +# switch ($Operation) { +# 'get' { +# $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text +# } +# 'set' { +# $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text +# $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text +# } +# 'test' { +# $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text +# } +# } +# } + +# It 'Config works with credential object' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource' +# Credential: +# UserName: 'User' +# Password: 'Password' +# "@ +# $out = dsc config get -i $yaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results.result.actualstate.Credential.UserName | Should -Be 'User' +# $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty +# } + +# It 'Config does not work when credential properties are missing required fields' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource credential info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource' +# Credential: +# UserName: 'User' +# OtherProperty: 'Password' +# "@ +# $out = dsc config get -i $yaml 2>&1 | Out-String +# $LASTEXITCODE | Should -Be 2 +# $out | Should -Not -BeNullOrEmpty +# $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" +# } + +# It 'Config get is able to return proper enum value' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# properties: +# Name: 'TestClassResource' +# Ensure: 'Present' +# "@ + +# $out = dsc config get -i $yaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results.result.actualState.Ensure | Should -Be 'Present' +# } + +# It 'Config export is able to return proper enum value' { +# $yaml = @" +# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Working with class-based resources +# type: Microsoft.DSC/PowerShell +# properties: +# resources: +# - name: Class-resource Info +# type: TestClassResource/TestClassResource +# "@ + +# $out = dsc config export -i $yaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.resources[0].properties.result.count | Should -Be 5 +# $out.resources[0].properties.result[0].Name | Should -Be "Object1" +# $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" +# } It 'Config whatIf works with class-based resources' { From b34ddecff94279f89ae43a945ae8874007db5d51 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 15:16:10 +0200 Subject: [PATCH 06/12] Expected input in capabilities --- .../0.0.1/TestClassResource.psd1 | 64 +- .../0.0.1/TestClassResource.psm1 | 79 +-- .../Tests/powershellgroup.config.tests.ps1 | 566 +++++++++--------- 3 files changed, 337 insertions(+), 372 deletions(-) diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 index 5262fa648..70ee8864f 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psd1 @@ -3,49 +3,49 @@ @{ -# Script module or binary module file associated with this manifest. -RootModule = 'TestClassResource.psm1' + # Script module or binary module file associated with this manifest. + RootModule = 'TestClassResource.psm1' -# Version number of this module. -ModuleVersion = '0.0.1' + # Version number of this module. + ModuleVersion = '0.0.1' -# ID used to uniquely identify this module -GUID = 'b267fa32-e77d-48e6-9248-676cc6f2327f' + # ID used to uniquely identify this module + GUID = 'b267fa32-e77d-48e6-9248-676cc6f2327f' -# Author of this module -Author = 'Microsoft' + # Author of this module + Author = 'Microsoft' -# Company or vendor of this module -CompanyName = 'Microsoft Corporation' + # Company or vendor of this module + CompanyName = 'Microsoft Corporation' -# Copyright statement for this module -Copyright = '(c) Microsoft. All rights reserved.' + # Copyright statement for this module + Copyright = '(c) Microsoft. All rights reserved.' -# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. -FunctionsToExport = @() + # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. + FunctionsToExport = @() -# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. -CmdletsToExport = '*' + # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. + CmdletsToExport = '*' -# Variables to export from this module -VariablesToExport = @() + # Variables to export from this module + VariablesToExport = @() -# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. -AliasesToExport = @() + # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. + AliasesToExport = @() -# DSC resources to export from this module -DscResourcesToExport = @('TestClassResource', 'NoExport') + # DSC resources to export from this module + DscResourcesToExport = @('TestClassResource', 'NoExport') -# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. -PrivateData = @{ - PSData = @{ - DscCapabilities = @( - 'get' - 'test' - 'whatif' - ) + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. + PrivateData = @{ + PSData = @{ + DscCapabilities = @( + 'get' + 'test' + 'whatIf' + 'export' + ) + } } } -} - diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 index a02e67468..443e0bd84 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 @@ -13,15 +13,13 @@ enum Ensure { Absent } -class BaseTestClass -{ +class BaseTestClass { [DscProperty()] [string] $BaseProperty } [DscResource()] -class TestClassResource : BaseTestClass -{ +class TestClassResource : BaseTestClass { [DscProperty(Key)] [string] $Name @@ -49,44 +47,36 @@ class TestClassResource : BaseTestClass [DscProperty()] [string] $HiddenDscProperty # This property should be in results data, but is an anti-pattern. - [void] Set() - { + [void] Set() { } - [bool] Test() - { - if (($this.Name -eq "TestClassResource1") -and ($this.Prop1 -eq "ValueForProp1")) - { + [bool] Test() { + if (($this.Name -eq "TestClassResource1") -and ($this.Prop1 -eq "ValueForProp1")) { return $true } - else - { + else { return $false } } - [TestClassResource] Get() - { - if ($this.Name -eq "TestClassResource1") - { + [TestClassResource] Get() { + if ($this.Name -eq "TestClassResource1") { $this.Prop1 = "ValueForProp1" } - else - { + else { $this.Prop1 = $env:DSC_CONFIG_ROOT } $this.EnumProp = ([EnumPropEnumeration]::Expected).ToString() return $this } - static [TestClassResource[]] Export() - { + static [TestClassResource[]] Export() { $resultList = [List[TestClassResource]]::new() $resultCount = 5 if ($env:TestClassResourceResultCount) { $resultCount = $env:TestClassResourceResultCount } - 1..$resultCount | %{ + 1..$resultCount | % { $obj = New-Object TestClassResource $obj.Name = "Object$_" $obj.Prop1 = "Property of object$_" @@ -96,20 +86,17 @@ class TestClassResource : BaseTestClass return $resultList.ToArray() } - static [TestClassResource[]] Export([bool]$UseExport) - { - if ($UseExport) - { + static [TestClassResource[]] Export([bool]$UseExport) { + if ($UseExport) { return [TestClassResource]::Export() } - else - { + else { $resultList = [List[TestClassResource]]::new() $resultCount = 5 if ($env:TestClassResourceResultCount) { $resultCount = $env:TestClassResourceResultCount } - 1..$resultCount | %{ + 1..$resultCount | % { $obj = New-Object TestClassResource $obj.Name = "Object$_" $obj.Prop1 = "Property of object$_" @@ -122,7 +109,7 @@ class TestClassResource : BaseTestClass [string] WhatIf() { $out = @{ - Name = $this.Name + Name = $this.Name _metadata = @{ whatIf = "A test message from the WhatIf method of TestClassResource" } @@ -133,8 +120,7 @@ class TestClassResource : BaseTestClass } [DscResource()] -class NoExport: BaseTestClass -{ +class NoExport: BaseTestClass { [DscProperty(Key)] [string] $Name @@ -144,40 +130,19 @@ class NoExport: BaseTestClass [DscProperty()] [string] $EnumProp - [void] Set() - { + [void] Set() { } - [bool] Test() - { + [bool] Test() { return $true } - [NoExport] Get() - { + [NoExport] Get() { return $this } - - static [NoExport[]] Export() - { - $resultList = [List[NoExport]]::new() - $resultCount = 5 - if ($env:TestClassResourceResultCount) { - $resultCount = $env:TestClassResourceResultCount - } - 1..$resultCount | %{ - $obj = New-Object NoExport - $obj.Name = "Object$_" - $obj.Prop1 = "Property of object$_" - $resultList.Add($obj) - } - - return $resultList.ToArray() - } - } +} -function Test-World() -{ +function Test-World() { "Hello world from PSTestModule!" } diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index e5041b6cb..d02bd03c7 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -23,292 +23,292 @@ Describe 'PowerShell adapter resource tests' { Remove-Item -Force -ea SilentlyContinue -Path $cacheFilePath } -# It 'Get works on config with class-based resources' { + It 'Get works on config with class-based resources' { -# $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $r | ConvertFrom-Json -# $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' -# $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' -# } + $r = Get-Content -Raw $pwshConfigPath | dsc config get -f - + $LASTEXITCODE | Should -Be 0 + $res = $r | ConvertFrom-Json + $res.results[0].result.actualState.result[0].properties.Prop1 | Should -BeExactly 'ValueForProp1' + $res.results[0].result.actualState.result[0].properties.EnumProp | Should -BeExactly 'Expected' + } -# It 'Get does not work on config when module does not exist' { + It 'Get does not work on config when module does not exist' { -# $yaml = @' -# $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResourceNotExist/TestClassResourceNotExist -# '@ -# $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" -# $LASTEXITCODE | Should -Be 2 -# "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." -# } - -# It 'Test works on config with class-based resources' { - -# $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $r | ConvertFrom-Json -# $res.results[0].result.actualState.result[0] | Should -Not -BeNull -# } - -# It 'Set works on config with class-based resources' { - -# $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $r | ConvertFrom-Json -# $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" -# } - -# It 'Export works on config with class-based resources' { - -# $yaml = @' -# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# '@ -# $out = $yaml | dsc config export -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $out | ConvertFrom-Json -# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# $res.'resources' | Should -Not -BeNullOrEmpty -# $res.resources[0].properties.result.count | Should -Be 5 -# $res.resources[0].properties.result[0].Name | Should -Be "Object1" -# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" -# } - -# It 'Export fails when class-based resource does not implement' { -# $yaml = @' -# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/NoExport -# '@ -# $out = $yaml | dsc config export -f - 2>&1 | Out-String -# $LASTEXITCODE | Should -Be 2 -# $out | Should -Not -BeNullOrEmpty -# $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" -# } - -# It 'Custom psmodulepath in config works' { - -# $OldPSModulePath = $env:PSModulePath -# Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive -# Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" - -# try { -# $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# psmodulepath: $psmp -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# "@ -# $out = $yaml | dsc config export -f - -# $LASTEXITCODE | Should -Be 0 -# $res = $out | ConvertFrom-Json -# $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# $res.'resources' | Should -Not -BeNullOrEmpty -# $res.resources[0].properties.result.count | Should -Be 5 -# $res.resources[0].properties.result[0].Name | Should -Be "Object1" -# $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" -# } -# finally { -# Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" -# $env:PSModulePath = $OldPSModulePath -# } -# } - -# It 'DSCConfigRoot macro is working when config is from a file' { - -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: "[envvar('DSC_CONFIG_ROOT')]" -# "@ - -# $config_path = "$TestDrive/test_config.dsc.yaml" -# $yaml | Set-Content -Path $config_path - -# $out = dsc config get --file $config_path -# $LASTEXITCODE | Should -Be 0 -# $res = $out | ConvertFrom-Json -# $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive -# $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive -# } - -# It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { - -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: "[envvar('DSC_CONFIG_ROOT')]" -# "@ -# $out = $yaml | dsc config get -f - | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path -# } - -# It 'DSC Configuration Document with key-value pair works' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource1' -# HashTableProp: -# Name: 'DSCv3' -# "@ - -# $out = $yaml | dsc config get -f - | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' -# } - -# It 'Config calling PS Resource directly works for ' -TestCases @( -# @{ Operation = 'get' } -# @{ Operation = 'set' } -# @{ Operation = 'test' } -# ) { -# param($Operation) - -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource1' -# HashTableProp: -# Name: 'DSCv3' -# "@ - -# $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt -# $text = $out | Out-String -# $out = $out | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) -# switch ($Operation) { -# 'get' { -# $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text -# } -# 'set' { -# $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text -# $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text -# } -# 'test' { -# $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text -# } -# } -# } - -# It 'Config works with credential object' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource' -# Credential: -# UserName: 'User' -# Password: 'Password' -# "@ -# $out = dsc config get -i $yaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results.result.actualstate.Credential.UserName | Should -Be 'User' -# $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty -# } - -# It 'Config does not work when credential properties are missing required fields' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource credential info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource' -# Credential: -# UserName: 'User' -# OtherProperty: 'Password' -# "@ -# $out = dsc config get -i $yaml 2>&1 | Out-String -# $LASTEXITCODE | Should -Be 2 -# $out | Should -Not -BeNullOrEmpty -# $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" -# } - -# It 'Config get is able to return proper enum value' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# properties: -# Name: 'TestClassResource' -# Ensure: 'Present' -# "@ - -# $out = dsc config get -i $yaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results.result.actualState.Ensure | Should -Be 'Present' -# } - -# It 'Config export is able to return proper enum value' { -# $yaml = @" -# `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Working with class-based resources -# type: Microsoft.DSC/PowerShell -# properties: -# resources: -# - name: Class-resource Info -# type: TestClassResource/TestClassResource -# "@ - -# $out = dsc config export -i $yaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.resources[0].properties.result.count | Should -Be 5 -# $out.resources[0].properties.result[0].Name | Should -Be "Object1" -# $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" -# } + $yaml = @' + $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResourceNotExist/TestClassResourceNotExist +'@ + $yaml | dsc -l trace config get -f - 2> "$TestDrive/tracing.txt" + $LASTEXITCODE | Should -Be 2 + "$TestDrive/tracing.txt" | Should -FileContentMatch "DSC resource 'TestClassResourceNotExist/TestClassResourceNotExist' module not found." + } + + It 'Test works on config with class-based resources' { + + $r = Get-Content -Raw $pwshConfigPath | dsc config test -f - + $LASTEXITCODE | Should -Be 0 + $res = $r | ConvertFrom-Json + $res.results[0].result.actualState.result[0] | Should -Not -BeNull + } + + It 'Set works on config with class-based resources' { + + $r = Get-Content -Raw $pwshConfigPath | dsc config set -f - + $LASTEXITCODE | Should -Be 0 + $res = $r | ConvertFrom-Json + $res.results.result.afterState.result[0].type | Should -Be "TestClassResource/TestClassResource" + } + + It 'Export works on config with class-based resources' { + + $yaml = @' + $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource +'@ + $out = $yaml | dsc config export -f - + $LASTEXITCODE | Should -Be 0 + $res = $out | ConvertFrom-Json + $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + $res.'resources' | Should -Not -BeNullOrEmpty + $res.resources[0].properties.result.count | Should -Be 5 + $res.resources[0].properties.result[0].Name | Should -Be "Object1" + $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + } + + It 'Export fails when class-based resource does not implement' { + $yaml = @' + $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/NoExport +'@ + $out = $yaml | dsc config export -f - 2>&1 | Out-String + $LASTEXITCODE | Should -Be 2 + $out | Should -Not -BeNullOrEmpty + $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" + } + + It 'Custom psmodulepath in config works' { + + $OldPSModulePath = $env:PSModulePath + Copy-Item -Recurse -Force -Path "$PSScriptRoot/TestClassResource" -Destination $TestDrive + Rename-Item -Path "$PSScriptRoot/TestClassResource" -NewName "_TestClassResource" + + try { + $psmp = "`$env:PSModulePath" + [System.IO.Path]::PathSeparator + $TestDrive + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + psmodulepath: $psmp + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource +"@ + $out = $yaml | dsc config export -f - + $LASTEXITCODE | Should -Be 0 + $res = $out | ConvertFrom-Json + $res.'$schema' | Should -BeExactly 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + $res.'resources' | Should -Not -BeNullOrEmpty + $res.resources[0].properties.result.count | Should -Be 5 + $res.resources[0].properties.result[0].Name | Should -Be "Object1" + $res.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + } + finally { + Rename-Item -Path "$PSScriptRoot/_TestClassResource" -NewName "TestClassResource" + $env:PSModulePath = $OldPSModulePath + } + } + + It 'DSCConfigRoot macro is working when config is from a file' { + + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: "[envvar('DSC_CONFIG_ROOT')]" +"@ + + $config_path = "$TestDrive/test_config.dsc.yaml" + $yaml | Set-Content -Path $config_path + + $out = dsc config get --file $config_path + $LASTEXITCODE | Should -Be 0 + $res = $out | ConvertFrom-Json + $res.results.result.actualState.result.properties.Name | Should -Be $TestDrive + $res.results.result.actualState.result.properties.Prop1 | Should -Be $TestDrive + } + + It 'DSC_CONFIG_ROOT env var is cwd when config is piped from stdin' { + + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: "[envvar('DSC_CONFIG_ROOT')]" +"@ + $out = $yaml | dsc config get -f - | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.actualState.result[0].properties.Name | Should -BeExactly (Get-Location).Path + } + + It 'DSC Configuration Document with key-value pair works' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource1' + HashTableProp: + Name: 'DSCv3' +"@ + + $out = $yaml | dsc config get -f - | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results.result.actualState.result.properties.HashTableProp.Name | Should -BeExactly 'DSCv3' + } + + It 'Config calling PS Resource directly works for ' -TestCases @( + @{ Operation = 'get' } + @{ Operation = 'set' } + @{ Operation = 'test' } + ) { + param($Operation) + + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource1' + HashTableProp: + Name: 'DSCv3' +"@ + + $out = dsc -l trace config $operation -i $yaml 2> $TestDrive/tracing.txt + $text = $out | Out-String + $out = $out | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 -Because (Get-Content -Raw -Path $TestDrive/tracing.txt) + switch ($Operation) { + 'get' { + $out.results[0].result.actualState.Name | Should -BeExactly 'TestClassResource1' -Because $text + } + 'set' { + $out.results[0].result.beforeState.Name | Should -BeExactly 'TestClassResource1' -Because $text + $out.results[0].result.afterState.Name | Should -BeExactly 'TestClassResource1' -Because $text + } + 'test' { + $out.results[0].result.actualState.InDesiredState | Should -BeFalse -Because $text + } + } + } + + It 'Config works with credential object' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource' + Credential: + UserName: 'User' + Password: 'Password' +"@ + $out = dsc config get -i $yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results.result.actualstate.Credential.UserName | Should -Be 'User' + $out.results.result.actualState.result.Credential.Password.Length | Should -Not -BeNullOrEmpty + } + + It 'Config does not work when credential properties are missing required fields' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource credential info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource' + Credential: + UserName: 'User' + OtherProperty: 'Password' +"@ + $out = dsc config get -i $yaml 2>&1 | Out-String + $LASTEXITCODE | Should -Be 2 + $out | Should -Not -BeNullOrEmpty + $out | Should -BeLike "*ERROR*Credential object 'Credential' requires both 'username' and 'password' properties*" + } + + It 'Config get is able to return proper enum value' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource + properties: + Name: 'TestClassResource' + Ensure: 'Present' +"@ + + $out = dsc config get -i $yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results.result.actualState.Ensure | Should -Be 'Present' + } + + It 'Config export is able to return proper enum value' { + $yaml = @" + `$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Working with class-based resources + type: Microsoft.DSC/PowerShell + properties: + resources: + - name: Class-resource Info + type: TestClassResource/TestClassResource +"@ + + $out = dsc config export -i $yaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.resources[0].properties.result.count | Should -Be 5 + $out.resources[0].properties.result[0].Name | Should -Be "Object1" + $out.resources[0].properties.result[0].Prop1 | Should -Be "Property of object1" + } It 'Config whatIf works with class-based resources' { From 793acd130271acf9f12eec1876c838a33afe6635 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 15:29:07 +0200 Subject: [PATCH 07/12] Output verbose --- build.ps1 | 2 +- powershell-adapter/Tests/powershellgroup.config.tests.ps1 | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build.ps1 b/build.ps1 index 9b88b1570..2672eca78 100755 --- a/build.ps1 +++ b/build.ps1 @@ -518,7 +518,7 @@ if ($Test) { (Get-Module -Name Pester -ListAvailable).Path } - Invoke-Pester -ErrorAction Stop + Invoke-Pester -ErrorAction Stop -Output Detailed -Verbose } function Find-MakeAppx() { diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index d02bd03c7..74f9b2594 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -321,10 +321,12 @@ Describe 'PowerShell adapter resource tests' { Name: 'TestClassResource' Ensure: 'Present' "@ - $out = dsc -l trace config set -i $yaml -w | ConvertFrom-Json + $out = dsc config set -i $yaml -w | ConvertFrom-Json + + Write-Verbose -Message ("Output: $($out | ConvertTo-Json -Depth 10)") -Verbose $LASTEXITCODE | Should -Be 0 - $out.results.result.afterstate.Result[0].name | Should -Be "TestClassResource" - $out.results.result.afterState.result[0]._metadata.whatIf | Should -Be "A test message from the WhatIf method of TestClassResource" + $out.results.result.afterstate.result[0].name | Should -Be "TestClassResource" + $out.results.result.afterstate.result[0]._metadata.whatIf | Should -Be "A test message from the WhatIf method of TestClassResource" } } From c71930d10b1bc21a54622f178301b8deb054c653 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 15:31:24 +0200 Subject: [PATCH 08/12] Fix export test --- powershell-adapter/Tests/powershellgroup.config.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index 74f9b2594..17355f914 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -101,7 +101,7 @@ Describe 'PowerShell adapter resource tests' { $out = $yaml | dsc config export -f - 2>&1 | Out-String $LASTEXITCODE | Should -Be 2 $out | Should -Not -BeNullOrEmpty - $out | Should -BeLike "*ERROR*Export method not implemented by resource 'TestClassResource/NoExport'*" + $out | Should -BeLike "*ERROR*'Export' method not implemented by resource 'NoExport'*" } It 'Custom psmodulepath in config works' { From e1d0e5c5d03db367592b2423f9e5df523ac18d42 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 15:58:31 +0200 Subject: [PATCH 09/12] Fix up resource test --- .vscode/launch.json | 78 +++++++++---------- build.ps1 | 2 +- .../0.0.1/TestClassResource.psm1 | 2 +- .../Tests/powershellgroup.config.tests.ps1 | 8 +- .../Tests/powershellgroup.resource.tests.ps1 | 8 +- 5 files changed, 48 insertions(+), 50 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 00879d03f..c0fe66904 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,39 +1,39 @@ -// { -// // Use IntelliSense to learn about possible attributes. -// // Hover to view descriptions of existing attributes. -// // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 -// "version": "0.2.0", -// "configurations": [ -// { -// "type": "lldb", -// "request": "launch", -// "name": "Debug config", -// "program": "${workspaceFolder}/config/target/debug/config", -// "args": [ -// "list", -// "r*" -// ], -// "cwd": "${workspaceFolder}" -// }, -// { -// "name": "(macOS) Attach", -// "type": "lldb", -// "request": "attach", -// "pid": "${command:pickMyProcess}", -// }, -// { -// "name": "(Windows) Attach", -// "type": "cppvsdbg", -// "request": "attach", -// "processId": "${command:pickProcess}", -// }, -// { -// "name": "Debug sshdconfig", -// "type": "cppvsdbg", -// "request": "launch", -// "program": "${workspaceFolder}/sshdconfig/target/debug/sshdconfig.exe", -// "args": ["get"], -// "cwd": "${workspaceFolder}" -// } -// ] -// } +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug config", + "program": "${workspaceFolder}/config/target/debug/config", + "args": [ + "list", + "r*" + ], + "cwd": "${workspaceFolder}" + }, + { + "name": "(macOS) Attach", + "type": "lldb", + "request": "attach", + "pid": "${command:pickMyProcess}", + }, + { + "name": "(Windows) Attach", + "type": "cppvsdbg", + "request": "attach", + "processId": "${command:pickProcess}", + }, + { + "name": "Debug sshdconfig", + "type": "cppvsdbg", + "request": "launch", + "program": "${workspaceFolder}/sshdconfig/target/debug/sshdconfig.exe", + "args": ["get"], + "cwd": "${workspaceFolder}" + } + ] +} diff --git a/build.ps1 b/build.ps1 index 2672eca78..9b88b1570 100755 --- a/build.ps1 +++ b/build.ps1 @@ -518,7 +518,7 @@ if ($Test) { (Get-Module -Name Pester -ListAvailable).Path } - Invoke-Pester -ErrorAction Stop -Output Detailed -Verbose + Invoke-Pester -ErrorAction Stop } function Find-MakeAppx() { diff --git a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 index 443e0bd84..abfd01b0f 100644 --- a/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 +++ b/powershell-adapter/Tests/TestClassResource/0.0.1/TestClassResource.psm1 @@ -107,7 +107,7 @@ class TestClassResource : BaseTestClass { return $resultList.ToArray() } - [string] WhatIf() { + [hashtable] WhatIf() { $out = @{ Name = $this.Name _metadata = @{ diff --git a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 index 17355f914..41398d46f 100644 --- a/powershell-adapter/Tests/powershellgroup.config.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.config.tests.ps1 @@ -101,7 +101,7 @@ Describe 'PowerShell adapter resource tests' { $out = $yaml | dsc config export -f - 2>&1 | Out-String $LASTEXITCODE | Should -Be 2 $out | Should -Not -BeNullOrEmpty - $out | Should -BeLike "*ERROR*'Export' method not implemented by resource 'NoExport'*" + $out | Should -BeLike "*ERROR*Method 'Export' not implemented by resource 'NoExport'*" } It 'Custom psmodulepath in config works' { @@ -322,11 +322,9 @@ Describe 'PowerShell adapter resource tests' { Ensure: 'Present' "@ $out = dsc config set -i $yaml -w | ConvertFrom-Json - - Write-Verbose -Message ("Output: $($out | ConvertTo-Json -Depth 10)") -Verbose $LASTEXITCODE | Should -Be 0 - $out.results.result.afterstate.result[0].name | Should -Be "TestClassResource" - $out.results.result.afterstate.result[0]._metadata.whatIf | Should -Be "A test message from the WhatIf method of TestClassResource" + $out.results.result.afterstate.name | Should -Be "TestClassResource" + $out.results.result.afterstate._metadata.whatIf | Should -Be "A test message from the WhatIf method of TestClassResource" } } diff --git a/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 b/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 index c8be165e3..93b644c34 100644 --- a/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 +++ b/powershell-adapter/Tests/powershellgroup.resource.tests.ps1 @@ -199,13 +199,13 @@ Describe 'PowerShell adapter resource tests' { $files | Copy-Item -Destination $path4 $filePath = Join-Path $path1 'TestClassResource.psd1' - (Get-Content -Raw $filePath).Replace("ModuleVersion = `'0.0.1`'", "ModuleVersion = `'1.0`'") | Set-Content $filePath + (Get-Content -Raw $filePath).Replace("ModuleVersion = '0.0.1'", "ModuleVersion = `'1.0`'") | Set-Content $filePath $filePath = Join-Path $path2 'TestClassResource.psd1' - (Get-Content -Raw $filePath).Replace("ModuleVersion = `'0.0.1`'", "ModuleVersion = `'1.1`'") | Set-Content $filePath + (Get-Content -Raw $filePath).Replace("ModuleVersion = '0.0.1'", "ModuleVersion = `'1.1`'") | Set-Content $filePath $filePath = Join-Path $path3 'TestClassResource.psd1' - (Get-Content -Raw $filePath).Replace("ModuleVersion = `'0.0.1`'", "ModuleVersion = `'2.0`'") | Set-Content $filePath + (Get-Content -Raw $filePath).Replace("ModuleVersion = '0.0.1'", "ModuleVersion = `'2.0`'") | Set-Content $filePath $filePath = Join-Path $path4 'TestClassResource.psd1' - (Get-Content -Raw $filePath).Replace("ModuleVersion = `'0.0.1`'", "ModuleVersion = `'2.0.1`'") | Set-Content $filePath + (Get-Content -Raw $filePath).Replace("ModuleVersion = '0.0.1'", "ModuleVersion = '2.0.1'") | Set-Content $filePath $oldPath = $env:PSModulePath From d833142d1ef583d85216dda208c68392e8c626fb Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 16:04:15 +0200 Subject: [PATCH 10/12] Output --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 9b88b1570..79aff5627 100755 --- a/build.ps1 +++ b/build.ps1 @@ -518,7 +518,7 @@ if ($Test) { (Get-Module -Name Pester -ListAvailable).Path } - Invoke-Pester -ErrorAction Stop + Invoke-Pester -ErrorAction Stop -Output Detailed } function Find-MakeAppx() { From ef80dae925cb0f654b5600e0e4a767405d2aba61 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 16:15:25 +0200 Subject: [PATCH 11/12] WhatIf on PowerShell adapter --- .github/workflows/rust.yml | 2 +- build.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index aca2363bb..620fdcde6 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,7 +2,7 @@ name: Rust on: push: - branches: [ "*" ] + branches: [ "main" ] pull_request: branches: [ "main" ] paths-ignore: diff --git a/build.ps1 b/build.ps1 index 79aff5627..9b88b1570 100755 --- a/build.ps1 +++ b/build.ps1 @@ -518,7 +518,7 @@ if ($Test) { (Get-Module -Name Pester -ListAvailable).Path } - Invoke-Pester -ErrorAction Stop -Output Detailed + Invoke-Pester -ErrorAction Stop } function Find-MakeAppx() { From 95492ce5934f3769c74f48ee6606fa1b01077946 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Wed, 28 May 2025 16:15:44 +0200 Subject: [PATCH 12/12] Remove unused function --- .../psDscAdapter/psDscAdapter.psm1 | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/powershell-adapter/psDscAdapter/psDscAdapter.psm1 b/powershell-adapter/psDscAdapter/psDscAdapter.psm1 index 33b0f7d36..f9dff1949 100644 --- a/powershell-adapter/psDscAdapter/psDscAdapter.psm1 +++ b/powershell-adapter/psDscAdapter/psDscAdapter.psm1 @@ -548,27 +548,6 @@ function ValidateMethod { return $method } -function GetResultProperties { - param ( - [Parameter(Mandatory = $true)] - [psobject] $raw_obj, - [Parameter(Mandatory = $true)] - [string[]] $ValidProperties - ) - - $result = @{} - $ValidProperties | ForEach-Object { - if ($raw_obj.$_ -is [System.Enum]) { - $result[$_] = $raw_obj.$_.ToString() - } - else { - $result[$_] = $raw_obj.$_ - } - } - - return $result -} - # cached resource class dscResourceCacheEntry { [string] $Type