Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

win reg - Support special chars in path #53305

Merged
merged 2 commits into from
Mar 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelogs/fragments/win_registry.yaml
Original file line number Diff line number Diff line change
@@ -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
172 changes: 81 additions & 91 deletions lib/ansible/modules/windows/win_reg_stat.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you're missing the colon after HKU here...

}

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

17 changes: 16 additions & 1 deletion lib/ansible/modules/windows/win_reg_stat.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@
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
Expand All @@ -49,6 +53,12 @@
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'''
Expand All @@ -67,6 +77,11 @@
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",
Expand All @@ -77,7 +92,7 @@
"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
Expand Down