From 8b6422be35ff34cd22676b4ebb065c86bc3a2777 Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL HE/HIM) (from Dev Box)" Date: Wed, 13 May 2026 15:45:55 -0700 Subject: [PATCH 1/5] Add explicit arg for enclosing resource path in quotes --- .../PowerShell_adapter.dsc.resource.json | 12 ++++++++---- dsc/tests/dsc_adapter.tests.ps1 | 8 ++++++++ lib/dsc-lib/src/dscresources/command_resource.rs | 16 ++++++++++++---- .../src/dscresources/resource_manifest.rs | 4 ++++ tools/dsctest/dsctest.dsc.manifests.json | 4 ++++ 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/adapters/powershell/PowerShell_adapter.dsc.resource.json b/adapters/powershell/PowerShell_adapter.dsc.resource.json index 954191224..dd36c2c8c 100644 --- a/adapters/powershell/PowerShell_adapter.dsc.resource.json +++ b/adapters/powershell/PowerShell_adapter.dsc.resource.json @@ -41,7 +41,8 @@ "resourceTypeArg": "-ResourceType" }, { - "resourcePathArg": "-ResourcePath" + "resourcePathArg": "-ResourcePath", + "includeQuotes": true } ], "input": "stdin" @@ -61,7 +62,8 @@ "resourceTypeArg": "-ResourceType" }, { - "resourcePathArg": "-ResourcePath" + "resourcePathArg": "-ResourcePath", + "includeQuotes": true } ], "input": "stdin", @@ -83,7 +85,8 @@ "resourceTypeArg": "-ResourceType" }, { - "resourcePathArg": "-ResourcePath" + "resourcePathArg": "-ResourcePath", + "includeQuotes": true } ], "input": "stdin", @@ -104,7 +107,8 @@ "resourceTypeArg": "-ResourceType" }, { - "resourcePathArg": "-ResourcePath" + "resourcePathArg": "-ResourcePath", + "includeQuotes": true } ], "input": "stdin", diff --git a/dsc/tests/dsc_adapter.tests.ps1 b/dsc/tests/dsc_adapter.tests.ps1 index 097e5a337..70b29b401 100644 --- a/dsc/tests/dsc_adapter.tests.ps1 +++ b/dsc/tests/dsc_adapter.tests.ps1 @@ -179,6 +179,14 @@ Describe 'Tests for adapter support' { $out.schema | Should -Not -BeNullOrEmpty } + It 'Specifying includeQuotes should include quotes for path' { + $out = dsc -l trace resource set -r Adapted/Two -i '{"two":"2"}' 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10 + $errorLog = Get-Content $TestDrive/error.log -Raw + $LASTEXITCODE | Should -Be 0 -Because $errorLog + $errorLog | Should -BeLike '*Invoking command ''dsctest'' with args Some(`["adapter", "--operation", "set", "--input", "{\"two\":\"2\"}", "--resource-type", "Adapted/Two", "--resource-path", "\"*\\adaptedTest.dsc.adaptedResource.json\""`])*' -Because $errorLog + $out.afterState.two | Should -BeExactly 'value2' -Because $errorLog + } + It 'Adapted resource with condition false should not be returned' { $out = dsc -l debug resource list 'Adapted/Four' 2>$TestDrive/error.log $errorLog = Get-Content $TestDrive/error.log -Raw diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index 306bb2ef8..7c9ade35b 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -963,10 +963,14 @@ pub fn process_get_args(args: Option<&Vec>, input: &str, command_res processed_args.push(resource_type_arg.clone()); processed_args.push(command_resource_info.type_name.to_string()); }, - GetArgKind::ResourcePath { resource_path_arg } => { + GetArgKind::ResourcePath { resource_path_arg , include_quotes} => { if let Some(path) = &command_resource_info.path { processed_args.push(resource_path_arg.clone()); - processed_args.push(path.to_string_lossy().to_string()); + if include_quotes.unwrap_or(false) { + processed_args.push(format!("\"{}\"", path.to_string_lossy())); + } else { + processed_args.push(path.to_string_lossy().to_string()); + } } }, } @@ -1028,10 +1032,14 @@ fn process_set_delete_args(args: Option<&Vec>, input: &str, co processed_args.push(json_input_arg.clone()); processed_args.push(input.to_string()); }, - SetDeleteArgKind::ResourcePath { resource_path_arg } => { + SetDeleteArgKind::ResourcePath { resource_path_arg , include_quotes} => { if let Some(path) = &command_resource_info.path { processed_args.push(resource_path_arg.clone()); - processed_args.push(path.to_string_lossy().to_string()); + if include_quotes.unwrap_or(false) { + processed_args.push(format!("\"{}\"", path.to_string_lossy())); + } else { + processed_args.push(path.to_string_lossy().to_string()); + } } }, SetDeleteArgKind::ResourceType { resource_type_arg } => { diff --git a/lib/dsc-lib/src/dscresources/resource_manifest.rs b/lib/dsc-lib/src/dscresources/resource_manifest.rs index 96cbdcef2..dbf63671f 100644 --- a/lib/dsc-lib/src/dscresources/resource_manifest.rs +++ b/lib/dsc-lib/src/dscresources/resource_manifest.rs @@ -116,6 +116,8 @@ pub enum GetArgKind { /// The argument that accepts the resource path. #[serde(rename = "resourcePathArg")] resource_path_arg: String, + #[serde(rename = "includeQuotes")] + include_quotes: Option, }, ResourceType { /// The argument that accepts the resource type name. @@ -142,6 +144,8 @@ pub enum SetDeleteArgKind { /// The argument that accepts the resource path. #[serde(rename = "resourcePathArg")] resource_path_arg: String, + #[serde(rename = "includeQuotes")] + include_quotes: Option, }, ResourceType { /// The argument that accepts the resource type name. diff --git a/tools/dsctest/dsctest.dsc.manifests.json b/tools/dsctest/dsctest.dsc.manifests.json index aebd5a990..681dbbf4d 100644 --- a/tools/dsctest/dsctest.dsc.manifests.json +++ b/tools/dsctest/dsctest.dsc.manifests.json @@ -966,6 +966,10 @@ }, { "resourceTypeArg": "--resource-type" + }, + { + "resourcePathArg": "--resource-path", + "includeQuotes": true } ] }, From d77e630054dd161042f43f7a936b9c69ada3b363 Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL HE/HIM) (from Dev Box)" Date: Wed, 13 May 2026 16:21:02 -0700 Subject: [PATCH 2/5] remove extra slash since it's not cross-platform compat --- dsc/tests/dsc_adapter.tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsc/tests/dsc_adapter.tests.ps1 b/dsc/tests/dsc_adapter.tests.ps1 index 70b29b401..2b0f09673 100644 --- a/dsc/tests/dsc_adapter.tests.ps1 +++ b/dsc/tests/dsc_adapter.tests.ps1 @@ -183,7 +183,7 @@ Describe 'Tests for adapter support' { $out = dsc -l trace resource set -r Adapted/Two -i '{"two":"2"}' 2>$TestDrive/error.log | ConvertFrom-Json -Depth 10 $errorLog = Get-Content $TestDrive/error.log -Raw $LASTEXITCODE | Should -Be 0 -Because $errorLog - $errorLog | Should -BeLike '*Invoking command ''dsctest'' with args Some(`["adapter", "--operation", "set", "--input", "{\"two\":\"2\"}", "--resource-type", "Adapted/Two", "--resource-path", "\"*\\adaptedTest.dsc.adaptedResource.json\""`])*' -Because $errorLog + $errorLog | Should -BeLike '*Invoking command ''dsctest'' with args Some(`["adapter", "--operation", "set", "--input", "{\"two\":\"2\"}", "--resource-type", "Adapted/Two", "--resource-path", "\"*adaptedTest.dsc.adaptedResource.json\""`])*' -Because $errorLog $out.afterState.two | Should -BeExactly 'value2' -Because $errorLog } From eb836def842bf090d8b29b163ba3e5bfaee54aa6 Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL HE/HIM) (from Dev Box)" Date: Wed, 13 May 2026 16:30:59 -0700 Subject: [PATCH 3/5] add powershell resource test --- adapters/powershell/Tests/PSAdapted.tests.ps1 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/adapters/powershell/Tests/PSAdapted.tests.ps1 b/adapters/powershell/Tests/PSAdapted.tests.ps1 index dd7eb953a..95abef00c 100644 --- a/adapters/powershell/Tests/PSAdapted.tests.ps1 +++ b/adapters/powershell/Tests/PSAdapted.tests.ps1 @@ -19,4 +19,19 @@ Describe 'Tests for PS adapted manifests' { $out.actualState.Name | Should -BeExactly 'hello' -Because ($out | ConvertTo-Json) $out.actualState.Value | Should -Be 42 } + + It 'Get operation works if adapted resource is in a path with spaces' { + $resourcePath = Join-Path -Path $TestDrive -ChildPath 'Path with spaces' + New-Item -Path $resourcePath -ItemType Directory | Out-Null + Copy-Item -Path (Join-Path -Path $PSScriptRoot -ChildPath 'PSAdaptedTestClassResource*') -Destination $resourcePath + $oldPath = $env:PATH + try { + $env:PATH = $resourcePath + [System.IO.Path]::PathSeparator + $env:PATH + $out = dsc resource get -r 'PSAdaptedTestClassResource/PSAdaptedTestClass' -i '{"name":"hello"}' | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.actualState.Name | Should -BeExactly 'hello' + } finally { + $env:PATH = $oldPath + } + } } From 39b554d70bcd24027741397c4ce97d714393204b Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL HE/HIM) (from Dev Box)" Date: Wed, 13 May 2026 16:34:25 -0700 Subject: [PATCH 4/5] fix copilot feedback --- lib/dsc-lib/src/dscresources/command_resource.rs | 4 ++-- lib/dsc-lib/src/dscresources/resource_manifest.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index 7c9ade35b..06aec3ef3 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -963,7 +963,7 @@ pub fn process_get_args(args: Option<&Vec>, input: &str, command_res processed_args.push(resource_type_arg.clone()); processed_args.push(command_resource_info.type_name.to_string()); }, - GetArgKind::ResourcePath { resource_path_arg , include_quotes} => { + GetArgKind::ResourcePath { resource_path_arg, include_quotes} => { if let Some(path) = &command_resource_info.path { processed_args.push(resource_path_arg.clone()); if include_quotes.unwrap_or(false) { @@ -1032,7 +1032,7 @@ fn process_set_delete_args(args: Option<&Vec>, input: &str, co processed_args.push(json_input_arg.clone()); processed_args.push(input.to_string()); }, - SetDeleteArgKind::ResourcePath { resource_path_arg , include_quotes} => { + SetDeleteArgKind::ResourcePath { resource_path_arg, include_quotes} => { if let Some(path) = &command_resource_info.path { processed_args.push(resource_path_arg.clone()); if include_quotes.unwrap_or(false) { diff --git a/lib/dsc-lib/src/dscresources/resource_manifest.rs b/lib/dsc-lib/src/dscresources/resource_manifest.rs index dbf63671f..910594de8 100644 --- a/lib/dsc-lib/src/dscresources/resource_manifest.rs +++ b/lib/dsc-lib/src/dscresources/resource_manifest.rs @@ -116,6 +116,7 @@ pub enum GetArgKind { /// The argument that accepts the resource path. #[serde(rename = "resourcePathArg")] resource_path_arg: String, + /// Indicates if the argument should be wrapped in quotes. Default is false. #[serde(rename = "includeQuotes")] include_quotes: Option, }, @@ -144,6 +145,7 @@ pub enum SetDeleteArgKind { /// The argument that accepts the resource path. #[serde(rename = "resourcePathArg")] resource_path_arg: String, + /// Indicates if the resource path should be passed with quotes. Default is false. #[serde(rename = "includeQuotes")] include_quotes: Option, }, From e4ff62b6de487e9bdcdc5417bcbf91ada7d7a382 Mon Sep 17 00:00:00 2001 From: "Steve Lee (POWERSHELL HE/HIM) (from Dev Box)" Date: Thu, 14 May 2026 09:50:12 -0700 Subject: [PATCH 5/5] address Mikey's comment to use serde default instead of option --- .../src/dscresources/command_resource.rs | 4 ++-- .../src/dscresources/resource_manifest.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index 06aec3ef3..c03525ab6 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -966,7 +966,7 @@ pub fn process_get_args(args: Option<&Vec>, input: &str, command_res GetArgKind::ResourcePath { resource_path_arg, include_quotes} => { if let Some(path) = &command_resource_info.path { processed_args.push(resource_path_arg.clone()); - if include_quotes.unwrap_or(false) { + if *include_quotes { processed_args.push(format!("\"{}\"", path.to_string_lossy())); } else { processed_args.push(path.to_string_lossy().to_string()); @@ -1035,7 +1035,7 @@ fn process_set_delete_args(args: Option<&Vec>, input: &str, co SetDeleteArgKind::ResourcePath { resource_path_arg, include_quotes} => { if let Some(path) = &command_resource_info.path { processed_args.push(resource_path_arg.clone()); - if include_quotes.unwrap_or(false) { + if *include_quotes { processed_args.push(format!("\"{}\"", path.to_string_lossy())); } else { processed_args.push(path.to_string_lossy().to_string()); diff --git a/lib/dsc-lib/src/dscresources/resource_manifest.rs b/lib/dsc-lib/src/dscresources/resource_manifest.rs index 910594de8..568e44f9b 100644 --- a/lib/dsc-lib/src/dscresources/resource_manifest.rs +++ b/lib/dsc-lib/src/dscresources/resource_manifest.rs @@ -112,17 +112,17 @@ pub enum GetArgKind { /// Indicates if argument is mandatory which will pass an empty string if no JSON input is provided. Default is false. mandatory: Option, }, + #[serde(rename_all = "camelCase")] ResourcePath { /// The argument that accepts the resource path. - #[serde(rename = "resourcePathArg")] resource_path_arg: String, /// Indicates if the argument should be wrapped in quotes. Default is false. - #[serde(rename = "includeQuotes")] - include_quotes: Option, + #[serde(default)] + include_quotes: bool, }, + #[serde(rename_all = "camelCase")] ResourceType { /// The argument that accepts the resource type name. - #[serde(rename = "resourceTypeArg")] resource_type_arg: String, }, } @@ -141,23 +141,23 @@ pub enum SetDeleteArgKind { /// Indicates if argument is mandatory which will pass an empty string if no JSON input is provided. Default is false. mandatory: Option, }, + #[serde(rename_all = "camelCase")] ResourcePath { /// The argument that accepts the resource path. - #[serde(rename = "resourcePathArg")] resource_path_arg: String, /// Indicates if the resource path should be passed with quotes. Default is false. - #[serde(rename = "includeQuotes")] - include_quotes: Option, + #[serde(default)] + include_quotes: bool, }, + #[serde(rename_all = "camelCase")] ResourceType { /// The argument that accepts the resource type name. - #[serde(rename = "resourceTypeArg")] resource_type_arg: String, }, /// The argument is passed when the resource is invoked in what-if mode. + #[serde(rename_all = "camelCase")] WhatIf { /// The argument to pass when in what-if mode. - #[serde(rename = "whatIfArg")] what_if_arg: String, } }