From 61f4b85b2637403aa7ec3717e8556066fb467e68 Mon Sep 17 00:00:00 2001 From: Michal Machniak Date: Mon, 8 Dec 2025 22:45:12 +0100 Subject: [PATCH 1/2] Add to win_psDscAdapter function for extraxting string from PSCredentaials --- .../psDscAdapter/win_psDscAdapter.psm1 | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 b/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 index c206d89d9..6833a45eb 100644 --- a/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 +++ b/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 @@ -298,6 +298,36 @@ function Get-DscResourceObject { return $desiredState } +## Primitive value for PScredentials + +function Get-PrimitiveValueString { + param([Parameter(Mandatory)][object]$Value) + + # If already a string → done + if ($Value -is [string]) { + return $Value + } + + # If it's a hashtable or PSCustomObject → unwrap + if ($Value -is [hashtable] -or $Value -is [pscustomobject]) { + $props = $Value.psobject.Properties + + # Case 1: { secureString = "admin" } + if ($props.Name -contains 'secureString') { + return $Value.secureString + } + + # Case 2: nested object e.g. @{ value = @{ secureString = "admin" }} + if ($props.Count -eq 1) { + return Get-PrimitiveValueString $props.Value + } + + "Cannot extract primitive value from nested object: $($Value | Out-String)" | Write-DscTrace -Operation Error + } + + "Unsupported type '$($Value.GetType().FullName)' for primitive extraction" | Write-DscTrace -Operation Error +} + # Get the actual state using DSC Get method from any type of DSC resource function Invoke-DscOperation { param( From cd5df41c2f00573839a84fd2c8b0ca228fde0f40 Mon Sep 17 00:00:00 2001 From: Michal Machniak Date: Mon, 8 Dec 2025 23:10:49 +0100 Subject: [PATCH 2/2] Add to win_psDscAdapter for ScriptBase resources PSCredentails fix convert to System.Management.Automation.PSCredentia --- .../win_powershell_script_resources.dsc.yaml | 48 +++++++++++++++++++ .../psDscAdapter/win_psDscAdapter.psm1 | 6 ++- 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 adapters/powershell/Tests/win_powershell_script_resources.dsc.yaml diff --git a/adapters/powershell/Tests/win_powershell_script_resources.dsc.yaml b/adapters/powershell/Tests/win_powershell_script_resources.dsc.yaml new file mode 100644 index 000000000..45ba1f068 --- /dev/null +++ b/adapters/powershell/Tests/win_powershell_script_resources.dsc.yaml @@ -0,0 +1,48 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +parameters: + SafemodeAdministratorPassword: + type: string + showSecrets: + type: bool + defaultValue: true + cred: + type: secureObject +metadata: + Microsoft.DSC: + requiredSecurityContext: elevated # this is the default and just used as an example indicating this config works for admins and non-admins +resources: +- name: Use class PowerShell resources + type: Microsoft.Windows/WindowsPowerShell + properties: + resources: + - name: Windows Features Install ADS + type: PSDesiredStateConfiguration/WindowsFeature + properties: + ensure: Present + name: AD-Domain-Services + - name: Windows Features Install ADS RSAT + type: PSDesiredStateConfiguration/WindowsFeature + properties: + ensure: Present + name: RSAT-AD-PowerShell + dependsOn: + - "[resourceId('PSDesiredStateConfiguration/WindowsFeature','Windows Features Install ADS')]" + - name: Active Directory Forest + type: ActiveDirectoryDsc/ADDomain + properties: + DomainName: contoso.com + Credential: + Username: "[parameters('cred').username]" + Password: "[parameters('cred').password]" + SafemodeAdministratorPassword: + Username: "[parameters('cred').username]" + Password: "[parameters('cred').password]" + ForestMode: WinThreshold +- name: secureObject + type: Microsoft.DSC.Debug/Echo + properties: + output: "[parameters('cred')]" + showSecrets: "[parameters('showSecrets')]" \ No newline at end of file diff --git a/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 b/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 index 6833a45eb..3bb36b7ee 100644 --- a/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 +++ b/adapters/powershell/psDscAdapter/win_psDscAdapter.psm1 @@ -398,7 +398,11 @@ function Invoke-DscOperation { "Credential object '$($_.Name)' requires both 'username' and 'password' properties" | Write-DscTrace -Operation Error exit 1 } - $property.$($_.Name) = [System.Management.Automation.PSCredential]::new($_.Value.Username, (ConvertTo-SecureString -AsPlainText $_.Value.Password -Force)) + + $username = Get-PrimitiveValueString $_.Value.Username + $password = $_.Value.Password | ConvertTo-SecureString -AsPlainText -Force + $property.$($_.Name) = [System.Management.Automation.PSCredential]::new($username, $password) + } else { $property.$($_.Name) = $_.Value.psobject.properties | ForEach-Object -Begin { $propertyHash = @{} } -Process { $propertyHash[$_.Name] = $_.Value } -End { $propertyHash } }