2015-06-25 18:18:57 +00:00
#!powershell
2017-10-17 20:30:33 +00:00
2018-07-17 21:29:05 +00:00
# Copyright: (c) 2015, Adam Keech <akeech@chathamfinancial.com>
# Copyright: (c) 2015, Josh Ludwig <jludwig@chathamfinancial.com>
# Copyright: (c) 2017, Jordan Borean <jborean93@gmail.com>
2017-10-17 20:30:33 +00:00
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
2017-10-23 18:40:54 +00:00
# Requires -Module Ansible.ModuleUtils.Legacy
2018-07-30 21:48:54 +00:00
# Requires -Module Ansible.ModuleUtils.PrivilegeUtil
2015-06-25 18:18:57 +00:00
2017-07-14 16:28:49 +00:00
$params = Parse-Args -arguments $args -supports_check_mode $true
2017-01-24 13:58:40 +00:00
$check_mode = Get-AnsibleParam -obj $params -name " _ansible_check_mode " -type " bool " -default $false
2017-07-14 16:28:49 +00:00
$diff_mode = Get-AnsibleParam -obj $params -name " _ansible_diff " -type " bool " -default $false
2018-05-22 21:12:32 +00:00
$_remote_tmp = Get-AnsibleParam $params " _ansible_remote_tmp " -type " path " -default $env:TMP
2016-02-09 06:42:02 +00:00
2017-07-14 16:28:49 +00:00
$path = Get-AnsibleParam -obj $params -name " path " -type " str " -failifempty $true -aliases " key "
$name = Get-AnsibleParam -obj $params -name " name " -type " str " -aliases " entry " , " value "
2017-01-24 13:58:40 +00:00
$data = Get-AnsibleParam -obj $params -name " data "
2017-07-14 16:28:49 +00:00
$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
2017-10-17 20:30:33 +00:00
$hive = Get-AnsibleParam -obj $params -name " hive " -type " path "
2015-06-25 18:18:57 +00:00
2017-01-24 13:58:40 +00:00
$result = @ {
changed = $false
data_changed = $false
data_type_changed = $false
2017-02-24 07:22:39 +00:00
}
2017-07-14 16:28:49 +00:00
if ( $diff_mode ) {
2017-02-24 07:22:39 +00:00
$result . diff = @ {
2019-03-07 19:41:52 +00:00
before = " "
after = " "
2017-01-24 13:58:40 +00:00
}
}
2015-07-06 19:25:01 +00:00
2017-10-17 20:30:33 +00:00
$registry_util = @ '
using System ;
using System . Collections . Generic ;
using System . Runtime . InteropServices ;
2019-03-07 19:41:52 +00:00
namespace Ansible . WinRegedit
2017-10-17 20:30:33 +00:00
{
2019-03-07 19:41:52 +00:00
internal class NativeMethods
2017-10-17 20:30:33 +00:00
{
2019-03-07 19:41:52 +00:00
[ 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 ) ;
2017-10-17 20:30:33 +00:00
}
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 ) ; }
}
2019-03-07 19:41:52 +00:00
public class Hive : IDisposable
2017-10-17 20:30:33 +00:00
{
2019-03-07 19:41:52 +00:00
private const UInt32 SCOPE = 0x80000002 ; / / HKLM
private string hiveKey ;
private bool loaded = false ;
2017-10-17 20:30:33 +00:00
2019-03-07 19:41:52 +00:00
public Hive ( string hiveKey , string hivePath )
2017-10-17 20:30:33 +00:00
{
2019-03-07 19:41:52 +00:00
this . hiveKey = hiveKey ;
int ret = NativeMethods . RegLoadKeyW ( SCOPE , hiveKey , hivePath ) ;
2017-10-17 20:30:33 +00:00
if ( ret ! = 0 )
2019-03-07 19:41:52 +00:00
throw new Win32Exception ( ret , String . Format ( " Failed to load registry hive at {0} " , hivePath ) ) ;
loaded = true ;
2017-10-17 20:30:33 +00:00
}
2019-03-07 19:41:52 +00:00
public static void UnloadHive ( string hiveKey )
2017-10-17 20:30:33 +00:00
{
2019-03-07 19:41:52 +00:00
int ret = NativeMethods . RegUnLoadKeyW ( SCOPE , hiveKey ) ;
2017-10-17 20:30:33 +00:00
if ( ret ! = 0 )
2019-03-07 19:41:52 +00:00
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 ) ;
2017-10-17 20:30:33 +00:00
}
2019-03-07 19:41:52 +00:00
~ Hive ( ) { this . Dispose ( ) ; }
2017-10-17 20:30:33 +00:00
}
}
' @
2017-07-14 16:28:49 +00:00
# fire a warning if the property name isn't specified, the (Default) key ($null) can only be a string
2019-03-07 19:41:52 +00:00
if ( $null -eq $name -and $type -ne " string " ) {
2017-07-14 16:28:49 +00:00
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 "
}
2017-01-24 13:58:40 +00:00
# Check that the registry path is in PSDrive format: HKCC, HKCR, HKCU, HKLM, HKU
2017-07-14 16:28:49 +00:00
if ( $path -notmatch " ^HK(CC|CR|CU|LM|U):\\ " ) {
2017-01-24 13:58:40 +00:00
Fail-Json $result " path: $path is not a valid powershell path, see module documentation for examples. "
2015-06-25 18:18:57 +00:00
}
2019-03-07 19:41:52 +00:00
# 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 ( '/' , '\' )
2016-04-14 20:22:10 +00:00
}
2016-04-07 17:22:23 +00:00
# Simplified version of Convert-HexStringToByteArray from
# https://cyber-defense.sans.org/blog/2010/02/11/powershell-byte-array-hex-convert
# Expects a hex in the format you get when you run reg.exe export,
# and converts to a byte array so powershell can modify binary registry entries
2017-07-14 16:28:49 +00:00
# import format is like 'hex:be,ef,be,ef,be,ef,be,ef,be,ef'
Function Convert-RegExportHexStringToByteArray($string ) {
2017-01-24 13:58:40 +00:00
# Remove 'hex:' from the front of the string if present
2017-07-14 16:28:49 +00:00
$string = $string . ToLower ( ) -replace '^hex\:' , ''
2016-04-07 17:22:23 +00:00
2017-01-24 13:58:40 +00:00
# Remove whitespace and any other non-hex crud.
2017-07-14 16:28:49 +00:00
$string = $string -replace '[^a-f0-9\\,x\-\:]' , ''
2016-04-07 17:22:23 +00:00
2017-01-24 13:58:40 +00:00
# Turn commas into colons
2017-07-14 16:28:49 +00:00
$string = $string -replace ',' , ':'
2016-04-07 17:22:23 +00:00
2017-01-24 13:58:40 +00:00
# Maybe there's nothing left over to convert...
2017-07-14 16:28:49 +00:00
if ( $string . Length -eq 0 ) {
2017-01-24 13:58:40 +00:00
return , @ ( )
}
2016-04-07 17:22:23 +00:00
2017-01-24 13:58:40 +00:00
# Split string with or without colon delimiters.
2017-07-14 16:28:49 +00:00
if ( $string . Length -eq 1 ) {
return , @ ( [ System.Convert ] :: ToByte ( $string , 16 ) )
} elseif ( ( $string . Length % 2 -eq 0 ) -and ( $string . IndexOf ( " : " ) -eq -1 ) ) {
return , @ ( $string -split '([a-f0-9]{2})' | foreach-object { if ( $_ ) { [ System.Convert ] :: ToByte ( $_ , 16 ) } } )
} elseif ( $string . IndexOf ( " : " ) -ne -1 ) {
return , @ ( $string -split ':+' | foreach-object { [ System.Convert ] :: ToByte ( $_ , 16 ) } )
2017-01-24 13:58:40 +00:00
} else {
return , @ ( )
}
}
2016-04-07 17:22:23 +00:00
2019-03-07 19:41:52 +00:00
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
}
2017-07-14 16:28:49 +00:00
try {
2019-03-07 19:41:52 +00:00
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 = @ { }
}
2017-07-14 16:28:49 +00:00
} else {
2019-03-07 19:41:52 +00:00
# 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 = @ { } }
}
2017-07-14 16:28:49 +00:00
}
2017-10-17 20:30:33 +00:00
} finally {
2019-03-07 19:41:52 +00:00
if ( $key ) {
$key . Dispose ( )
2017-10-17 20:30:33 +00:00
}
2017-07-14 16:28:49 +00:00
}
2016-04-07 17:22:23 +00:00
}
2019-03-07 19:41:52 +00:00
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 = @ { } }
2017-07-14 16:28:49 +00:00
}
2019-03-07 19:41:52 +00:00
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
2017-07-14 16:28:49 +00:00
}
2017-01-26 15:26:56 +00:00
2019-03-07 19:41:52 +00:00
$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
2016-04-07 17:22:23 +00:00
2019-03-07 19:41:52 +00:00
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 ( )
2017-09-07 06:14:49 +00:00
}
}
}
2017-07-14 16:28:49 +00:00
# convert property names "" to $null as "" refers to (Default)
if ( $name -eq " " ) {
$name = $null
2017-01-24 13:58:40 +00:00
}
2017-07-14 16:28:49 +00:00
# convert the data to the required format
if ( $type -in @ ( " binary " , " none " ) ) {
2019-03-07 19:41:52 +00:00
if ( $null -eq $data ) {
2017-07-14 16:28:49 +00:00
$data = " "
}
2017-01-25 19:40:57 +00:00
2017-07-14 16:28:49 +00:00
# convert the data from string to byte array if in hex: format
if ( $data -is [ String ] ) {
$data = [ byte[] ] ( Convert-RegExportHexStringToByteArray -string $data )
} elseif ( $data -is [ Int ] ) {
if ( $data -gt 255 ) {
Fail-Json $result " cannot convert binary data ' $data ' to byte array, please specify this value as a yaml byte array or a comma separated hex value string "
}
$data = [ byte[] ] @ ( [ byte ] $data )
} elseif ( $data -is [ Array ] ) {
$data = [ byte[] ] $data
}
} elseif ( $type -in @ ( " dword " , " qword " ) ) {
# dword's and dword's don't allow null values, set to 0
2019-03-07 19:41:52 +00:00
if ( $null -eq $data ) {
2017-07-14 16:28:49 +00:00
$data = 0
}
2017-01-24 13:58:40 +00:00
2017-07-14 16:28:49 +00:00
if ( $data -is [ String ] ) {
# if the data is a string we need to convert it to an unsigned int64
# it needs to be unsigned as Ansible passes in an unsigned value while
# powershell uses a signed data type. The value will then be converted
# below
$data = [ UInt64 ] $data
}
2017-01-24 13:58:40 +00:00
2017-07-14 16:28:49 +00:00
if ( $type -eq " dword " ) {
if ( $data -gt [ UInt32 ] :: MaxValue ) {
Fail-Json $result " data cannot be larger than 0xffffffff when type is dword "
} elseif ( $data -gt [ Int32 ] :: MaxValue ) {
# when dealing with larger int32 (> 2147483647 or 0x7FFFFFFF) powershell
# automatically converts it to a signed int64. We need to convert this to
# signed int32 by parsing the hex string value.
$data = " 0x $( " {0:x} " -f $data ) "
}
$data = [ Int32 ] $data
} else {
if ( $data -gt [ UInt64 ] :: MaxValue ) {
Fail-Json $result " data cannot be larger than 0xffffffffffffffff when type is qword "
} elseif ( $data -gt [ Int64 ] :: MaxValue ) {
$data = " 0x $( " {0:x} " -f $data ) "
}
$data = [ Int64 ] $data
}
2019-03-07 19:41:52 +00:00
} elseif ( $type -in @ ( " string " , " expandstring " ) -and $name ) {
2017-07-14 16:28:49 +00:00
# a null string or expandstring must be empty quotes
2019-03-07 19:41:52 +00:00
# Only do this if $name has been defined (not the default key)
if ( $null -eq $data ) {
2017-07-14 16:28:49 +00:00
$data = " "
}
} elseif ( $type -eq " multistring " ) {
# convert the data for a multistring to a String[] array
2019-03-07 19:41:52 +00:00
if ( $null -eq $data ) {
2017-07-14 16:28:49 +00:00
$data = [ String[] ] @ ( )
} elseif ( $data -isnot [ Array ] ) {
$new_data = New-Object -TypeName String [ ] -ArgumentList 1
$new_data [ 0 ] = $data . ToString ( [ CultureInfo ] :: InvariantCulture )
$data = $new_data
} else {
$new_data = New-Object -TypeName String [ ] -ArgumentList $data . Count
foreach ( $entry in $data ) {
$new_data [ $data . IndexOf ( $entry ) ] = $entry . ToString ( [ CultureInfo ] :: InvariantCulture )
}
$data = $new_data
}
}
2017-01-24 13:58:40 +00:00
2017-07-14 16:28:49 +00:00
# convert the type string to the .NET class
$type = [ System.Enum ] :: Parse ( [ Microsoft.Win32.RegistryValueKind ] , $type , $true )
2015-12-19 21:57:13 +00:00
2019-03-07 19:41:52 +00:00
$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 }
2019-03-26 20:30:05 +00:00
" HKU: " { [ Microsoft.Win32.Registry ] :: Users }
2019-03-07 19:41:52 +00:00
}
$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 "
}
2018-07-30 21:48:54 +00:00
2019-03-07 19:41:52 +00:00
$original_tmp = $env:TMP
$env:TMP = $_remote_tmp
Add-Type -TypeDefinition $registry_util
$env:TMP = $original_tmp
2017-10-17 20:30:33 +00:00
2017-07-14 16:28:49 +00:00
try {
2019-03-07 19:41:52 +00:00
Set-AnsiblePrivilege -Name SeBackupPrivilege -Value $true
Set-AnsiblePrivilege -Name SeRestorePrivilege -Value $true
2017-10-17 20:30:33 +00:00
} catch [ System.ComponentModel.Win32Exception ] {
2019-03-07 19:41:52 +00:00
Fail-Json -obj $result -message " failed to enable SeBackupPrivilege and SeRestorePrivilege for the current process: $( $_ . Exception . Message ) "
2017-07-14 16:28:49 +00:00
}
2017-02-24 07:22:39 +00:00
2019-03-07 19:41:52 +00:00
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 "
2017-10-17 20:30:33 +00:00
try {
2019-03-07 19:41:52 +00:00
[ 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 ) "
2017-07-14 16:28:49 +00:00
}
}
2019-03-07 19:41:52 +00:00
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 ) "
2015-06-25 18:18:57 +00:00
}
2019-03-07 19:41:52 +00:00
}
if ( $state -eq " present " ) {
Set-StatePresent -PrintPath $path -Hive $registry_hive -Path $registry_path -Name $name -Data $data -Type $type
2017-07-14 16:28:49 +00:00
} else {
2019-03-07 19:41:52 +00:00
Set-StateAbsent -PrintPath $path -Hive $registry_hive -Path $registry_path -Name $name -DeleteKey: $delete_key
2015-06-25 18:18:57 +00:00
}
2017-10-17 20:30:33 +00:00
} finally {
2019-03-07 19:41:52 +00:00
$registry_hive . Dispose ( )
if ( $loaded_hive ) {
$loaded_hive . Dispose ( )
2017-10-17 20:30:33 +00:00
}
2015-06-25 18:18:57 +00:00
}
Exit-Json $result
2019-03-07 19:41:52 +00:00