win reg - Support special chars in path (#53305)

* win reg - Support special chars in path

* Added deprecation warning for path separators
pull/53478/head
Jordan Borean 5 years ago committed by GitHub
parent e4f2e15b96
commit 072fa54b50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
bugfixes:
- win_regedit - Fix issue where creating a new key would set the ``(Default)`` key property to an empty string instead of undefined
- win_regedit - Support registry paths with special characters - https://github.com/ansible/ansible/issues/41791
- win_reg_stat - Support registry paths with special characters - https://github.com/ansible/ansible/issues/41791
- win_reg_stat - Fix issue where the key's ``(Default)`` property was not being returned if it was set

@ -15,122 +15,112 @@ $result = @{
changed = $false
}
Function Get-NetHiveName($hive) {
# Will also check that the hive passed in the path is a known hive
switch ($hive.ToUpper()) {
"HKCR" {"ClassesRoot"}
"HKCC" {"CurrentConfig"}
"HKCU" {"CurrentUser"}
"HKLM" {"LocalMachine"}
"HKU" {"Users"}
default {"unsupported"}
Function Get-PropertyValue {
param(
[Parameter(Mandatory=$true)][Microsoft.Win32.RegistryKey]$Key,
[String]$Name
)
$value = $Key.GetValue($Name, $null, [Microsoft.Win32.RegistryValueOptions]::None)
if ($null -eq $value) {
# Property does not exist or the key's (Default) is not set
return $null
}
}
Function Get-PropertyType($hive, $path, $property) {
$type = (Get-Item REGISTRY::$hive\$path).GetValueKind($property)
switch ($type) {
"Binary" {"REG_BINARY"}
"String" {"REG_SZ"}
"DWord" {"REG_DWORD"}
"QWord" {"REG_QWORD"}
"MultiString" {"REG_MULTI_SZ"}
"ExpandString" {"REG_EXPAND_SZ"}
"None" {"REG_NONE"}
default {"Unknown"}
$raw_value = $Key.GetValue($Name, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
if ($Name -eq "") {
# The key's (Default) will fail on GetValueKind
$type = [Microsoft.Win32.RegistryValueKind]::String
} else {
$type = $Key.GetValueKind($Name)
}
}
Function Get-PropertyObject($hive, $net_hive, $path, $property) {
$value = (Get-ItemProperty REGISTRY::$hive\$path).$property
$type = Get-PropertyType -hive $hive -path $path -property $property
If ($type -eq 'REG_EXPAND_SZ') {
$raw_value = [Microsoft.Win32.Registry]::$net_hive.OpenSubKey($path).GetValue($property, $false, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
} ElseIf ($type -eq 'REG_BINARY' -or $type -eq 'REG_NONE') {
$raw_value = @()
if ($type -in @([Microsoft.Win32.RegistryValueKind]::Binary, [Microsoft.Win32.RegistryValueKind]::None)) {
$formatted_raw_value = [System.Collections.Generic.List`1[String]]@()
foreach ($byte in $value) {
$hex_value = ('{0:x}' -f $byte).PadLeft(2, '0')
$raw_value += "0x$hex_value"
$formatted_raw_value.Add("0x{0:x2}" -f $byte)
}
} Else {
$raw_value = $formatted_raw_value
} elseif ($type -eq [Microsoft.Win32.RegistryValueKind]::DWord) {
# .NET returns the value as a signed integer, we need to make it unsigned
$value = [UInt32]("0x{0:x}" -f $value)
$raw_value = $value
} elseif ($type -eq [Microsoft.Win32.RegistryValueKind]::QWord) {
$value = [UInt64]("0x{0:x}" -f $value)
$raw_value = $value
}
$object = @{
raw_value = $raw_value
value = $value
type = $type
}
$object
}
Function Test-RegistryProperty($hive, $path, $property) {
Try {
$type = (Get-Item REGISTRY::$hive\$path).GetValueKind($property)
} Catch {
$type = $null
$return_type = switch($type.ToString()) {
"Binary" { "REG_BINARY" }
"String" { "REG_SZ" }
"DWord" { "REG_DWORD" }
"QWord" { "REG_QWORD" }
"MultiString" { "REG_MULTI_SZ" }
"ExpandString" { "REG_EXPAND_SZ" }
"None" { "REG_NONE" }
default { "Unknown - $($type.ToString())" }
}
If ($type -eq $null) {
$false
} Else {
$true
return @{
type = $return_type
value = $value
raw_value = $raw_value
}
}
# Will validate the key parameter to make sure it matches known format
if ($path -match "^([a-zA-Z_]*):\\(.*)$") {
$hive = $matches[1]
$reg_path = $matches[2]
} else {
Fail-Json $result "path does not match format 'HIVE:\KEY_PATH'"
if ($path -notmatch "^HK(CC|CR|CU|LM|U):\\") {
Fail-Json -obj $result -message "path: $path is not a valid registry path, see module documentation for examples."
}
# Used when getting the actual REG_EXPAND_SZ value as well as checking the hive is a known value
$net_hive = Get-NetHiveName -hive $hive
if ($net_hive -eq 'unsupported') {
Fail-Json $result "the hive in path is '$hive'; must be 'HKCR', 'HKCC', 'HKCU', 'HKLM' or 'HKU'"
$registry_path = (Split-Path -Path $path -NoQualifier).Substring(1) # removes the hive: and leading \
$registry_hive = switch(Split-Path -Path $path -Qualifier) {
"HKCR:" { [Microsoft.Win32.Registry]::ClassesRoot }
"HKCC:" { [Microsoft.Win32.Registry]::CurrentConfig }
"HKCU:" { [Microsoft.Win32.Registry]::CurrentUser }
"HKLM:" { [Microsoft.Win32.Registry]::LocalMachine }
"HKU" { [Microsoft.Win32.Registry]::Users }
}
if (Test-Path REGISTRY::$hive\$reg_path) {
if ($name -eq $null) {
$property_info = @{}
$properties = Get-ItemProperty REGISTRY::$hive\$reg_path
foreach ($property in $properties.PSObject.Properties) {
# Powershell adds in some metadata we need to filter out
$real_property = Test-RegistryProperty -hive $hive -path $reg_path -property $property.Name
if ($real_property -eq $true) {
$property_object = Get-PropertyObject -hive $hive -net_hive $net_hive -path $reg_path -property $property.Name
$property_info.Add($property.Name, $property_object)
}
}
$key = $null
try {
$key = $registry_hive.OpenSubKey($registry_path, $false)
$sub_keys = @()
$sub_keys_raw = Get-ChildItem REGISTRY::$hive\$reg_path -ErrorAction SilentlyContinue
if ($null -ne $key) {
if ($null -eq $name) {
$property_info = @{}
foreach ($property in $key.GetValueNames()) {
$property_info.$property = Get-PropertyValue -Key $key -Name $property
}
foreach ($sub_key in $sub_keys_raw) {
$sub_keys += $sub_key.PSChildName
}
# Return the key's (Default) property if it has been defined
$default_value = Get-PropertyValue -Key $key -Name ""
if ($null -ne $default_value) {
$property_info."" = $default_value
}
$result.exists = $true
$result.sub_keys = $sub_keys
$result.properties = $property_info
} else {
$exists = Test-RegistryProperty -hive $hive -path $reg_path -property $name
if ($exists -eq $true) {
$propertyObject = Get-PropertyObject -hive $hive -net_hive $net_hive -path $reg_path -property $name
$result.exists = $true
$result.raw_value = $propertyObject.raw_value
$result.value = $propertyObject.value
$result.type = $propertyObject.type
$result.properties = $property_info
$result.sub_keys = $key.GetSubKeyNames()
} else {
$result.exists = $false
$property_value = Get-PropertyValue -Key $key -Name $name
if ($null -ne $property_value) {
$result.exists = $true
$result += $property_value
} else {
$result.exists = $false
}
}
} else {
$result.exists = $false
}
} else {
$result.exists = $false
} finally {
if ($key) {
$key.Dispose()
}
$registry_hive.Dispose()
}
Exit-Json $result
Exit-Json -obj $result

@ -29,8 +29,12 @@ options:
name:
description:
- The registry property name to get information for, the return json will not include the sub_keys and properties entries for the I(key) specified.
- Set to an empty string to target the registry key's C((Default)) property value.
type: str
aliases: [ entry, value, property ]
notes:
- The C(properties) return value will contain an empty string key C("") that refers to the key's C(Default) value. If
the value has not been set then this key is not returned.
seealso:
- module: win_regedit
- module: win_regmerge
@ -49,6 +53,12 @@ EXAMPLES = r'''
path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
name: CommonFilesDir
register: common_files_dir
- name: Obtain the registry key's (Default) property
win_reg_stat:
path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion
name: ''
register: current_version_default
'''
RETURN = r'''
@ -67,6 +77,11 @@ properties:
returned: success, path exists and property not specified
type: dict
sample: {
"" : {
"raw_value": "",
"type": "REG_SZ",
"value": ""
},
"binary_property" : {
"raw_value": ["0x01", "0x16"],
"type": "REG_BINARY",
@ -77,7 +92,7 @@ properties:
"type": "REG_MULTI_SZ",
"value": ["a", "b"]
}
}
}
sub_keys:
description: A list of all the sub keys of the key specified.
returned: success, path exists and property not specified

@ -8,8 +8,6 @@
#Requires -Module Ansible.ModuleUtils.Legacy
#Requires -Module Ansible.ModuleUtils.PrivilegeUtil
$ErrorActionPreference = "Stop"
$params = Parse-Args -arguments $args -supports_check_mode $true
$check_mode = Get-AnsibleParam -obj $params -name "_ansible_check_mode" -type "bool" -default $false
$diff_mode = Get-AnsibleParam -obj $params -name "_ansible_diff" -type "bool" -default $false
@ -31,7 +29,8 @@ $result = @{
if ($diff_mode) {
$result.diff = @{
prepared = ""
before = ""
after = ""
}
}
@ -40,12 +39,20 @@ using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Ansible.RegEdit
namespace Ansible.WinRegedit
{
public enum HKEY : uint
internal class NativeMethods
{
LOCAL_MACHINE = 0x80000002,
USERS = 0x80000003
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegLoadKeyW(
UInt32 hKey,
string lpSubKey,
string lpFile);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern int RegUnLoadKeyW(
UInt32 hKey,
string lpSubKey);
}
public class Win32Exception : System.ComponentModel.Win32Exception
@ -60,41 +67,48 @@ namespace Ansible.RegEdit
public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
}
public class Hive
public class Hive : IDisposable
{
[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);
private const UInt32 SCOPE = 0x80000002; // HKLM
private string hiveKey;
private bool loaded = false;
public static void LoadHive(string lpSubKey, string lpFile)
public Hive(string hiveKey, string hivePath)
{
int ret;
ret = RegLoadKey(HKEY.LOCAL_MACHINE, lpSubKey, lpFile);
this.hiveKey = hiveKey;
int ret = NativeMethods.RegLoadKeyW(SCOPE, hiveKey, hivePath);
if (ret != 0)
throw new Win32Exception(ret, String.Format("Failed to load registry hive at {0}", lpFile));
throw new Win32Exception(ret, String.Format("Failed to load registry hive at {0}", hivePath));
loaded = true;
}
public static void UnloadHive(string lpSubKey)
public static void UnloadHive(string hiveKey)
{
GC.Collect();
int ret;
ret = RegUnLoadKey(HKEY.LOCAL_MACHINE, lpSubKey);
int ret = NativeMethods.RegUnLoadKeyW(SCOPE, hiveKey);
if (ret != 0)
throw new Win32Exception(ret, String.Format("Failed to unload registry hive at {0}", lpSubKey));
throw new Win32Exception(ret, String.Format("Failed to unload registry hive at {0}", hiveKey));
}
public void Dispose()
{
if (loaded)
{
// Make sure the garbage collector disposes all unused handles and waits until it is complete
GC.Collect();
GC.WaitForPendingFinalizers();
UnloadHive(hiveKey);
loaded = false;
}
GC.SuppressFinalize(this);
}
~Hive() { this.Dispose(); }
}
}
'@
# fire a warning if the property name isn't specified, the (Default) key ($null) can only be a string
if ($name -eq $null -and $type -ne "string") {
if ($null -eq $name -and $type -ne "string") {
Add-Warning -obj $result -message "the data type when name is not specified can only be 'string', the type has automatically been converted"
$type = "string"
}
@ -104,16 +118,13 @@ if ($path -notmatch "^HK(CC|CR|CU|LM|U):\\") {
Fail-Json $result "path: $path is not a valid powershell path, see module documentation for examples."
}
# Create the required PSDrives if missing
$registry_hive = Split-Path -Path $path -Qualifier
if ($registry_hive -eq "HKCR:" -and (-not (Test-Path HKCR:\))) {
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT
}
if ($registry_hive -eq "HKU:" -and (-not (Test-Path HKU:\))) {
New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS
}
if ($registry_hive -eq "HKCC:" -and (-not (Test-Path HKCC:\))) {
New-PSDrive -Name HKCC -PSProvider Registry -Root HKEY_CURRENT_CONFIG
# Add a warning if the path does not contains a \ and is not the leaf path
$registry_path = (Split-Path -Path $path -NoQualifier).Substring(1) # removes the hive: and leading \
$registry_leaf = Split-Path -Path $path -Leaf
if ($registry_path -ne $registry_leaf -and -not $registry_path.Contains('\')) {
$msg = "path is not using '\' as a separator, support for '/' as a separator will be removed in a future Ansible version"
Add-DeprecationWarning -obj $result -message $msg -version 2.12
$registry_path = $registry_path.Replace('/', '\')
}
# Simplified version of Convert-HexStringToByteArray from
@ -148,62 +159,202 @@ Function Convert-RegExportHexStringToByteArray($string) {
}
}
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
Function Compare-RegistryProperties($existing, $new) {
# Outputs $true if the property values don't match
if ($existing -is [Array]) {
(Compare-Object -ReferenceObject $existing -DifferenceObject $new -SyncWindow 0).Length -ne 0
} else {
$existing -cne $new
}
}
Function Get-DiffValue {
param(
[Parameter(Mandatory=$true)][Microsoft.Win32.RegistryValueKind]$Type,
[Parameter(Mandatory=$true)][Object]$Value
)
$diff = @{ type = $Type.ToString(); value = $Value }
$enum = [Microsoft.Win32.RegistryValueKind]
if ($Type -in @($enum::Binary, $enum::None)) {
$diff.value = [System.Collections.Generic.List`1[String]]@()
foreach ($dec_value in $Value) {
$diff.value.Add("0x{0:x2}" -f $dec_value)
}
} elseif ($Type -eq $enum::DWord) {
$diff.value = "0x{0:x8}" -f $Value
} elseif ($Type -eq $enum::QWord) {
$diff.value = "0x{0:x16}" -f $Value
}
return $diff
}
Function Set-StateAbsent {
param(
# Used for diffs and exception messages to match up against Ansible input
[Parameter(Mandatory=$true)][String]$PrintPath,
[Parameter(Mandatory=$true)][Microsoft.Win32.RegistryKey]$Hive,
[Parameter(Mandatory=$true)][String]$Path,
[String]$Name,
[Switch]$DeleteKey
)
$key = $Hive.OpenSubKey($Path, $true)
if ($null -eq $key) {
# Key does not exist, no need to delete anything
return
}
try {
$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
if ($DeleteKey -and -not $Name) {
# delete_key=yes is set and name is null/empty, so delete the entire key
$key.Dispose()
$key = $null
if (-not $check_mode) {
try {
$Hive.DeleteSubKeyTree($Path, $false)
} catch {
Fail-Json -obj $result -message "failed to delete registry key at $($PrintPath): $($_.Exception.Message)"
}
}
$result.changed = $true
if ($diff_mode) {
$result.diff.before = @{$PrintPath = @{}}
$result.diff.after = @{}
}
} else {
return $true
# delete_key=no or name is not null/empty, delete the property not the full key
$property = $key.GetValue($Name)
if ($null -eq $property) {
# property does not exist
return
}
$property_type = $key.GetValueKind($Name) # used for the diff
if (-not $check_mode) {
try {
$key.DeleteValue($Name)
} catch {
Fail-Json -obj $result -message "failed to delete registry property '$Name' at $($PrintPath): $($_.Exception.Message)"
}
}
$result.changed = $true
if ($diff_mode) {
$diff_value = Get-DiffValue -Type $property_type -Value $property
$result.diff.before = @{ $PrintPath = @{ $Name = $diff_value } }
$result.diff.after = @{ $PrintPath = @{} }
}
}
} catch [System.Management.Automation.ItemNotFoundException] {
# key didn't exist so the property mustn't
return $false
} finally {
if ($reg_key) {
$reg_key.Close()
if ($key) {
$key.Dispose()
}
}
}
Function Compare-RegistryProperties($existing, $new) {
$mismatch = $false
if ($existing -is [Array]) {
if ((Compare-Object -ReferenceObject $existing -DifferenceObject $new -SyncWindow 0).Length -ne 0) {
$mismatch = $true
Function Set-StatePresent {
param(
[Parameter(Mandatory=$true)][String]$PrintPath,
[Parameter(Mandatory=$true)][Microsoft.Win32.RegistryKey]$Hive,
[Parameter(Mandatory=$true)][String]$Path,
[String]$Name,
[Object]$Data,
[Microsoft.Win32.RegistryValueKind]$Type
)
$key = $Hive.OpenSubKey($Path, $true)
try {
if ($null -eq $key) {
# the key does not exist, create it so the next steps work
if (-not $check_mode) {
try {
$key = $Hive.CreateSubKey($Path)
} catch {
Fail-Json -obj $result -message "failed to create registry key at $($PrintPath): $($_.Exception.Message)"
}
}
$result.changed = $true
if ($diff_mode) {
$result.diff.before = @{}
$result.diff.after = @{$PrintPath = @{}}
}
} elseif ($diff_mode) {
# Make sure the diff is in an expected state for the key
$result.diff.before = @{$PrintPath = @{}}
$result.diff.after = @{$PrintPath = @{}}
}
} else {
if ($existing -cne $new) {
$mismatch = $true
if ($null -eq $key -or $null -eq $Data) {
# Check mode and key was created above, we cannot do any more work, or $Data is $null which happens when
# we create a new key but haven't explicitly set the data
return
}
}
return $mismatch
}
$property = $key.GetValue($Name, $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
if ($null -ne $property) {
# property exists, need to compare the values and type
$existing_type = $key.GetValueKind($name)
$change_value = $false
Function Get-DiffValueString($type, $value) {
$enum = [Microsoft.Win32.RegistryValueKind]
if ($type -in @($enum::Binary, $enum::None)) {
$hex_values = @()
foreach ($dec_value in $value) {
$hex_values += "0x$("{0:x2}" -f $dec_value)"
if ($Type -ne $existing_type) {
$change_value = $true
$result.data_type_changed = $true
$data_mismatch = Compare-RegistryProperties -existing $property -new $Data
if ($data_mismatch) {
$result.data_changed = $true
}
} else {
$data_mismatch = Compare-RegistryProperties -existing $property -new $Data
if ($data_mismatch) {
$change_value = $true
$result.data_changed = $true
}
}
if ($change_value) {
if (-not $check_mode) {
try {
$key.SetValue($Name, $Data, $Type)
} catch {
Fail-Json -obj $result -message "failed to change registry property '$Name' at $($PrintPath): $($_.Exception.Message)"
}
}
$result.changed = $true
if ($diff_mode) {
$result.diff.before.$PrintPath.$Name = Get-DiffValue -Type $existing_type -Value $property
$result.diff.after.$PrintPath.$Name = Get-DiffValue -Type $Type -Value $Data
}
} elseif ($diff_mode) {
$diff_value = Get-DiffValue -Type $existing_type -Value $property
$result.diff.before.$PrintPath.$Name = $diff_value
$result.diff.after.$PrintPath.$Name = $diff_value
}
} else {
# property doesn't exist just create a new one
if (-not $check_mode) {
try {
$key.SetValue($Name, $Data, $Type)
} catch {
Fail-Json -obj $result -message "failed to create registry property '$Name' at $($PrintPath): $($_.Exception.Message)"
}
}
$result.changed = $true
if ($diff_mode) {
$result.diff.after.$PrintPath.$Name = Get-DiffValue -Type $Type -Value $Data
}
}
} finally {
if ($key) {
$key.Dispose()
}
$diff_value = "$($type):[$($hex_values -join ", ")]"
} elseif ($type -eq $enum::DWord) {
$diff_value = "$($type):0x$("{0:x8}" -f $value)"
} elseif ($type -eq $enum::QWord) {
$diff_value = "$($type):0x$("{0:x16}" -f $value)"
} elseif ($type -eq $enum::MultiString) {
$diff_value = "$($type):[$($value -join ", ")]"
} else {
$diff_value = "$($type):$value"
}
return $diff_value
}
# convert property names "" to $null as "" refers to (Default)
@ -213,7 +364,7 @@ if ($name -eq "") {
# convert the data to the required format
if ($type -in @("binary", "none")) {
if ($data -eq $null) {
if ($null -eq $data) {
$data = ""
}
@ -230,7 +381,7 @@ if ($type -in @("binary", "none")) {
}
} elseif ($type -in @("dword", "qword")) {
# dword's and dword's don't allow null values, set to 0
if ($data -eq $null) {
if ($null -eq $data) {
$data = 0
}
@ -260,14 +411,15 @@ if ($type -in @("binary", "none")) {
}
$data = [Int64]$data
}
} elseif ($type -in @("string", "expandstring")) {
} elseif ($type -in @("string", "expandstring") -and $name) {
# a null string or expandstring must be empty quotes
if ($data -eq $null) {
# Only do this if $name has been defined (not the default key)
if ($null -eq $data) {
$data = ""
}
} elseif ($type -eq "multistring") {
# convert the data for a multistring to a String[] array
if ($data -eq $null) {
if ($null -eq $data) {
$data = [String[]]@()
} elseif ($data -isnot [Array]) {
$new_data = New-Object -TypeName String[] -ArgumentList 1
@ -285,209 +437,59 @@ if ($type -in @("binary", "none")) {
# convert the type string to the .NET class
$type = [System.Enum]::Parse([Microsoft.Win32.RegistryValueKind], $type, $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"
}
$original_tmp = $env:TMP
$env:TMP = $_remote_tmp
Add-Type -TypeDefinition $registry_util
$env:TMP = $original_tmp
$registry_hive = switch(Split-Path -Path $path -Qualifier) {
"HKCR:" { [Microsoft.Win32.Registry]::ClassesRoot }
"HKCC:" { [Microsoft.Win32.Registry]::CurrentConfig }
"HKCU:" { [Microsoft.Win32.Registry]::CurrentUser }
"HKLM:" { [Microsoft.Win32.Registry]::LocalMachine }
"HKU" { [Microsoft.Win32.Registry]::Users }
}
$loaded_hive = $null
try {
if ($hive) {
if (-not (Test-Path -LiteralPath $hive)) {
Fail-Json -obj $result -message "hive at path '$hive' is not valid or accessible, cannot load hive"
}
try {
Set-AnsiblePrivilege -Name SeBackupPrivilege -Value $true
Set-AnsiblePrivilege -Name SeRestorePrivilege -Value $true
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to enable SeBackupPrivilege and SeRestorePrivilege for the current process: $($_.Exception.Message)"
}
$original_tmp = $env:TMP
$env:TMP = $_remote_tmp
Add-Type -TypeDefinition $registry_util
$env:TMP = $original_tmp
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.RegEdit.Hive]::UnloadHive("ANSIBLE")
Set-AnsiblePrivilege -Name SeBackupPrivilege -Value $true
Set-AnsiblePrivilege -Name SeRestorePrivilege -Value $true
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to unload registry hive HKLM:\ANSIBLE from $($hive): $($_.Exception.Message)"
Fail-Json -obj $result -message "failed to enable SeBackupPrivilege and SeRestorePrivilege for the current process: $($_.Exception.Message)"
}
}
try {
[Ansible.RegEdit.Hive]::LoadHive("ANSIBLE", $hive)
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to load registry hive from '$hive' to HKLM:\ANSIBLE: $($_.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
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 {
$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]
"@
[Ansible.WinRegedit.Hive]::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)
$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 {
$sub_key = $reg_key.OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree)
try {
$sub_key.SetValue($name, $data, $type)
} finally {
$sub_key.Close()
}
} 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 {
$sub_key = $reg_key.OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree)
try {
$sub_key.SetValue($name, $data, $type)
} finally {
$sub_key.Close()
}
} 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 $type -value $data)"
"@
}
try {
$loaded_hive = New-Object -TypeName Ansible.WinRegedit.Hive -ArgumentList "ANSIBLE", $hive
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to load registry hive from '$hive' to HKLM:\ANSIBLE: $($_.Exception.Message)"
}
}
if ($state -eq "present") {
Set-StatePresent -PrintPath $path -Hive $registry_hive -Path $registry_path -Name $name -Data $data -Type $type
} 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)
$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 {
$sub_key = $reg_key.OpenSubKey($null, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree)
try {
$sub_key.DeleteValue($name)
} finally {
$sub_key.Close()
}
} 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)"
"@
}
}
}
}
Set-StateAbsent -PrintPath $path -Hive $registry_hive -Path $registry_path -Name $name -DeleteKey:$delete_key
}
} finally {
if ($hive) {
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
try {
[Ansible.RegEdit.Hive]::UnloadHive("ANSIBLE")
} catch [System.ComponentModel.Win32Exception] {
Fail-Json -obj $result -message "failed to unload registry hive HKLM:\ANSIBLE from $($hive): $($_.Exception.Message)"
}
$registry_hive.Dispose()
if ($loaded_hive) {
$loaded_hive.Dispose()
}
}
Exit-Json $result

@ -0,0 +1,2 @@
---
test_reg_path: Test Key / [&Ansible*]

@ -1,24 +0,0 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Test]
[HKEY_CURRENT_USER\Test\nested]
"string"="test"
"binary"=hex:01,16
"dword"=dword:00000001
"qword"=hex(b):01,00,00,00,00,00,00,00
"multi"=hex(7):61,00,2c,00,20,00,62,00,00,00,63,00,00,00,00,00
"expand"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,64,00,69,\
00,72,00,00,00
[HKEY_CURRENT_USER\Test\nested\nest1]
"dontcare"=""
[HKEY_CURRENT_USER\Test\nested\nest2]
[HKEY_CURRENT_USER\Test\single]
"string1"=""
"string2"="abc123"
"none"=hex(0):
"none1"=hex(0):00

@ -1,322 +1,29 @@
---
- name: test
win_file:
path: "{{win_output_dir}}"
state: absent
- name: make sure win output dir exists
win_file:
path: "{{win_output_dir}}"
state: directory
- name: template out test registry structure
win_copy:
src: test_reg.reg
dest: "{{win_output_dir}}\\raw_test_reg.reg"
- name: convert the line endings to the windows variant
win_shell: Get-Content "{{win_output_dir}}\raw_test_reg.reg" | Set-Content "{{win_output_dir}}\test_reg.reg"
- name: import test registry structure
win_regmerge:
path: "{{win_output_dir}}\\test_reg.reg"
- name: get value of expand string %windir%
win_command: powershell.exe $env:windir
register: win_dir_value
- name: expect failure when not passing in path option
win_reg_stat:
name: a
register: actual
failed_when: "actual.msg != 'Get-AnsibleParam: Missing required argument: path'"
- name: expect failure when passing in an invalid hive
win_reg_stat:
path: ABCD:\test
register: actual
failed_when: actual.msg != "the hive in path is 'ABCD'; must be 'HKCR', 'HKCC', 'HKCU', 'HKLM' or 'HKU'"
- name: get known nested reg key structure for testing with short hive form
win_reg_stat:
path: HKCU:\Test\nested
register: actual_short
- name: get known nested reg key structure for testing with quoted yaml
win_reg_stat:
path: "HKCU:\\Test\\nested"
register: actual_quoted
- name: set expected value for reg structure
set_fact:
expected:
changed: false
exists: true
failed: false
properties:
binary: { raw_value: ["0x01", "0x16"], type: 'REG_BINARY', value: [1, 22] }
dword: { raw_value: 1, type: 'REG_DWORD', value: 1 }
expand: { raw_value: '%windir%\dir', type: 'REG_EXPAND_SZ', value: "{{win_dir_value.stdout_lines[0]}}\\dir" }
multi: { raw_value: ['a, b', 'c'], type: 'REG_MULTI_SZ', value: ['a, b', 'c'] }
qword: { raw_value: 1, type: 'REG_QWORD', value: 1 }
string: { raw_value: 'test', type: 'REG_SZ', value: 'test' }
sub_keys:
- nest1
- nest2
- name: validate test
assert:
that:
- "actual_short == expected"
- "actual_quoted == expected"
- name: get known reg key with no sub keys but some properties
win_reg_stat:
path: HKCU:\Test\single
register: actual
- name: set expected value for reg key with no sub keys but some properties
set_fact:
expected:
changed: false
exists: true
failed: false
properties:
none: { raw_value: [], type: 'REG_NONE', value: [] }
none1: { raw_value: ["0x00"], type: 'REG_NONE', value: [0] }
string1: { raw_value: '', type: 'REG_SZ', value: '' }
string2: { raw_value: 'abc123', type: 'REG_SZ', value: 'abc123' }
sub_keys: []
- name: validate test
assert:
that:
- "actual == expected"
- name: get known reg key without sub keys and properties
win_reg_stat:
path: HKCU:\Test\nested\nest2
register: actual
- name: set expected value for reg key without sub keys or properties
set_fact:
expected:
changed: false
exists: true
failed: false
properties: {}
sub_keys: []
register: expected
- name: validate test
assert:
that:
- "actual == expected"
- name: get non-existent reg key
win_reg_stat:
path: HKCU:\Test\Thispathwillneverexist
register: actual
- name: set expected value for non-existent reg key
set_fact:
expected:
changed: false
exists: false
failed: false
- name: validate test
assert:
that:
- "actual == expected"
- name: get string property
win_reg_stat:
path: HKCU:\Test\nested
name: string
register: actual
- name: set expected string property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: 'test'
type: 'REG_SZ'
value: 'test'
- name: validate test
assert:
that:
- "actual == expected"
- name: get expand string property
win_reg_stat:
path: HKCU:\Test\nested
name: expand
register: actual
- name: set expected expand string property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: '%windir%\dir'
type: 'REG_EXPAND_SZ'
value: "{{win_dir_value.stdout_lines[0]}}\\dir"
- name: validate test
assert:
that:
- "actual == expected"
- name: get multi string property
win_reg_stat:
path: HKCU:\Test\nested
name: multi
register: actual
- name: set expected multi string property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: ['a, b', 'c']
type: 'REG_MULTI_SZ'
value: ['a, b', 'c']
- name: validate test
assert:
that:
- "actual == expected"
- name: get binary property
win_reg_stat:
path: HKCU:\Test\nested
name: binary
register: actual
- name: set expected binary property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: ["0x01", "0x16"]
type: 'REG_BINARY'
value: [1, 22]
- name: validate test
assert:
that:
- "actual == expected"
- name: get dword property
win_reg_stat:
path: HKCU:\Test\nested
name: dword
register: actual
- name: set expected dword property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: 1
type: 'REG_DWORD'
value: 1
- name: validate test
assert:
that:
- "actual == expected"
- name: get qword property
win_reg_stat:
path: HKCU:\Test\nested
name: qword
register: actual
- name: set expected qword property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: 1
type: 'REG_QWORD'
value: 1
- name: validate test
assert:
that:
- "actual == expected"
- name: get none property
win_reg_stat:
path: HKCU:\Test\single
name: none
register: actual
- name: set expected none property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: []
type: 'REG_NONE'
value: []
- name: validate test
assert:
that:
- "actual == expected"
- name: get none with value property
win_reg_stat:
path: HKCU:\Test\single
name: none1
register: actual
- name: set expected none with value property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: ["0x00"]
type: 'REG_NONE'
value: [0]
- name: validate test
assert:
that:
- "actual == expected"
- name: get non-existence property
win_reg_stat:
path: HKCU:\Test\single
name: doesnotexist
register: actual
- name: set expected non-existence property
set_fact:
expected:
changed: false
exists: false
failed: false
- name: validate test
assert:
that:
- "actual == expected"
- name: template out test registry structure
win_template:
src: test_reg.reg.j2
dest: '{{ win_output_dir }}\test_reg.reg'
- name: remove registry entry
win_regedit:
path: HKCU:\Test
state: absent
- name: import test registry structure
win_regmerge:
path: '{{ win_output_dir }}\test_reg.reg'
- block:
- name: run tests
import_tasks: tests.yml
always:
- name: remove test registry key
win_regedit:
path: HKCU:\{{ test_reg_path }}
state: absent
delete_key: True
- name: remove template registry file
win_file:
path: '{{ win_output_dir }}\test_reg.reg'
state: absent

@ -0,0 +1,364 @@
---
- name: expect failure when not passing in path option
win_reg_stat:
name: a
register: actual
failed_when: "actual.msg != 'Get-AnsibleParam: Missing required argument: path'"
- name: expect failure when passing in an invalid hive
win_reg_stat:
path: ABCD:\test
register: actual
failed_when: 'actual.msg != "path: ABCD:\\test is not a valid registry path, see module documentation for examples."'
- name: get known nested reg key structure
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
register: actual
- name: set expected value for reg structure
set_fact:
expected:
changed: false
exists: true
failed: false
properties:
binary: { raw_value: ["0x01", "0x16"], type: 'REG_BINARY', value: [1, 22] }
dword: { raw_value: 1, type: 'REG_DWORD', value: 1 }
expand: { raw_value: '%windir%\dir', type: 'REG_EXPAND_SZ', value: "{{win_dir_value.stdout_lines[0]}}\\dir" }
large_dword: { raw_value: 4294967295, type: 'REG_DWORD', value: 4294967295 }
large_qword: { raw_value: 18446744073709551615, type: 'REG_QWORD', value: 18446744073709551615 }
multi: { raw_value: ['a, b', 'c'], type: 'REG_MULTI_SZ', value: ['a, b', 'c'] }
qword: { raw_value: 1, type: 'REG_QWORD', value: 1 }
string: { raw_value: 'test', type: 'REG_SZ', value: 'test' }
sub_keys:
- nest1
- nest2
- name: assert get known nested reg key structure
assert:
that:
- actual == expected
- name: get known reg key with no sub keys but some properties
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\single
register: actual
- name: set expected value for reg key with no sub keys but some properties
set_fact:
expected:
changed: false
exists: true
failed: false
properties:
none: { raw_value: [], type: 'REG_NONE', value: [] }
none1: { raw_value: ["0x00"], type: 'REG_NONE', value: [0] }
string1: { raw_value: '', type: 'REG_SZ', value: '' }
string2: { raw_value: 'abc123', type: 'REG_SZ', value: 'abc123' }
sub_keys: []
- name: assert get known reg key with no sub keys but some properties
assert:
that:
- actual == expected
- name: get known reg key without sub keys and properties
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested\nest2
register: actual
- name: set expected value for reg key without sub keys or properties
set_fact:
expected:
changed: false
exists: true
failed: false
properties: {}
sub_keys: []
register: expected
- name: assert get known reg key without sub keys and properties
assert:
that:
- actual == expected
- name: get non-existent reg key
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Thispathwillneverexist
register: actual
- name: set expected value for non-existent reg key
set_fact:
expected:
changed: false
exists: false
failed: false
- name: assert get non-existent reg key
assert:
that:
- actual == expected
- name: get string property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
name: string
register: actual
- name: set expected string property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: 'test'
type: 'REG_SZ'
value: 'test'
- name: assert get string property
assert:
that:
- actual == expected
- name: get expand string property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
name: expand
register: actual
- name: set expected expand string property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: '%windir%\dir'
type: 'REG_EXPAND_SZ'
value: "{{win_dir_value.stdout_lines[0]}}\\dir"
- name: assert get expand string property
assert:
that:
- actual == expected
- name: get multi string property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
name: multi
register: actual
- name: set expected multi string property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: ['a, b', 'c']
type: 'REG_MULTI_SZ'
value: ['a, b', 'c']
- name: assert get multi string property
assert:
that:
- actual == expected
- name: get binary property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
name: binary
register: actual
- name: set expected binary property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: ["0x01", "0x16"]
type: 'REG_BINARY'
value: [1, 22]
- name: assert get binary property
assert:
that:
- actual == expected
- name: get dword property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
name: dword
register: actual
- name: set expected dword property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: 1
type: 'REG_DWORD'
value: 1
- name: assert get dword property
assert:
that:
- actual == expected
- name: get qword property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\nested
name: qword
register: actual
- name: set expected qword property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: 1
type: 'REG_QWORD'
value: 1
- name: assert get qword property
assert:
that:
- actual == expected
- name: get none property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\single
name: none
register: actual
- name: set expected none property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: []
type: 'REG_NONE'
value: []
- name: assert get none property
assert:
that:
- actual == expected
- name: get none with value property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\single
name: none1
register: actual
- name: set expected none with value property
set_fact:
expected:
changed: false
exists: true
failed: false
raw_value: ["0x00"]
type: 'REG_NONE'
value: [0]
- name: assert get non with value property
assert:
that:
- actual == expected
- name: get non-existent property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\single
name: doesnotexist
register: actual
- name: set expected non-existent property
set_fact:
expected:
changed: false
exists: false
failed: false
- name: assert get non-existent property
assert:
that:
- actual == expected
- name: get key with default property set
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Duplicate Default
register: actual
- name: assert get key with default property set
assert:
that:
- actual.properties[""]['raw_value'] == "default"
- actual.properties[""]['type'] == "REG_SZ"
- actual.properties[""]['value'] == "default"
- actual.properties['(Default)'].raw_value == "custom"
- actual.properties['(Default)'].type == "REG_SZ"
- actual.properties['(Default)'].value == "custom"
- name: get default property
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Duplicate Default
name: ''
register: actual
- name: assert get default property
assert:
that:
- actual.value == "default"
- actual.raw_value == "default"
- actual.type == "REG_SZ"
- name: get key with blank property set
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Blank Default
register: actual
- name: assert get key with blank property set
assert:
that:
- actual.properties[""].raw_value == ""
- actual.properties[""].type == "REG_SZ"
- actual.properties[""].value == ""
- actual.properties['(Default)'].raw_value == ""
- actual.properties['(Default)'].type == "REG_SZ"
- actual.properties['(Default)'].value == ""
- name: get default property as empty string
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Blank Default
name: ''
register: actual
- name: assert get default property as empty string
assert:
that:
- actual.value == ""
- actual.raw_value == ""
- actual.type == "REG_SZ"
- name: get key with no properties set
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Empty Default
register: actual
- name: assert get key with no properties set
assert:
that:
- actual.properties == {}
- name: get default property that has not been set
win_reg_stat:
path: HKCU:\{{ test_reg_path }}\Empty Default
name: ''
register: actual
- name: assert get default property that has not been set
assert:
that:
- not actual.exists

@ -0,0 +1,37 @@
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\{{ test_reg_path }}]
[HKEY_CURRENT_USER\{{ test_reg_path }}\nested]
"string"="test"
"binary"=hex:01,16
"dword"=dword:00000001
"qword"=hex(b):01,00,00,00,00,00,00,00
"large_dword"=dword:ffffffff
"large_qword"=hex(b):ff,ff,ff,ff,ff,ff,ff,ff
"multi"=hex(7):61,00,2c,00,20,00,62,00,00,00,63,00,00,00,00,00
"expand"=hex(2):25,00,77,00,69,00,6e,00,64,00,69,00,72,00,25,00,5c,00,64,00,69,\
00,72,00,00,00
[HKEY_CURRENT_USER\{{ test_reg_path }}\nested\nest1]
"dontcare"=""
[HKEY_CURRENT_USER\{{ test_reg_path }}\nested\nest2]
[HKEY_CURRENT_USER\{{ test_reg_path }}\single]
"string1"=""
"string2"="abc123"
"none"=hex(0):
"none1"=hex(0):00
[HKEY_CURRENT_USER\{{ test_reg_path }}\Empty Default]
[HKEY_CURRENT_USER\{{ test_reg_path }}\Blank Default]
@=""
"(Default)"=""
[HKEY_CURRENT_USER\{{ test_reg_path }}\Duplicate Default]
@="default"
"(Default)"="custom"

@ -1,3 +1,3 @@
test_win_regedit_local_key: HKLM:\Software\Cow Corp
test_win_regedit_local_key: 'HKLM:\Software\Moo []{}!@#$%^&*()-_=+/key''"?<>'
test_win_regedit_classes_key: HKCR:\.test-ansible
test_win_regedit_hive_key: HKLM:\ANSIBLE\NewKey

@ -131,14 +131,6 @@
- data_create_actual.type == test_win_regedit_key_expected_type
when: test_win_regedit_key_type not in ['dword', 'qword']
- name: debug 1
debug:
var: test_win_regedit_key_expected_value1
- name: debug 2
debug:
var: test_win_regedit_key_expected_value1|int
- name: assert create a {{test_win_regedit_key_type}} for dword or qword
assert:
that:

@ -1,4 +1,17 @@
---
- name: check warning is fired if path with / as separators is used
win_regedit:
path: HKLM:\SOFTWARE/Microsoft
state: present
register: forward_separator_warn
- name: assert warning is fired if / is used as a separator
assert:
that:
- forward_separator_warn.deprecations|length == 1
- forward_separator_warn.deprecations[0].msg == "path is not using '\\' as a separator, support for '/' as a separator will be removed in a future Ansible version"
- forward_separator_warn.deprecations[0].version == 2.12
- name: fail run win_regedit with larger dword
win_regedit:
path: '{{test_win_regedit_local_key}}'
@ -82,16 +95,17 @@
register: modify_default_check
check_mode: yes
# win_reg_stat struggles with the (Default) property just use powershell
- name: get actual modify the (Default) key property check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
name: ''
register: modify_default_actual_check
- name: assert modify the (Default) key property check
assert:
that:
- modify_default_check is changed
- modify_default_actual_check.stdout == ""
- not modify_default_actual_check.exists
- name: modify the (Default) key property
win_regedit:
@ -101,14 +115,16 @@
register: modify_default
- name: get actual modify the (Default) key property
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
name: ''
register: modify_default_actual
- name: assert modify the (Default) key property
assert:
that:
- modify_default is changed
- modify_default_actual.stdout == "default value\r\n"
- modify_default_actual.value == "default value"
- name: create an actual property called (Default)
win_regedit:
@ -120,20 +136,17 @@
register: create_specific_default_check
check_mode: yes
- name: get actual value for (Default) property to ensure it didn't change check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
register: create_specific_default_actual_default_check
- name: get actual for create specific property called (Default) check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue('(Default)', $null)"
- name: get actual value for (Default) property
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
register: create_specific_default_actual_check
- name: assert create specific property called (Default) check
assert:
that:
- create_specific_default_check is changed
- create_specific_default_actual_default_check.stdout == "default value\r\n"
- create_specific_default_actual_check.stdout == ""
- create_specific_default_actual_check.properties[""].value == "default value"
- not "(Default)" in create_specific_default_actual_check.properties
- name: create an actual property called (Default)
win_regedit:
@ -144,20 +157,17 @@
state: present
register: create_specific_default
- name: get actual value for (Default) property to ensure it didn't change
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
register: create_specific_default_actual_default
- name: get actual for specific property called (Default)
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue('(Default)', $null)"
- name: get actual value for (Default) property
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
register: create_specific_default_actual
- name: assert create specific property called (Default)
assert:
that:
- create_specific_default is changed
- create_specific_default_actual_default.stdout == "default value\r\n"
- create_specific_default_actual.stdout == "custom default value\r\n"
- create_specific_default_actual.properties[""].value == "default value"
- create_specific_default_actual.properties["(Default)"].value == "custom default value"
- name: delete property check
win_regedit:
@ -219,19 +229,16 @@
check_mode: yes
- name: get actual of key's (Default) property check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
register: delete_default_actual_check
- name: get actual of custom (Default) property check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue('(Default)', $null)"
register: delete_default_custom_actual_check
- name: assert delete the key's (Default) property check
assert:
that:
- delete_default_check is changed
- delete_default_actual_check.stdout == "default value\r\n"
- delete_default_custom_actual_check.stdout == "custom default value\r\n"
- delete_default_actual_check.properties[""].value == "default value"
- delete_default_actual_check.properties["(Default)"].value == "custom default value"
- name: delete the key's (Default) property
win_regedit:
@ -241,19 +248,16 @@
register: delete_default
- name: get actual of key's (Default) property
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
register: delete_default_actual
- name: get actual of custom (Default) property
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue('(Default)', $null)"
register: delete_default_custom_actual
- name: assert delete the key's (Default) property
assert:
that:
- delete_default is changed
- delete_default_actual.stdout == ""
- delete_default_custom_actual.stdout == "custom default value\r\n"
- not "" in delete_default_actual.properties
- delete_default_actual.properties["(Default)"].value == "custom default value"
- name: recreate the key's (Default) property for next test
win_regedit:
@ -270,19 +274,16 @@
check_mode: yes
- name: get actual of key's (Default) property check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
register: delete_custom_default_actual_check
- name: get actual of custom (Default) property check
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue('(Default)', $null)"
register: delete_custom_default_custom_actual_check
- name: assert delete the custom (Default) property check
assert:
that:
- delete_custom_default_check is changed
- delete_custom_default_actual_check.stdout == "default value\r\n"
- delete_custom_default_custom_actual_check.stdout == "custom default value\r\n"
- delete_custom_default_actual_check.properties[""].value == "default value"
- delete_custom_default_actual_check.properties["(Default)"].value == "custom default value"
- name: delete the custom (Default) property
win_regedit:
@ -293,19 +294,16 @@
register: delete_custom_default
- name: get actual of key's (Default) property
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue($null, $null)"
win_reg_stat:
path: '{{ test_win_regedit_local_key }}'
register: delete_custom_default_actual
- name: get actual of custom (Default) property
win_command: powershell.exe "(Get-Item -Path '{{test_win_regedit_local_key}}').GetValue('(Default)', $null)"
register: delete_custom_default_custom_actual
- name: assert delete the custom (Default) property
assert:
that:
- delete_custom_default is changed
- delete_custom_default_actual.stdout == "default value\r\n"
- delete_custom_default_custom_actual.stdout == ""
- delete_custom_default_actual.properties[""].value == "default value"
- not "(Default)" in delete_custom_default_actual.properties
- name: add some nested keys for later deletion
win_regedit:
@ -366,6 +364,26 @@
that:
- delete_key_again is not changed
- name: create a new key without specifying the property
win_regedit:
path: '{{ test_win_regedit_local_key }}\new'
state: present
register: create_key_no_prop
- name: get result of create a new key without specifying the property
win_reg_stat:
path: '{{ test_win_regedit_local_key }}\new'
register: create_key_no_prop_actual
- name: assert create a new key without specifying the property
assert:
that:
- create_key_no_prop is changed
- not create_key_no_prop.data_changed
- not create_key_no_prop.data_type_changed
- create_key_no_prop_actual.exists
- create_key_no_prop_actual.properties == {}
- name: create key in HKEY_CLASSES_ROOT check
win_regedit:
path: '{{test_win_regedit_classes_key}}'

Loading…
Cancel
Save