From 8f5a9d3b92579bad005e5d006e492f5bf8d4d850 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Fri, 24 Oct 2025 04:33:16 +0200 Subject: [PATCH 1/3] (MAINT) Improve permission handling in RegistryHelper --- lib/dsc-lib-registry/src/lib.rs | 16 +- .../tests/registry.config.set.tests.ps1 | 297 ++++++++++-------- 2 files changed, 187 insertions(+), 126 deletions(-) diff --git a/lib/dsc-lib-registry/src/lib.rs b/lib/dsc-lib-registry/src/lib.rs index 7b2326bb4..48e18affc 100644 --- a/lib/dsc-lib-registry/src/lib.rs +++ b/lib/dsc-lib-registry/src/lib.rs @@ -259,13 +259,22 @@ impl RegistryHelper { /// /// * `RegistryError` - The error that occurred. pub fn remove(&self) -> Result, RegistryError> { - let (reg_key, _subkey) = match self.open(Security::AllAccess) { + // For deleting a value, we need SetValue permission (KEY_SET_VALUE). + // Try to open with the minimal required permission. + // If that fails due to permission, try with AllAccess as a fallback. + let (reg_key, _subkey) = match self.open(Security::SetValue) { Ok(reg_key) => reg_key, // handle NotFound error Err(RegistryError::RegistryKeyNotFound(_)) => { eprintln!("{}", t!("registry_helper.removeErrorKeyNotExist")); return Ok(None); }, + Err(RegistryError::RegistryKey(key::Error::PermissionDenied(_, _))) => { + match self.open(Security::AllAccess) { + Ok(reg_key) => reg_key, + Err(e) => return self.handle_error_or_what_if(e), + } + }, Err(e) => return self.handle_error_or_what_if(e), }; @@ -289,10 +298,11 @@ impl RegistryHelper { Err(e) => return self.handle_error_or_what_if(RegistryError::RegistryValue(e)), } } else { - // to delete the key, we need to open the parent key first + // to delete the key, we need to open the parent key with CreateSubKey permission + // which includes the ability to delete subkeys let parent_path = get_parent_key_path(&self.config.key_path); let (hive, parent_subkey) = get_hive_from_path(parent_path)?; - let parent_reg_key = match hive.open(parent_subkey, Security::AllAccess) { + let parent_reg_key = match hive.open(parent_subkey, Security::CreateSubKey) { Ok(k) => k, Err(e) => return self.handle_error_or_what_if(RegistryError::RegistryKey(e)), }; diff --git a/resources/registry/tests/registry.config.set.tests.ps1 b/resources/registry/tests/registry.config.set.tests.ps1 index 7090be8a0..395a67e4c 100644 --- a/resources/registry/tests/registry.config.set.tests.ps1 +++ b/resources/registry/tests/registry.config.set.tests.ps1 @@ -8,141 +8,192 @@ Describe 'registry config set tests' { } } - It 'Can set a deeply nested key and value' -Skip:(!$IsWindows) { - $json = @' +# It 'Can set a deeply nested key and value' -Skip:(!$IsWindows) { +# $json = @' +# { +# "keyPath": "HKCU\\1\\2\\3", +# "valueName": "Hello", +# "valueData": { +# "String": "World" +# } +# } +# '@ +# $out = registry config set --input $json 2>$null +# $LASTEXITCODE | Should -Be 0 +# $out | Should -BeNullOrEmpty +# $result = registry config get --input $json 2>$null | ConvertFrom-Json +# $result.keyPath | Should -Be 'HKCU\1\2\3' +# $result.valueName | Should -Be 'Hello' +# $result.valueData.String | Should -Be 'World' +# ($result.psobject.properties | Measure-Object).Count | Should -Be 3 + +# $out = registry config get --input $json 2>$null +# $LASTEXITCODE | Should -Be 0 +# $result = $out | ConvertFrom-Json +# $result.keyPath | Should -Be 'HKCU\1\2\3' +# $result.valueName | Should -Be 'Hello' +# $result.valueData.String | Should -Be 'World' +# ($result.psobject.properties | Measure-Object).Count | Should -Be 3 +# } + +# It 'delete called when _exist is false' -Skip:(!$IsWindows) { +# $config = @{ +# '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# resources = @( +# @{ +# name = 'reg' +# type = 'Microsoft.Windows/Registry' +# properties = @{ +# keyPath = 'HKCU\1\2' +# valueName = 'Test' +# valueData = @{ +# String = 'Test' +# } +# _exist = $true +# } +# } +# ) +# } + +# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) +# $LASTEXITCODE | Should -Be 0 + +# $config.resources[0].properties._exist = $false +# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.afterState._exist | Should -Be $false + +# Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty + +# $config.resources[0].properties.valueName = $null +# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.afterState._exist | Should -Be $false + +# Get-Item -Path 'HKCU:\1\2' -ErrorAction Ignore | Should -BeNullOrEmpty +# } + +# It 'Can set value without data' -Skip:(!$IsWindows) { +# $configYaml = @' +# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json +# resources: +# - name: Key +# type: Microsoft.Windows/Registry +# properties: +# keyPath: 'HKCU\1' +# valueName: Test +# _exist: true +# '@ + +# $out = dsc config set -i $configYaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.afterState.keyPath | Should -BeExactly 'HKCU\1' +# $out.results[0].result.afterState.valueName | Should -BeExactly 'Test' +# $out.results[0].result.afterState.valueData | Should -BeNullOrEmpty + +# $out = dsc config get -i $configYaml | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.actualState.keyPath | Should -BeExactly 'HKCU\1' +# $out.results[0].result.actualState.valueName | Should -BeExactly 'Test' +# $out.results[0].result.actualState.valueData | Should -BeNullOrEmpty + +# Remove-Item -Path 'HKCU:\1' -Recurse -ErrorAction Ignore +# } + +# It 'Should succeed when _exist is false and value does not exist' -Skip:(!$IsWindows) { +# $config = @{ +# '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# resources = @( +# @{ +# name = 'reg' +# type = 'Microsoft.Windows/Registry' +# properties = @{ +# keyPath = 'HKCU' +# valueName = 'Test' +# valueData = @{ +# String = 'Test' +# } +# _exist = $false +# } +# } +# ) +# } + +# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.afterState._exist | Should -Be $false + +# Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty +# } + +# It 'Should succeed when _exist is false and key does not exist' -Skip:(!$IsWindows) { +# $config = @{ +# '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' +# resources = @( +# @{ +# name = 'reg' +# type = 'Microsoft.Windows/Registry' +# properties = @{ +# keyPath = 'HKCU\1' +# _exist = $false +# } +# } +# ) +# } + +# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json +# $LASTEXITCODE | Should -Be 0 +# $out.results[0].result.afterState._exist | Should -Be $false +# } + + It 'Can delete value from system-protected key with minimal permissions' -Skip:(!$IsWindows) { + $testKeyPath = 'HKLM:\Software\Policies\Microsoft\Windows\Appx' + if (-not (Test-Path $testKeyPath)) { + Set-ItResult -Skipped -Because "Test key path '$testKeyPath' does not exist" + return + } + + $currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) + $isElevated = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + + if (-not $isElevated) { + Set-ItResult -Skipped -Because "Test requires elevated privileges" + return + } + + $setJson = @' { - "keyPath": "HKCU\\1\\2\\3", - "valueName": "Hello", + "keyPath": "HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Appx", + "valueName": "DSCTestValue", "valueData": { - "String": "World" + "String": "TestData" } } '@ - $out = registry config set --input $json 2>$null + $out = registry config set --input $setJson 2>$null $LASTEXITCODE | Should -Be 0 - $out | Should -BeNullOrEmpty - $result = registry config get --input $json 2>$null | ConvertFrom-Json - $result.keyPath | Should -Be 'HKCU\1\2\3' - $result.valueName | Should -Be 'Hello' - $result.valueData.String | Should -Be 'World' - ($result.psobject.properties | Measure-Object).Count | Should -Be 3 - - $out = registry config get --input $json 2>$null - $LASTEXITCODE | Should -Be 0 - $result = $out | ConvertFrom-Json - $result.keyPath | Should -Be 'HKCU\1\2\3' - $result.valueName | Should -Be 'Hello' - $result.valueData.String | Should -Be 'World' - ($result.psobject.properties | Measure-Object).Count | Should -Be 3 - } - It 'delete called when _exist is false' -Skip:(!$IsWindows) { - $config = @{ - '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - resources = @( - @{ - name = 'reg' - type = 'Microsoft.Windows/Registry' - properties = @{ - keyPath = 'HKCU\1\2' - valueName = 'Test' - valueData = @{ - String = 'Test' - } - _exist = $true - } - } - ) + $getJson = @' + { + "keyPath": "HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Appx", + "valueName": "DSCTestValue" } - - $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) - $LASTEXITCODE | Should -Be 0 - - $config.resources[0].properties._exist = $false - $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.afterState._exist | Should -Be $false - - Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty - - $config.resources[0].properties.valueName = $null - $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.afterState._exist | Should -Be $false - - Get-Item -Path 'HKCU:\1\2' -ErrorAction Ignore | Should -BeNullOrEmpty - } - - It 'Can set value without data' -Skip:(!$IsWindows) { - $configYaml = @' - $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json - resources: - - name: Key - type: Microsoft.Windows/Registry - properties: - keyPath: 'HKCU\1' - valueName: Test - _exist: true '@ + $result = registry config get --input $getJson 2>$null | ConvertFrom-Json + $result.valueName | Should -Be 'DSCTestValue' + $result.valueData.String | Should -Be 'TestData' - $out = dsc config set -i $configYaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.afterState.keyPath | Should -BeExactly 'HKCU\1' - $out.results[0].result.afterState.valueName | Should -BeExactly 'Test' - $out.results[0].result.afterState.valueData | Should -BeNullOrEmpty - - $out = dsc config get -i $configYaml | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.actualState.keyPath | Should -BeExactly 'HKCU\1' - $out.results[0].result.actualState.valueName | Should -BeExactly 'Test' - $out.results[0].result.actualState.valueData | Should -BeNullOrEmpty - - Remove-Item -Path 'HKCU:\1' -Recurse -ErrorAction Ignore - } - - It 'Should succeed when _exist is false and value does not exist' -Skip:(!$IsWindows) { - $config = @{ - '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - resources = @( - @{ - name = 'reg' - type = 'Microsoft.Windows/Registry' - properties = @{ - keyPath = 'HKCU' - valueName = 'Test' - valueData = @{ - String = 'Test' - } - _exist = $false - } - } - ) + $deleteJson = @' + { + "keyPath": "HKEY_LOCAL_MACHINE\\Software\\Policies\\Microsoft\\Windows\\Appx", + "valueName": "DSCTestValue" } - - $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json +'@ + $out = registry config delete --input $deleteJson 2>$null $LASTEXITCODE | Should -Be 0 - $out.results[0].result.afterState._exist | Should -Be $false - - Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty - } - It 'Should succeed when _exist is false and key does not exist' -Skip:(!$IsWindows) { - $config = @{ - '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' - resources = @( - @{ - name = 'reg' - type = 'Microsoft.Windows/Registry' - properties = @{ - keyPath = 'HKCU\1' - _exist = $false - } - } - ) - } - - $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json - $LASTEXITCODE | Should -Be 0 - $out.results[0].result.afterState._exist | Should -Be $false + $result = registry config get --input $getJson 2>$null | ConvertFrom-Json + $result._exist | Should -Be $false + $result.valueData | Should -BeNullOrEmpty } } From f9eb12111a1eea6aaa026a37580b8d7c807e1bf7 Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Fri, 24 Oct 2025 04:35:43 +0200 Subject: [PATCH 2/3] Bump up version --- resources/registry/registry.dsc.resource.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/registry/registry.dsc.resource.json b/resources/registry/registry.dsc.resource.json index 505050921..8a5490869 100644 --- a/resources/registry/registry.dsc.resource.json +++ b/resources/registry/registry.dsc.resource.json @@ -5,7 +5,7 @@ "tags": [ "Windows" ], - "version": "0.1.0", + "version": "1.0.0", "get": { "executable": "registry", "args": [ From 726ce295094c1bf10a8a9ae38fd55480c8f693ef Mon Sep 17 00:00:00 2001 From: "G.Reijn" Date: Fri, 24 Oct 2025 04:36:30 +0200 Subject: [PATCH 3/3] Uncomment tests --- .../tests/registry.config.set.tests.ps1 | 274 +++++++++--------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/resources/registry/tests/registry.config.set.tests.ps1 b/resources/registry/tests/registry.config.set.tests.ps1 index 395a67e4c..7b6cb404c 100644 --- a/resources/registry/tests/registry.config.set.tests.ps1 +++ b/resources/registry/tests/registry.config.set.tests.ps1 @@ -8,143 +8,143 @@ Describe 'registry config set tests' { } } -# It 'Can set a deeply nested key and value' -Skip:(!$IsWindows) { -# $json = @' -# { -# "keyPath": "HKCU\\1\\2\\3", -# "valueName": "Hello", -# "valueData": { -# "String": "World" -# } -# } -# '@ -# $out = registry config set --input $json 2>$null -# $LASTEXITCODE | Should -Be 0 -# $out | Should -BeNullOrEmpty -# $result = registry config get --input $json 2>$null | ConvertFrom-Json -# $result.keyPath | Should -Be 'HKCU\1\2\3' -# $result.valueName | Should -Be 'Hello' -# $result.valueData.String | Should -Be 'World' -# ($result.psobject.properties | Measure-Object).Count | Should -Be 3 - -# $out = registry config get --input $json 2>$null -# $LASTEXITCODE | Should -Be 0 -# $result = $out | ConvertFrom-Json -# $result.keyPath | Should -Be 'HKCU\1\2\3' -# $result.valueName | Should -Be 'Hello' -# $result.valueData.String | Should -Be 'World' -# ($result.psobject.properties | Measure-Object).Count | Should -Be 3 -# } - -# It 'delete called when _exist is false' -Skip:(!$IsWindows) { -# $config = @{ -# '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# resources = @( -# @{ -# name = 'reg' -# type = 'Microsoft.Windows/Registry' -# properties = @{ -# keyPath = 'HKCU\1\2' -# valueName = 'Test' -# valueData = @{ -# String = 'Test' -# } -# _exist = $true -# } -# } -# ) -# } - -# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) -# $LASTEXITCODE | Should -Be 0 - -# $config.resources[0].properties._exist = $false -# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.afterState._exist | Should -Be $false - -# Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty - -# $config.resources[0].properties.valueName = $null -# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.afterState._exist | Should -Be $false - -# Get-Item -Path 'HKCU:\1\2' -ErrorAction Ignore | Should -BeNullOrEmpty -# } - -# It 'Can set value without data' -Skip:(!$IsWindows) { -# $configYaml = @' -# $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json -# resources: -# - name: Key -# type: Microsoft.Windows/Registry -# properties: -# keyPath: 'HKCU\1' -# valueName: Test -# _exist: true -# '@ - -# $out = dsc config set -i $configYaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.afterState.keyPath | Should -BeExactly 'HKCU\1' -# $out.results[0].result.afterState.valueName | Should -BeExactly 'Test' -# $out.results[0].result.afterState.valueData | Should -BeNullOrEmpty - -# $out = dsc config get -i $configYaml | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.actualState.keyPath | Should -BeExactly 'HKCU\1' -# $out.results[0].result.actualState.valueName | Should -BeExactly 'Test' -# $out.results[0].result.actualState.valueData | Should -BeNullOrEmpty - -# Remove-Item -Path 'HKCU:\1' -Recurse -ErrorAction Ignore -# } - -# It 'Should succeed when _exist is false and value does not exist' -Skip:(!$IsWindows) { -# $config = @{ -# '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# resources = @( -# @{ -# name = 'reg' -# type = 'Microsoft.Windows/Registry' -# properties = @{ -# keyPath = 'HKCU' -# valueName = 'Test' -# valueData = @{ -# String = 'Test' -# } -# _exist = $false -# } -# } -# ) -# } - -# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.afterState._exist | Should -Be $false - -# Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty -# } - -# It 'Should succeed when _exist is false and key does not exist' -Skip:(!$IsWindows) { -# $config = @{ -# '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' -# resources = @( -# @{ -# name = 'reg' -# type = 'Microsoft.Windows/Registry' -# properties = @{ -# keyPath = 'HKCU\1' -# _exist = $false -# } -# } -# ) -# } - -# $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json -# $LASTEXITCODE | Should -Be 0 -# $out.results[0].result.afterState._exist | Should -Be $false -# } + It 'Can set a deeply nested key and value' -Skip:(!$IsWindows) { + $json = @' + { + "keyPath": "HKCU\\1\\2\\3", + "valueName": "Hello", + "valueData": { + "String": "World" + } + } +'@ + $out = registry config set --input $json 2>$null + $LASTEXITCODE | Should -Be 0 + $out | Should -BeNullOrEmpty + $result = registry config get --input $json 2>$null | ConvertFrom-Json + $result.keyPath | Should -Be 'HKCU\1\2\3' + $result.valueName | Should -Be 'Hello' + $result.valueData.String | Should -Be 'World' + ($result.psobject.properties | Measure-Object).Count | Should -Be 3 + + $out = registry config get --input $json 2>$null + $LASTEXITCODE | Should -Be 0 + $result = $out | ConvertFrom-Json + $result.keyPath | Should -Be 'HKCU\1\2\3' + $result.valueName | Should -Be 'Hello' + $result.valueData.String | Should -Be 'World' + ($result.psobject.properties | Measure-Object).Count | Should -Be 3 + } + + It 'delete called when _exist is false' -Skip:(!$IsWindows) { + $config = @{ + '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + resources = @( + @{ + name = 'reg' + type = 'Microsoft.Windows/Registry' + properties = @{ + keyPath = 'HKCU\1\2' + valueName = 'Test' + valueData = @{ + String = 'Test' + } + _exist = $true + } + } + ) + } + + $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) + $LASTEXITCODE | Should -Be 0 + + $config.resources[0].properties._exist = $false + $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.afterState._exist | Should -Be $false + + Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty + + $config.resources[0].properties.valueName = $null + $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.afterState._exist | Should -Be $false + + Get-Item -Path 'HKCU:\1\2' -ErrorAction Ignore | Should -BeNullOrEmpty + } + + It 'Can set value without data' -Skip:(!$IsWindows) { + $configYaml = @' + $schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json + resources: + - name: Key + type: Microsoft.Windows/Registry + properties: + keyPath: 'HKCU\1' + valueName: Test + _exist: true +'@ + + $out = dsc config set -i $configYaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.afterState.keyPath | Should -BeExactly 'HKCU\1' + $out.results[0].result.afterState.valueName | Should -BeExactly 'Test' + $out.results[0].result.afterState.valueData | Should -BeNullOrEmpty + + $out = dsc config get -i $configYaml | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.actualState.keyPath | Should -BeExactly 'HKCU\1' + $out.results[0].result.actualState.valueName | Should -BeExactly 'Test' + $out.results[0].result.actualState.valueData | Should -BeNullOrEmpty + + Remove-Item -Path 'HKCU:\1' -Recurse -ErrorAction Ignore + } + + It 'Should succeed when _exist is false and value does not exist' -Skip:(!$IsWindows) { + $config = @{ + '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + resources = @( + @{ + name = 'reg' + type = 'Microsoft.Windows/Registry' + properties = @{ + keyPath = 'HKCU' + valueName = 'Test' + valueData = @{ + String = 'Test' + } + _exist = $false + } + } + ) + } + + $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.afterState._exist | Should -Be $false + + Get-ItemProperty -Path 'HKCU:\1\2' -Name 'Test' -ErrorAction Ignore | Should -BeNullOrEmpty + } + + It 'Should succeed when _exist is false and key does not exist' -Skip:(!$IsWindows) { + $config = @{ + '$schema' = 'https://aka.ms/dsc/schemas/v3/bundled/config/document.json' + resources = @( + @{ + name = 'reg' + type = 'Microsoft.Windows/Registry' + properties = @{ + keyPath = 'HKCU\1' + _exist = $false + } + } + ) + } + + $out = dsc config set -i ($config | ConvertTo-Json -Depth 10) | ConvertFrom-Json + $LASTEXITCODE | Should -Be 0 + $out.results[0].result.afterState._exist | Should -Be $false + } It 'Can delete value from system-protected key with minimal permissions' -Skip:(!$IsWindows) { $testKeyPath = 'HKLM:\Software\Policies\Microsoft\Windows\Appx'