diff --git a/lib/ansible/modules/windows/win_regedit.ps1 b/lib/ansible/modules/windows/win_regedit.ps1 index e270ec04adc..28d7bc117be 100644 --- a/lib/ansible/modules/windows/win_regedit.ps1 +++ b/lib/ansible/modules/windows/win_regedit.ps1 @@ -1,24 +1,11 @@ #!powershell # This file is part of Ansible -# + # (c) 2015, Adam Keech , Josh Ludwig # (c) 2017, Jordan Borean -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) -# WANT_JSON -# POWERSHELL_COMMON +#Requires -Module Ansible.ModuleUtils.Legacy.psm1 $ErrorActionPreference = "Stop" @@ -32,6 +19,7 @@ $data = Get-AnsibleParam -obj $params -name "data" $type = Get-AnsibleParam -obj $params -name "type" -type "str" -default "string" -validateset "none","binary","dword","expandstring","multistring","string","qword" -aliases "datatype" $state = Get-AnsibleParam -obj $params -name "state" -type "str" -default "present" -validateset "present","absent" $delete_key = Get-AnsibleParam -obj $params -name "delete_key" -type "bool" -default $true +$hive = Get-AnsibleParam -obj $params -name "hive" -type "path" $result = @{ changed = $false @@ -45,6 +33,147 @@ if ($diff_mode) { } } +$registry_util = @' +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Ansible +{ + [StructLayout(LayoutKind.Sequential)] + public struct LUID + { + public UInt32 LowPart; + public Int32 HighPart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TOKEN_PRIVILEGES + { + public UInt32 PrivilegeCount; + public LUID Luid; + public UInt32 Attributes; + } + + public enum HKEY : uint + { + LOCAL_MACHINE = 0x80000002, + USERS = 0x80000003 + } + + public class Win32Exception : System.ComponentModel.Win32Exception + { + private string _msg; + public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { } + public Win32Exception(int errorCode, string message) : base(errorCode) + { + _msg = String.Format("{0} ({1}, Win32ErrorCode {2})", message, base.Message, errorCode); + } + public override string Message { get { return _msg; } } + public static explicit operator Win32Exception(string message) { return new Win32Exception(message); } + } + + public class RegistryUtil + { + + public const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; + public const int TOKEN_QUERY = 0x00000008; + public const int SE_PRIVILEGE_ENABLED = 0x00000002; + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern IntPtr GetCurrentProcess(); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern bool CloseHandle( + IntPtr hObject); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto)] + private static extern bool OpenProcessToken( + IntPtr ProcessHandle, + UInt32 DesiredAccess, + out IntPtr TokenHandle); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto)] + private static extern bool LookupPrivilegeValue( + string lpSystemName, + string lpName, + [MarshalAs(UnmanagedType.Struct)] out LUID lpLuid); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto)] + private static extern bool AdjustTokenPrivileges( + IntPtr TokenHandle, + [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, + ref TOKEN_PRIVILEGES NewState, + UInt32 BufferLength, + IntPtr PreviousState, + IntPtr ReturnLength); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegLoadKey( + HKEY hKey, + string lpSubKey, + string lpFile); + + [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern int RegUnLoadKey( + HKEY hKey, + string lpSubKey); + + public static void EnablePrivileges() + { + List privileges = new List() + { + "SeRestorePrivilege", + "SeBackupPrivilege" + }; + foreach (string privilege in privileges) + { + IntPtr hToken; + LUID luid; + TOKEN_PRIVILEGES tkpPrivileges; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken)) + throw new Win32Exception("OpenProcessToken() failed"); + + try + { + if (!LookupPrivilegeValue(null, privilege, out luid)) + throw new Win32Exception("LookupPrivilegeValue() failed"); + + tkpPrivileges.PrivilegeCount = 1; + tkpPrivileges.Luid = luid; + tkpPrivileges.Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(hToken, false, ref tkpPrivileges, 0, IntPtr.Zero, IntPtr.Zero)) + throw new Win32Exception(String.Format("AdjustTokenPrivileges() failed to adjust privilege {0}", privilege)); + } + finally + { + CloseHandle(hToken); + } + } + } + + public static void LoadHive(string lpSubKey, string lpFile) + { + int ret; + ret = RegLoadKey(HKEY.LOCAL_MACHINE, lpSubKey, lpFile); + if (ret != 0) + throw new Win32Exception(ret, String.Format("Failed to load registry hive at {0}", lpFile)); + } + + public static void UnloadHive(string lpSubKey) + { + GC.Collect(); + int ret; + ret = RegUnLoadKey(HKEY.LOCAL_MACHINE, lpSubKey); + if (ret != 0) + throw new Win32Exception(ret, String.Format("Failed to unload registry hive at {0}", lpSubKey)); + } + } +} +'@ + # Fix HCCC:\ PSDrive for pre-2.3 compatibility if ($path -match "^HCCC:\\") { Add-DeprecationWarning -obj $result -message "Please use path: HKCC:\... instead of path: $path" -version 2.6 @@ -110,7 +239,8 @@ Function Test-RegistryProperty($path, $name) { # will validate if the registry key contains the property, returns true # if the property exists and false if the property does not try { - $value = (Get-Item -Path $path).GetValue($name) + $reg_key = Get-Item -Path $path + $value = $reg_key.GetValue($name) # need to do it this way return ($value -eq $null) does not work if ($value -eq $null) { return $false @@ -120,6 +250,10 @@ Function Test-RegistryProperty($path, $name) { } catch [System.Management.Automation.ItemNotFoundException] { # key didn't exist so the property mustn't return $false + } finally { + if ($reg_key) { + $reg_key.Close() + } } } @@ -235,59 +369,121 @@ if ($type -in @("binary", "none")) { } } - # convert the type string to the .NET class $type = [System.Enum]::Parse([Microsoft.Win32.RegistryValueKind], $type, $true) -if ($state -eq "present") { - if (-not (Test-Path -path $path)) { - # the key doesn't exist, create it so the next steps work - try { - $null = New-Item -Path $path -Type directory -Force -WhatIf:$check_mode - } catch { - Fail-Json $result "failed to create registry key at $($path): $($_.Exception.Message)" - } - $result.changed = $true +if ($hive) { + if (-not (Test-Path $hive)) { + Fail-Json -obj $result -message "hive at path '$hive' is not valid or accessible, cannot load hive" + } + Add-Type -TypeDefinition $registry_util + try { + [Ansible.RegistryUtil]::EnablePrivileges() + } catch [System.ComponentModel.Win32Exception] { + Fail-Json -obj $result -message "failed to enable SeRestorePrivilege and SeRestorePrivilege for the current process: $($_.Exception.Message)" + } - if ($diff_mode) { - $result.diff.prepared += @" -+[$path] -"@ + if (Test-Path -Path HKLM:\ANSIBLE) { + Add-Warning -obj $result -message "hive already loaded at HKLM:\ANSIBLE, had to unload hive for win_regedit to continue" + try { + [Ansible.RegistryUtil]::UnloadHive("ANSIBLE") + } catch [System.ComponentModel.Win32Exception] { + Fail-Json -obj $result -message "failed to unload registry hive HKLM:\ANSIBLE from $($hive): $($_.Exception.Message)" } } - if (Test-RegistryProperty -path $path -name $name) { - # property exists, need to compare the values and type - $existing_key = Get-Item -Path $path - $existing_type = $existing_key.GetValueKind($name) - $existing_data = $existing_key.GetValue($name, $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) - $change_value = $false - - if ($type -ne $existing_type) { - $change_value = $true - $result.data_type_changed = $true - $data_mismatch = Compare-RegistryProperties -existing $existing_data -new $data - if ($data_mismatch) { - $result.data_changed = $true - } - } else { - $data_mismatch = Compare-RegistryProperties -existing $existing_data -new $data - if ($data_mismatch) { - $change_value = $true - $result.data_changed = $true - } - } + try { + [Ansible.RegistryUtil]::LoadHive("ANSIBLE", $hive) + } catch [System.ComponentModel.Win32Exception] { + Fail-Json -obj $result -message "failed to load registry hive from '$hive' to HKLM:\ANSIBLE: $($_.Exception.Message)" + } +} - if ($change_value) { - if (-not $check_mode) { - try { - (Get-Item -Path $path).OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree).SetValue($name, $data, $type) - } catch { - Fail-Json $result "failed to change registry property '$name' at $($path): $($_.Exception.Message)" +try { + if ($state -eq "present") { + if (-not (Test-Path -path $path)) { + # the key doesn't exist, create it so the next steps work + try { + $new_key = New-Item -Path $path -Type directory -Force -WhatIf:$check_mode + } catch { + Fail-Json $result "failed to create registry key at $($path): $($_.Exception.Message)" + } finally { + if ($new_key) { + $new_key.Close() + } + } + $result.changed = $true + + if ($diff_mode) { + $result.diff.prepared += @" ++[$path] +"@ + } + } + + if (Test-RegistryProperty -path $path -name $name) { + # property exists, need to compare the values and type + $existing_key = Get-Item -Path $path + $existing_type = $existing_key.GetValueKind($name) + $existing_data = $existing_key.GetValue($name, $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) + $existing_key.Close() + $change_value = $false + + if ($type -ne $existing_type) { + $change_value = $true + $result.data_type_changed = $true + $data_mismatch = Compare-RegistryProperties -existing $existing_data -new $data + if ($data_mismatch) { + $result.data_changed = $true + } + } else { + $data_mismatch = Compare-RegistryProperties -existing $existing_data -new $data + if ($data_mismatch) { + $change_value = $true + $result.data_changed = $true + } + } + + if ($change_value) { + if (-not $check_mode) { + $reg_key = Get-Item -Path $path + try { + $reg_key.OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree).SetValue($name, $data, $type) + } catch { + Fail-Json $result "failed to change registry property '$name' at $($path): $($_.Exception.Message)" + } finally { + $reg_key.Close() + } + } + $result.changed = $true + + if ($diff_mode) { + if ($result.diff.prepared) { + $key_prefix = "+" + } else { + $key_prefix = "" + } + + $result.diff.prepared = @" +$key_prefix[$path] +-"$name" = "$(Get-DiffValueString -type $existing_type -value $existing_data)" ++"$name" = "$(Get-DiffValueString -type $type -value $data)" +"@ + } + } + } else { + # property doesn't exist just create a new one + if (-not $check_mode) { + $reg_key = Get-Item -Path $path + try { + $reg_key.OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree).SetValue($name, $data, $type) + } catch { + Fail-Json $result "failed to change registry property '$name' at $($path): $($_.Exception.Message)" + } finally { + $reg_key.Close() } } $result.changed = $true - if ($diff_mode) { if ($result.diff.prepared) { $key_prefix = "+" @@ -297,76 +493,66 @@ if ($state -eq "present") { $result.diff.prepared = @" $key_prefix[$path] --"$name" = "$(Get-DiffValueString -type $existing_type -value $existing_data)" +"$name" = "$(Get-DiffValueString -type $type -value $data)" "@ } } } else { - # property doesn't exist just create a new one - if (-not $check_mode) { - try { - (Get-Item -Path $path).OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree).SetValue($name, $data, $type) - } catch { - Fail-Json $result "failed to change registry property '$name' at $($path): $($_.Exception.Message)" - } - } - $result.changed = $true - if ($diff_mode) { - if ($result.diff.prepared) { - $key_prefix = "+" - } else { - $key_prefix = "" - } - - $result.diff.prepared = @" -$key_prefix[$path] -+"$name" = "$(Get-DiffValueString -type $type -value $data)" -"@ - } - } -} else { - if (Test-Path -path $path) { - if ($delete_key -and $name -eq $null) { - # the clear_key flag is set and name is null so delete the entire key - try { - $null = Remove-Item -Path $path -Force -Recurse -WhatIf:$check_mode - } catch { - Fail-Json $result "failed to delete registry key at $($path): $($_.Exception.Message)" - } - $result.changed = $true - - if ($diff_mode) { - $result.diff.prepared += @" --[$path] -"@ - } - } else { - # the clear_key flag is set or name is not null, check whether we need to delete a property - if (Test-RegistryProperty -path $path -name $name) { - $existing_key = Get-Item -Path $path - $existing_type = $existing_key.GetValueKind($name) - $existing_data = $existing_key.GetValue($name, $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) - - # cannot use Remove-ItemProperty as it fails when deleting the (Default) key ($name = $null) - if (-not $check_mode) { - try { - (Get-Item -Path $path).OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree).DeleteValue($name) - } catch { - Fail-Json $result "failed to delete registry property '$name' at $($path): $($_.Exception.Message)" - } + if (Test-Path -path $path) { + if ($delete_key -and $name -eq $null) { + # the clear_key flag is set and name is null so delete the entire key + try { + $null = Remove-Item -Path $path -Force -Recurse -WhatIf:$check_mode + } catch { + Fail-Json $result "failed to delete registry key at $($path): $($_.Exception.Message)" } $result.changed = $true - + if ($diff_mode) { $result.diff.prepared += @" +-[$path] +"@ + } + } else { + # the clear_key flag is set or name is not null, check whether we need to delete a property + if (Test-RegistryProperty -path $path -name $name) { + $existing_key = Get-Item -Path $path + $existing_type = $existing_key.GetValueKind($name) + $existing_data = $existing_key.GetValue($name, $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) + $existing_key.Close() + + # cannot use Remove-ItemProperty as it fails when deleting the (Default) key ($name = $null) + if (-not $check_mode) { + $reg_key = Get-Item -Path $path + try { + $reg_key.OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree).DeleteValue($name) + } catch { + Fail-Json $result "failed to delete registry property '$name' at $($path): $($_.Exception.Message)" + } finally { + $reg_key.Close() + } + } + $result.changed = $true + + if ($diff_mode) { + $result.diff.prepared += @" [$path] -"$name" = "$(Get-DiffValueString -type $existing_type -value $existing_data)" "@ + } } } } } +} finally { + if ($hive) { + [GC]::Collect() + try { + [Ansible.RegistryUtil]::UnloadHive("ANSIBLE") + } catch [System.ComponentModel.Win32Exception] { + Fail-Json -obj $result -message "failed to unload registry hive HKLM:\ANSIBLE from $($hive): $($_.Exception.Message)" + } + } } Exit-Json $result diff --git a/lib/ansible/modules/windows/win_regedit.py b/lib/ansible/modules/windows/win_regedit.py index 5b1451c1bfb..016b59e27ef 100644 --- a/lib/ansible/modules/windows/win_regedit.py +++ b/lib/ansible/modules/windows/win_regedit.py @@ -83,10 +83,21 @@ options: type: bool default: 'yes' version_added: '2.4' + hive: + description: + - A path to a hive key like C:\Users\Default\NTUSER.DAT to load in the + registry. + - This hive is loaded under the HKLM:\ANSIBLE key which can then be used + in I(name) like any other path. + - This can be used to load the default user profile registry hive or any + other hive saved as a file. + - Using this function requires the user to have the C(SeRestorePrivilege) + and C(SeBackupPrivilege) privileges enabled. + version_added: '2.5' notes: - Check-mode C(-C/--check) and diff output C(-D/--diff) are supported, so that you can test every change against the active configuration before applying changes. -- Beware that some registry hives (C(HKEY_USERS) in particular) do not allow to create new registry paths. +- Beware that some registry hives (C(HKEY_USERS) in particular) do not allow to create new registry paths in the root folder. - Since ansible 2.4, when checking if a string registry value has changed, a case-sensitive test is used. Previously the test was case-insensitive. author: - Adam Keech (@smadam813) @@ -178,6 +189,15 @@ EXAMPLES = r''' path: HKCU:\Software\MyCompany name: hello state: absent + +- name: Change default mouse trailing settings for new users + win_regedit: + path: HKLM:\ANSIBLE\Control Panel\Mouse + name: MouseTrails + data: 10 + type: string + state: present + hive: C:\Users\Default\NTUSER.dat ''' RETURN = r''' diff --git a/test/integration/targets/win_regedit/defaults/main.yml b/test/integration/targets/win_regedit/defaults/main.yml index 87aa3e597ce..cb3b84b0a15 100644 --- a/test/integration/targets/win_regedit/defaults/main.yml +++ b/test/integration/targets/win_regedit/defaults/main.yml @@ -1,2 +1,3 @@ test_win_regedit_local_key: HKLM:\Software\Cow Corp test_win_regedit_classes_key: HKCR:\.test-ansible +test_win_regedit_hive_key: HKLM:\ANSIBLE\NewKey diff --git a/test/integration/targets/win_regedit/tasks/cleanup.yml b/test/integration/targets/win_regedit/tasks/cleanup.yml new file mode 100644 index 00000000000..f10452506ec --- /dev/null +++ b/test/integration/targets/win_regedit/tasks/cleanup.yml @@ -0,0 +1,18 @@ +--- +- name: load HKLM:\ANSIBLE with test hive + win_command: reg.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat + failed_when: false + +- name: make sure testing keys are removed before test + win_regedit: + path: '{{item}}' + delete_key: yes + state: absent + with_items: + - '{{test_win_regedit_local_key}}' + - '{{test_win_regedit_classes_key}}' + - '{{test_win_regedit_hive_key}}' + +- name: ensure HKLM:\ANSIBLE is unloaded + win_command: reg.exe unload HKLM\ANSIBLE + failed_when: false diff --git a/test/integration/targets/win_regedit/tasks/main.yml b/test/integration/targets/win_regedit/tasks/main.yml index e8468a096eb..86ca1cbd601 100644 --- a/test/integration/targets/win_regedit/tasks/main.yml +++ b/test/integration/targets/win_regedit/tasks/main.yml @@ -1,12 +1,6 @@ --- -- name: make sure testing keys are removed before test - win_regedit: - path: '{{item}}' - delete_key: yes - state: absent - with_items: - - '{{test_win_regedit_local_key}}' - - '{{test_win_regedit_classes_key}}' +- name: make sure we start on a blank state + include_tasks: cleanup.yml - block: - name: run tests for each property type @@ -81,10 +75,4 @@ always: - name: make sure testing keys are removed after test - win_regedit: - path: '{{item}}' - delete_key: yes - state: absent - with_items: - - '{{test_win_regedit_local_key}}' - - '{{test_win_regedit_classes_key}}' + include_tasks: cleanup.yml diff --git a/test/integration/targets/win_regedit/tasks/tests.yml b/test/integration/targets/win_regedit/tasks/tests.yml index 1e39de566f7..9144d491b5a 100644 --- a/test/integration/targets/win_regedit/tasks/tests.yml +++ b/test/integration/targets/win_regedit/tasks/tests.yml @@ -458,3 +458,258 @@ assert: that: - not create_prop_with_json_again|changed + +- name: create new key in loaded hive (check mode) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + state: present + hive: C:\Users\Default\NTUSER.dat + register: new_key_in_hive_check + check_mode: yes + +- name: get result of create new key in loaded hive (check mode) + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + Test-Path -Path HKLM:\ANSIBLE\NewKey + exit 0 + register: new_key_in_hive_result_check + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of create new key in loaded hive (check mode) + assert: + that: + - new_key_in_hive_check|changed + - new_key_in_hive_result_check.stdout == "False\r\n" + +- name: create new key in loaded hive + win_regedit: + path: '{{test_win_regedit_hive_key}}' + state: present + hive: C:\Users\Default\NTUSER.dat + register: new_key_in_hive + +- name: get result of create new key in loaded hive + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + Test-Path -Path HKLM:\ANSIBLE\NewKey + exit 0 + register: new_key_in_hive_result + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of create new key in loaded hive + assert: + that: + - new_key_in_hive|changed + - new_key_in_hive_result.stdout == "True\r\n" + +- name: create new key in loaded hive (idempotent) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + state: present + hive: C:\Users\Default\NTUSER.dat + register: new_key_in_hive_again + +- name: assert result of create new key in loaded hive (idempotent) + assert: + that: + - not new_key_in_hive_again|changed + +- name: set hive key property (check mode) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + name: TestProp + data: string + type: string + state: present + hive: C:\Users\Default\NTUSER.dat + register: new_prop_in_hive_check + check_mode: yes + +- name: get result of set hive key property (check mode) + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + $prop = Get-ItemProperty -Path HKLM:\ANSIBLE\NewKey -Name TestProp -ErrorAction SilentlyContinue + if ($prop) { + $prop.TestProp + } + exit 0 + register: new_prop_in_hive_result_check + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of set hive key property (check mode) + assert: + that: + - new_prop_in_hive_check|changed + - new_prop_in_hive_result_check.stdout == "" + +- name: set hive key property + win_regedit: + path: '{{test_win_regedit_hive_key}}' + name: TestProp + data: string + type: string + state: present + hive: C:\Users\Default\NTUSER.dat + register: new_prop_in_hive + +- name: get result of set hive key property + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + $prop = Get-ItemProperty -Path HKLM:\ANSIBLE\NewKey -Name TestProp -ErrorAction SilentlyContinue + if ($prop) { + $prop.TestProp + } + exit 0 + register: new_prop_in_hive_result + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of set hive key property + assert: + that: + - new_prop_in_hive|changed + - new_prop_in_hive_result.stdout == "string\r\n" + +- name: set hive key property (idempotent) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + name: TestProp + data: string + type: string + state: present + hive: C:\Users\Default\NTUSER.dat + register: new_prop_in_hive_again + +- name: assert result of set hive key property (idempotent) + assert: + that: + - not new_prop_in_hive_again|changed + +- name: remove hive key property (check mode) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + name: TestProp + state: absent + hive: C:\Users\Default\NTUSER.dat + register: remove_prop_in_hive_check + check_mode: yes + +- name: get result of remove hive key property (check mode) + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + $prop = Get-ItemProperty -Path HKLM:\ANSIBLE\NewKey -Name TestProp -ErrorAction SilentlyContinue + if ($prop) { + $prop.TestProp + } + exit 0 + register: remove_prop_in_hive_result_check + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of remove hive key property (check mode) + assert: + that: + - remove_prop_in_hive_check|changed + - remove_prop_in_hive_result_check.stdout == "string\r\n" + +- name: remove hive key property + win_regedit: + path: '{{test_win_regedit_hive_key}}' + name: TestProp + state: absent + hive: C:\Users\Default\NTUSER.dat + register: remove_prop_in_hive + +- name: get result of remove hive key property + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + $prop = Get-ItemProperty -Path HKLM:\ANSIBLE\NewKey -Name TestProp -ErrorAction SilentlyContinue + if ($prop) { + $prop.TestProp + } + exit 0 + register: remove_prop_in_hive_result + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of remove hive key property + assert: + that: + - remove_prop_in_hive|changed + - remove_prop_in_hive_result.stdout == "" + +- name: remove hive key property (idempotent) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + name: TestProp + state: absent + hive: C:\Users\Default\NTUSER.dat + register: remove_prop_in_hive_again + +- name: assert result of set hive key property (idempotent) + assert: + that: + - not remove_prop_in_hive_again|changed + +- name: remove key in loaded hive (check mode) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + state: absent + delete_yes: yes + hive: C:\Users\Default\NTUSER.dat + register: remove_key_in_hive_check + check_mode: yes + +- name: get result of remove key in loaded hive (check mode) + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + Test-Path -Path HKLM:\ANSIBLE\NewKey + exit 0 + register: remove_key_in_hive_result_check + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of removekey in loaded hive (check mode) + assert: + that: + - remove_key_in_hive_check|changed + - remove_key_in_hive_result_check.stdout == "True\r\n" + +- name: remove key in loaded hive + win_regedit: + path: '{{test_win_regedit_hive_key}}' + state: absent + delete_yes: yes + hive: C:\Users\Default\NTUSER.dat + register: remove_key_in_hive + +- name: get result of remove key in loaded hive + win_shell: | + ®.exe load HKLM\ANSIBLE C:\Users\Default\NTUSER.dat > $null + Test-Path -Path HKLM:\ANSIBLE\NewKey + exit 0 + register: remove_key_in_hive_result + +- win_command: reg.exe unload HKLM\ANSIBLE + +- name: assert result of remove key in loaded hive + assert: + that: + - remove_key_in_hive|changed + - remove_key_in_hive_result.stdout == "False\r\n" + +- name: remove key in loaded hive (idempotent) + win_regedit: + path: '{{test_win_regedit_hive_key}}' + state: absent + delete_yes: yes + hive: C:\Users\Default\NTUSER.dat + register: remove_key_in_hive_again + +- name: assert result of remove key in loaded hive (idempotent) + assert: + that: + - not remove_key_in_hive_again|changed