2

I'm attempting to programmatically change the owner of a registry key but I can't get it to work using a few different methods in CMD or PowerShell. Is this even possible?

The key is owned by "System". I need to delete it on a bunch of computers. I am able to successfully do this manually by doing the following:

  1. Open Key permissions > Advanced
  2. Change owner to myself
  3. Add a permission entry to give myself full control
  4. Select "replace owner of subcontainers and objects" and select "Replace all child object permission entries with interitable permission entries from this object".
  5. Delete the key

But doing this through a script does not work. I get an error at the first step of taking ownership that the "Access is denied" or something similar. Here are some of the methods I have tried:

CMD1:

reg add "HKEY_LOCAL_MACHINE\Path_To_Key\Key_Name" /f /t REG_SZ /d username /reg:64
ERROR: Access is denied.

CMD2:

takeown /f "HKEY_LOCAL_MACHINE\Path_To_Key\Key_Name"
ERROR: The system cannot find the path specified.

PS1:

$keyPath = "HKEY_LOCAL_MACHINE\SYSTEM\Path_To_Key\Key_Name"
$username = "username"
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$acl = $key.GetAccessControl()
$acl.SetOwner([System.Security.Principal.NTAccount] $username)
$key.SetAccessControl($acl)
$key.Close()

You cannot call a method on a null-valued expression.
At line:1 char:1
+ $acl = $key.GetAccessControl()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

PS2:

$keyPath = "HKLM:\SYSTEM\Path_To_Key\Key_Name"
$owner = "YOUR_USERNAME"    
# Take ownership
$key = [Microsoft.Win32.Registry]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64).OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$acl = $key.GetAccessControl()
$acl.SetOwner([System.Security.Principal.NTAccount] $owner)
[Microsoft.Win32.Registry]::SetAccessControl($keyPath, $acl)

Method invocation failed because [Microsoft.Win32.Registry] does not contain a method named 'OpenBaseKey'.
At line:5 char:1
+ $regKey = [Microsoft.Win32.Registry]::OpenBaseKey([Microsoft.Win32.Re ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

I have also looked at a few other options, including this suggestion but also got the error "You cannot call a method on a null-valued expression".

Additionally, I have tried deleting the key using a desktop management system, which I can launch command prompt as nt authority\system but I still get an error when deleting the key ERROR: Access is denied.

I imagine since I can do this manually with my admin account, there must be a way to do it through a script. Any thoughts would be greatly appreciated!

2 Answers 2

0

Take ownership of a registry key via PowerShell

I've encountered a similar situation in the past and can offer a solution that worked for me, tailored to better suit your specific requirements with error handling for suppression.

This code consists of two functions, followed by a function call that takes the desired registry path value, excluding the initial HKLM hive notation, as an argument taking ownership of the key.

PowerShell Enable-Privilege Function

Function Enable-Privilege {
    param ([string[]]$Privileges)
    try {
        $typeExists = [AppDomain]::CurrentDomain.GetAssemblies() | ForEach-Object {$_.GetExportedTypes() | Where-Object { $_.Name -eq "AdjPriv" }};
        if ($typeExists -eq $null) {
        $Definition = @"
        using System;
        using System.Runtime.InteropServices;
        
        public class AdjPriv
        {
            [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
            internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr rele);      
            [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
            internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);           
            [DllImport("advapi32.dll", SetLastError = true)]
            internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);        
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            internal struct TokPriv1Luid
            {
                public int Count;
                public long Luid;
                public int Attr;
            }        
            internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
            internal const int TOKEN_QUERY = 0x00000008;
            internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;        
            public static bool EnablePrivilege(long processHandle, string privilege)
            {
                bool retVal;
                TokPriv1Luid tp;
                IntPtr hproc = new IntPtr(processHandle);
                IntPtr htok = IntPtr.Zero;        
                retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
                tp.Count = 1;
                tp.Luid = 0;
                tp.Attr = SE_PRIVILEGE_ENABLED;
                retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
                retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);       
                return retVal;
            }
        }
"@            
        $ProcessHandle = (Get-Process -id $pid).Handle;
        $type = Add-Type $definition -PassThru};
        $Privileges | ForEach-Object {If($_){Try{$type[0]::EnablePrivilege($processHandle, $_)}Catch{$False}}
        }
        }catch{}
        };

PowerShell TakeOwnership-RegistryKey Function

Note: This has HKLM level logic hard-coded into it so it's HKLM specific.

Function TakeOwnership-RegistryKey {
    param ([string]$RegistryPath)
    Enable-Privilege @("SeTakeOwnershipPrivilege", "SeRestorePrivilege")
    $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($RegistryPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
    if ($key -eq $null) {
        Write-Host "Registry key not found: $RegistryPath";
        return;
        }
    $acl = $key.GetAccessControl();
    $owner = [System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME";
    $acl.SetOwner($owner);
    $key.SetAccessControl($acl);
    Write-Host "Ownership of registry key '$RegistryPath' has been taken by $env:USERNAME" -ForegroundColor Yellow;
};

Execute

Note: You will not append HKLM to the value passed to the function here—omit it.

TakeOwnership-RegistryKey "SOFTWARE\Test";

Supporting Resources

7
  • Tried a few things with this suggestion. Keep getting the error "You cannot call a method on a null-valued expression" when it executes "$acl = $key.GetAccessControl();". I created a new key called test just to test if it isn't some other problem. So I used TakeRegKeyOwnership "HKLM:\SOFTWARE\Test"; Commented Oct 27, 2023 at 12:21
  • This looks like it will work for taking ownership, but I assume OP wanted to set ownership to someone else (which would involve SeRestorePrivilege). Commented Oct 27, 2023 at 13:08
  • After rereading the post, I think that assumption is not accurate based on #2 item in the question stating 2. Change owner to myself. I'll dig more if the OP states this is the case and something is still not working since my latest comment about the format of the reg key value to pass to the function call. Commented Oct 28, 2023 at 13:17
  • sorry for the delayed response. I have tried with a number of variations including "SOFTWARE\Test" but unfortunately it makes no difference. Commented Oct 30, 2023 at 9:50
  • @VomitIT-ChunkyMessStyle I have followed the same process - set SYSTEM as owner manually, ran logic from your link. Here is the result: Exception calling "GetExportedTypes" with "0" argument(s): "The invoked member is not supported in a dynamic assembly." At C:\temp\Test-Permission.ps1:7 char:9 Commented Oct 31, 2023 at 12:52
-1

This PowerShell snippet sets the owner using the Set-Acl command:

$ACL = Get-Acl -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion"
$User = New-Object System.Security.Principal.Ntaccount("TestUser1")
$ACL.SetOwner($User)
$ACL | Set-Acl -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion"
Get-ACL -Path "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion"

You need to run this code as administrator.

Source : How to Use PowerShell to Manage Folder Permissions.

2
  • 1
    We are clearly not talking about folders Commented Oct 27, 2023 at 11:54
  • @PatrickKeane: Any object can be used with the above code. I changed it to registry, as you wish.
    – harrymc
    Commented Oct 27, 2023 at 12:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .