none
Remove other users(HKEY_CURRENTUSER) registry key using an admin account RRS feed

  • Question

  • I am writing C# windows application which will run On WinXP.  The code is suppose to traverse though all the local non admin users from remove certain registry keys. I have no access to the non admin user accounts or passwords

    For example: I have 3 users, 1 admin and 2 non admin.

    The admin user is used to install and uninstall the c# windows application. and the 2 non-admin users merely uses the application(they may or may not have access to regedit)

    I found some examples in retrieving SIDs using ManagemnetObjectSearcher, SIDs basically represents local user id.

    now the question is, how to do use the SIDs to retreive the "other local users" RegistryKey so i can remove them from the admin account. I need to remove registry keys from nonadmin's HKCU entries. 

    Thank You, any help will be very much appreciated.

    Wednesday, May 2, 2012 4:11 PM

Answers

  • Hi Howie,

    you are correct - it was just one part of the solution. I used it a few years ago to fix computer problems where the user was logged in already.

    You can make the system to load a hive using the RegLoadKey function:
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms724889(v=vs.85).aspx

    You might find this thread interesting:
    http://stackoverflow.com/questions/7894909/load-registry-hive-from-c-sharp-fails
    Just make sure that you fix the Dllmport - the method returns a 32Bit int (int/Int32) instead of a long.

    That way you already have the code required to get the privileges required.

    With kind regards,

    Konrad

    • Proposed as answer by webJose Thursday, May 3, 2012 3:30 AM
    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Wednesday, May 2, 2012 5:00 PM
  • thank you so much Konrad, your solution worked very well. Except I can't seem to unload the reg. All the registry that was loaded stay loaded.  

    Here is the complete solution in deleting a registry. 

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    using Microsoft.Win32;
    using System.Management;

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {

                ManagementObjectSearcher searcher =
            new ManagementObjectSearcher("root\\CIMV2",
            "SELECT * FROM Win32_UserAccount");
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Console.WriteLine("SID: " + queryObj["SID"].ToString());
                    String sid = queryObj["SID"].ToString();
                    Console.WriteLine(queryObj.GetPropertyValue("Name").ToString());
                    String username = queryObj.GetPropertyValue("Name").ToString();
                    
                    //String name = queryObj["user"].ToString();
                    ////RegistryKey userSubkey = users.OpenSubKey(sid, true);
                    //Registry.Users.OpenSubKey(queryObj["SID"].ToString());
                    RegistryTest test = new RegistryTest( sid,  username);
                }

              //  RegistryTest test = new RegistryTest();
            }

            public class RegistryTest
            {
                [StructLayout(LayoutKind.Sequential)]
                private struct LUID
                {
                    public uint LowPart;
                    public int HighPart;
                }

                [StructLayout(LayoutKind.Sequential)]
                private struct LUID_AND_ATTRIBUTES
                {
                    public LUID pLuid;
                    public UInt32 Attributes;
                }

                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                private struct TokPriv1Luid
                {
                    public int Count;
                    public LUID Luid;
                    public UInt32 Attr;
                }

                private const Int32 ANYSIZE_ARRAY = 1;
                private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
                private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
                private const UInt32 TOKEN_QUERY = 0x0008;

                private const uint HKEY_USERS = 0x80000003;
                private const string SE_RESTORE_NAME = "SeRestorePrivilege";
                private const string SE_BACKUP_NAME = "SeBackupPrivilege";

                [DllImport("kernel32.dll")]
                static extern IntPtr GetCurrentProcess();

                [DllImport("advapi32.dll", SetLastError = true)]
                [return: MarshalAs(UnmanagedType.Bool)]
                static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

                [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
                [return: MarshalAs(UnmanagedType.Bool)]
                static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

                [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
                static extern bool AdjustTokenPrivileges(
                    IntPtr htok,
                    bool disableAllPrivileges,
                    ref TokPriv1Luid newState,
                    int len,
                    IntPtr prev,
                    IntPtr relen);

                [DllImport("advapi32.dll", SetLastError = true)]
                static extern int RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);

                [DllImport("advapi32.dll", SetLastError = true)]
                static extern int RegUnLoadKey(UInt32 hKey, string lpSubKey);

                private IntPtr _myToken;
                private TokPriv1Luid _tokenPrivileges = new TokPriv1Luid();
                private TokPriv1Luid _tokenPrivileges2 = new TokPriv1Luid();

                private LUID _restoreLuid;
                private LUID _backupLuid;

                public RegistryTest(string sid, string username)
                {
                    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out _myToken))
                        Console.WriteLine("OpenProcess Error");

                    if (!LookupPrivilegeValue(null, SE_RESTORE_NAME, out _restoreLuid))
                        Console.WriteLine("LookupPrivilegeValue Error");

                    if (!LookupPrivilegeValue(null, SE_BACKUP_NAME, out _backupLuid))
                        Console.WriteLine("LookupPrivilegeValue Error");

                    _tokenPrivileges.Attr = SE_PRIVILEGE_ENABLED;
                    _tokenPrivileges.Luid = _restoreLuid;
                    _tokenPrivileges.Count = 1;

                    _tokenPrivileges2.Attr = SE_PRIVILEGE_ENABLED;
                    _tokenPrivileges2.Luid = _backupLuid;
                    _tokenPrivileges2.Count = 1;

                    if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
                        Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());

                    if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges2, 0, IntPtr.Zero, IntPtr.Zero))
                        Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());

                    // --> RegLoadKey fails with return value 8589934592 <--
                    string path =  "C:\\Documents and Settings\\" + username + "\\NTUSER.DAT";
                    int retVal = RegLoadKey(HKEY_USERS, sid, @path);
                    
                    if (retVal != 0)
                        Console.WriteLine("Ignoring..... probably can't find NTUSER.DAT" + retVal);
                    else
                    {
                        RegistryKey users = Registry.Users;

                        RegistryKey userSubkey = users.OpenSubKey(sid, true);


                        if (userSubkey != null)
                        {
                            // open some registry
                            RegistryKey userWordLocation = userSubkey.OpenSubKey("abc");

                            if (userWordLocation != null)
                            {
                                RegistryKey deleteKey = userWordLocation.OpenSubKey("abc");

                                if (deleteKey != null)
                                    deleteKey.DeleteSubKeyTree("abc");
                            }
                        }
                    }

                    retVal = RegUnLoadKey(HKEY_USERS, sid);
                }
            }
        }
    }
     

    Howie Zhu

    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Wednesday, May 2, 2012 6:30 PM
  • Hi,

    first of all it is nice to see the progress that happened. Hopefully I can clarify a little more about the different problems:

    a) The RegistryKey has a Close method. Please make sure to call close when you no longer use it. As long as your application keeps an RegistryKey open, the hive will not be unloaded. So your code regarding close calls could be like this:

                    RegistryKey users = Registry.Users;
                    RegistryKey userSubkey = users.OpenSubKey(sid, true);


                    if (userSubkey != null)
                    {
                        // open some registry
                        RegistryKey userWordLocation = userSubkey.OpenSubKey("abc");

                        if (userWordLocation != null)
                        {
                            RegistryKey deleteKey = userWordLocation.OpenSubKey("abc");

                            if (deleteKey != null)
                            {
                                deleteKey.DeleteSubKeyTree("abc");
                                deleteKey.Close();
                            }
                           
                            userWordLocation.Close();
                        }
                       
                    }
                    users.Close();
                    userSubkey.Close();

                }

    In my tests, I was able to confirm that the Hive is now unloaded correctly. Also very interesting: RegistryKey does not implement IDisposable. At least I saw no Dispose() method in IntelliSense which really wonders me! Shouldn't Microsoft implement IDisposable on these classes?

    2) Required rights. You do not need to take over any rights on the user files. It is ok that you cannot read the file. My understanding is, that you just tell the system to load the registry hive. For this you need the priviledges you get first (afaik - didn't test it further now) but you do not need file access. So there is no need to implement any code there. (I tested it on a windows 7 64Bit system. Hives was loaded correctly without taking ownership or so on the files!)

    So if you had problems, you might want to check that you had the correct key, that the key is there and also important: The Registry Entries have an ACL, too. So make sure that you had the required rights on the key. It could be a goot test to use regedit or regedt32 to check everything.

    In my tests I simply placed a breakpoint after loading the hive so I was able to check the registry.

    With kind regards,

    Konrad

    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Thursday, May 3, 2012 1:23 PM
  • Hi,

    I played around further now and I think I found the problem.

    First and important: There is no need to takeover any rights! Your test with RegEdit (which I did, too) prooved already that the rights on the file does not count at all and that the windows system is taking care of it. The ACLs on the registry parts are important and nothing else.

    So where is the Problem?

    Just check the documentation of the OpenSubKey method used: http://msdn.microsoft.com/en-us/library/z9f66s0a.aspx

    The remarks are quite straight forward: If you want to modify the subkey, you have to use another overload!

    So just change it to
    var newRegistryKeyInstance = someRegistryKey.OpenSubKey("Whatever", true);

    So if you set writeable to true, the deletion of a key is possible.

    So my code to remove a key looks like this now:

                    RegistryKey users = Registry.Users;
                    RegistryKey userSubkey = users.OpenSubKey(sid, true);


                    if (userSubkey != null)
                    {
                        // open some registry
                        RegistryKey SoftwareKey = userSubkey.OpenSubKey("Software", true);

                        if (SoftwareKey != null)
                        {
                            try
                            {
                                SoftwareKey.DeleteSubKeyTree("7-Zip");
                            } catch(Exception e)
                            {
                                Console.WriteLine("Exception {0} at {1}", e.Message, e.StackTrace);
                            }
                            SoftwareKey.Close();
                        }
                       
                    }
                    users.Close();
                    userSubkey.Close();

    With kind regards,

    Konrad

    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Friday, May 4, 2012 11:08 AM

All replies

  • Hi,

    you can get the Registry Keys of a user through
    HKey_Users\<Sid of User>\...

    An administrator should have rights on these trees so when your application was started with elevated rights (in case of activated UAC!), it could delete registry keys there.

    So in code you could use the Microsoft.Win32 namespace, Registry class Users Property:
    http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.users.aspx

    I hope that helped a little bit.

    With kind regards,

    Konrad

    Wednesday, May 2, 2012 4:37 PM
  • Thank You, I don't think Registry.Users is the solution. Registry.Users only give you access to currently logged on users and not all users. 

    What I am trying to do is get access to all the local user's registry key. 

    Thank You

    Howie


    Howie Zhu

    Wednesday, May 2, 2012 4:45 PM
  • Hi Howie,

    you are correct - it was just one part of the solution. I used it a few years ago to fix computer problems where the user was logged in already.

    You can make the system to load a hive using the RegLoadKey function:
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms724889(v=vs.85).aspx

    You might find this thread interesting:
    http://stackoverflow.com/questions/7894909/load-registry-hive-from-c-sharp-fails
    Just make sure that you fix the Dllmport - the method returns a 32Bit int (int/Int32) instead of a long.

    That way you already have the code required to get the privileges required.

    With kind regards,

    Konrad

    • Proposed as answer by webJose Thursday, May 3, 2012 3:30 AM
    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Wednesday, May 2, 2012 5:00 PM
  • Thank You so much, I was looking at that same article earlier. I didn't quiet understand it. 

    For example: Where do I get the uint HKey_USERS? the example was using HKEY_USERS = 0x80000003; 

    Thank You

    Howie


    Howie Zhu

    Wednesday, May 2, 2012 5:27 PM
  • Thank you Konrad; I figured out what the uint HK_USERS really mean, 

    so I think I will use ManagementObjectSercher to get all the user name and sid's. Then load it using RegLoadKey. 

    Then use HKEY_Current_Users to try to edit the registries?

    Thanks a lot, 

    Howie


    Howie Zhu

    Wednesday, May 2, 2012 5:41 PM
  • thank you so much Konrad, your solution worked very well. Except I can't seem to unload the reg. All the registry that was loaded stay loaded.  

    Here is the complete solution in deleting a registry. 

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    using Microsoft.Win32;
    using System.Management;

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {

                ManagementObjectSearcher searcher =
            new ManagementObjectSearcher("root\\CIMV2",
            "SELECT * FROM Win32_UserAccount");
                foreach (ManagementObject queryObj in searcher.Get())
                {
                    Console.WriteLine("SID: " + queryObj["SID"].ToString());
                    String sid = queryObj["SID"].ToString();
                    Console.WriteLine(queryObj.GetPropertyValue("Name").ToString());
                    String username = queryObj.GetPropertyValue("Name").ToString();
                    
                    //String name = queryObj["user"].ToString();
                    ////RegistryKey userSubkey = users.OpenSubKey(sid, true);
                    //Registry.Users.OpenSubKey(queryObj["SID"].ToString());
                    RegistryTest test = new RegistryTest( sid,  username);
                }

              //  RegistryTest test = new RegistryTest();
            }

            public class RegistryTest
            {
                [StructLayout(LayoutKind.Sequential)]
                private struct LUID
                {
                    public uint LowPart;
                    public int HighPart;
                }

                [StructLayout(LayoutKind.Sequential)]
                private struct LUID_AND_ATTRIBUTES
                {
                    public LUID pLuid;
                    public UInt32 Attributes;
                }

                [StructLayout(LayoutKind.Sequential, Pack = 1)]
                private struct TokPriv1Luid
                {
                    public int Count;
                    public LUID Luid;
                    public UInt32 Attr;
                }

                private const Int32 ANYSIZE_ARRAY = 1;
                private const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002;
                private const UInt32 TOKEN_ADJUST_PRIVILEGES = 0x0020;
                private const UInt32 TOKEN_QUERY = 0x0008;

                private const uint HKEY_USERS = 0x80000003;
                private const string SE_RESTORE_NAME = "SeRestorePrivilege";
                private const string SE_BACKUP_NAME = "SeBackupPrivilege";

                [DllImport("kernel32.dll")]
                static extern IntPtr GetCurrentProcess();

                [DllImport("advapi32.dll", SetLastError = true)]
                [return: MarshalAs(UnmanagedType.Bool)]
                static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle);

                [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
                [return: MarshalAs(UnmanagedType.Bool)]
                static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid);

                [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
                static extern bool AdjustTokenPrivileges(
                    IntPtr htok,
                    bool disableAllPrivileges,
                    ref TokPriv1Luid newState,
                    int len,
                    IntPtr prev,
                    IntPtr relen);

                [DllImport("advapi32.dll", SetLastError = true)]
                static extern int RegLoadKey(UInt32 hKey, String lpSubKey, String lpFile);

                [DllImport("advapi32.dll", SetLastError = true)]
                static extern int RegUnLoadKey(UInt32 hKey, string lpSubKey);

                private IntPtr _myToken;
                private TokPriv1Luid _tokenPrivileges = new TokPriv1Luid();
                private TokPriv1Luid _tokenPrivileges2 = new TokPriv1Luid();

                private LUID _restoreLuid;
                private LUID _backupLuid;

                public RegistryTest(string sid, string username)
                {
                    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out _myToken))
                        Console.WriteLine("OpenProcess Error");

                    if (!LookupPrivilegeValue(null, SE_RESTORE_NAME, out _restoreLuid))
                        Console.WriteLine("LookupPrivilegeValue Error");

                    if (!LookupPrivilegeValue(null, SE_BACKUP_NAME, out _backupLuid))
                        Console.WriteLine("LookupPrivilegeValue Error");

                    _tokenPrivileges.Attr = SE_PRIVILEGE_ENABLED;
                    _tokenPrivileges.Luid = _restoreLuid;
                    _tokenPrivileges.Count = 1;

                    _tokenPrivileges2.Attr = SE_PRIVILEGE_ENABLED;
                    _tokenPrivileges2.Luid = _backupLuid;
                    _tokenPrivileges2.Count = 1;

                    if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero))
                        Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());

                    if (!AdjustTokenPrivileges(_myToken, false, ref _tokenPrivileges2, 0, IntPtr.Zero, IntPtr.Zero))
                        Console.WriteLine("AdjustTokenPrivileges Error: " + Marshal.GetLastWin32Error());

                    // --> RegLoadKey fails with return value 8589934592 <--
                    string path =  "C:\\Documents and Settings\\" + username + "\\NTUSER.DAT";
                    int retVal = RegLoadKey(HKEY_USERS, sid, @path);
                    
                    if (retVal != 0)
                        Console.WriteLine("Ignoring..... probably can't find NTUSER.DAT" + retVal);
                    else
                    {
                        RegistryKey users = Registry.Users;

                        RegistryKey userSubkey = users.OpenSubKey(sid, true);


                        if (userSubkey != null)
                        {
                            // open some registry
                            RegistryKey userWordLocation = userSubkey.OpenSubKey("abc");

                            if (userWordLocation != null)
                            {
                                RegistryKey deleteKey = userWordLocation.OpenSubKey("abc");

                                if (deleteKey != null)
                                    deleteKey.DeleteSubKeyTree("abc");
                            }
                        }
                    }

                    retVal = RegUnLoadKey(HKEY_USERS, sid);
                }
            }
        }
    }
     

    Howie Zhu

    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Wednesday, May 2, 2012 6:30 PM
  • the code above didn't exactly work. I am now having permission issues.

    Apparently, I was able to openSubKeys but not delete them.

    System.UnauthorizedAccessException was caught

      Message=Cannot write to the registry key.
      Source=mscorlib
      StackTrace:
           at System.ThrowHelper.ThrowUnauthorizedAccessException(ExceptionResource resource)
           at Microsoft.Win32.RegistryKey.EnsureWriteable()
           at Microsoft.Win32.RegistryKey.DeleteSubKeyTree(String subkey, Boolean throwOnMissingSubKey)
           at Microsoft.Win32.RegistryKey.DeleteSubKeyTree(String subkey)
           at ConsoleApplication1.Program.RegistryRemove..ctor(String sid, String username) in c:\documents and settings\admin\my documents\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\Program.cs:line 151
      InnerException: 

    ps# I am running windows XP and using Admin.


    Howie Zhu


    • Edited by HowieRocks Wednesday, May 2, 2012 11:15 PM
    Wednesday, May 2, 2012 8:14 PM
  • Usually administrators does not have right on users hive, you may need the code here to take ownership from it.
    Thursday, May 3, 2012 2:32 AM
    Answerer
  • Hi HowieRocks,

    There is another simple way, if local profile exist on the system:

     HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion \ProfileList


    Regards, http://shwetamannjain.blogspot.com

    Thursday, May 3, 2012 3:24 AM
  • Hi,

    first of all it is nice to see the progress that happened. Hopefully I can clarify a little more about the different problems:

    a) The RegistryKey has a Close method. Please make sure to call close when you no longer use it. As long as your application keeps an RegistryKey open, the hive will not be unloaded. So your code regarding close calls could be like this:

                    RegistryKey users = Registry.Users;
                    RegistryKey userSubkey = users.OpenSubKey(sid, true);


                    if (userSubkey != null)
                    {
                        // open some registry
                        RegistryKey userWordLocation = userSubkey.OpenSubKey("abc");

                        if (userWordLocation != null)
                        {
                            RegistryKey deleteKey = userWordLocation.OpenSubKey("abc");

                            if (deleteKey != null)
                            {
                                deleteKey.DeleteSubKeyTree("abc");
                                deleteKey.Close();
                            }
                           
                            userWordLocation.Close();
                        }
                       
                    }
                    users.Close();
                    userSubkey.Close();

                }

    In my tests, I was able to confirm that the Hive is now unloaded correctly. Also very interesting: RegistryKey does not implement IDisposable. At least I saw no Dispose() method in IntelliSense which really wonders me! Shouldn't Microsoft implement IDisposable on these classes?

    2) Required rights. You do not need to take over any rights on the user files. It is ok that you cannot read the file. My understanding is, that you just tell the system to load the registry hive. For this you need the priviledges you get first (afaik - didn't test it further now) but you do not need file access. So there is no need to implement any code there. (I tested it on a windows 7 64Bit system. Hives was loaded correctly without taking ownership or so on the files!)

    So if you had problems, you might want to check that you had the correct key, that the key is there and also important: The Registry Entries have an ACL, too. So make sure that you had the required rights on the key. It could be a goot test to use regedit or regedt32 to check everything.

    In my tests I simply placed a breakpoint after loading the hive so I was able to check the registry.

    With kind regards,

    Konrad

    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Thursday, May 3, 2012 1:23 PM
  • Ok, Just to clarify the IDisposable thing: The interface is implemented explicitly.

    At least that is the result from my quick look into the msdn library and some quick checks. So you could use the using statement or you could cast to IDisposable in case you want to call Dispose() instead of Close().

    With kind regards,

    Konrad

    Thursday, May 3, 2012 1:32 PM
  • Thank You Konrad;

    Close() worked in unloading the Hives. but I still can't remove the keys. I modified the code as you specified. 

    The code crashes with "System.UnauthorizedAccessException was caught" on userWordLocation.DeleteSubKeyTree("TestAddIn"); This tells me the key actually exists but no permission to remove it. Interesting fact is that when i have break point set, I can manually go into regedit to remove the TestAddIn key, but unable to remove it using userWordLocation.DeleteSubKeyTree("TestAddIn");

    I also know that the keys I am using is correct cause if (deleteKey != null) is a none null value.

                        RegistryKey users = Registry.Users;
                        string legacyWordLocation = @"SOFTWARE\Microsoft\Office\Word\Addins\";
                        RegistryKey userSubkey = users.OpenSubKey(username, true);

                        if (userSubkey != null)
                        {
                            RegistryKey userWordLocation = userSubkey.OpenSubKey(legacyWordLocation);
                            if (userWordLocation != null)
                            {
                                RegistryKey deleteKey = userWordLocation.OpenSubKey("TestAddIn");

                                try
                                {
                                    if (deleteKey != null)
                                    {
                                        userWordLocation.DeleteSubKeyTree("TestAddIn");
                                        deleteKey.Close();
                                    }
                                }
                                catch (Exception e) 
                                {
                                    deleteKey.Close();
                                }
                                userWordLocation.Close();
                            }

                            userSubkey.Close();

                            users.Close();
                        }


    Howie Zhu

    Thursday, May 3, 2012 2:51 PM
  • The exception is thown at EnsureWriteable() call, not at the actual deletion code. So it's not that you can't actually remove the key, it's the .NET runtime's sanity check preventing you from remove it.

    Just take ownership to ensure you have write access to the subkeys and it'll not complain.

    Friday, May 4, 2012 1:43 AM
    Answerer
  • Hi,

    I played around further now and I think I found the problem.

    First and important: There is no need to takeover any rights! Your test with RegEdit (which I did, too) prooved already that the rights on the file does not count at all and that the windows system is taking care of it. The ACLs on the registry parts are important and nothing else.

    So where is the Problem?

    Just check the documentation of the OpenSubKey method used: http://msdn.microsoft.com/en-us/library/z9f66s0a.aspx

    The remarks are quite straight forward: If you want to modify the subkey, you have to use another overload!

    So just change it to
    var newRegistryKeyInstance = someRegistryKey.OpenSubKey("Whatever", true);

    So if you set writeable to true, the deletion of a key is possible.

    So my code to remove a key looks like this now:

                    RegistryKey users = Registry.Users;
                    RegistryKey userSubkey = users.OpenSubKey(sid, true);


                    if (userSubkey != null)
                    {
                        // open some registry
                        RegistryKey SoftwareKey = userSubkey.OpenSubKey("Software", true);

                        if (SoftwareKey != null)
                        {
                            try
                            {
                                SoftwareKey.DeleteSubKeyTree("7-Zip");
                            } catch(Exception e)
                            {
                                Console.WriteLine("Exception {0} at {1}", e.Message, e.StackTrace);
                            }
                            SoftwareKey.Close();
                        }
                       
                    }
                    users.Close();
                    userSubkey.Close();

    With kind regards,

    Konrad

    • Marked as answer by HowieRocks Friday, May 4, 2012 3:29 PM
    Friday, May 4, 2012 11:08 AM
  • Konrad; 

    that was exactly the issue. after putting true in OpenSubKey, everything seem to work now.

    Except that there seem to be a latency in deleting the subkeys. It really only take effect after I restart PC. Is there a flush feature for Registry too?



    Howie Zhu

    Friday, May 4, 2012 3:29 PM
  • Hi Howie,

    in my tests the keys was directy removed. Are you sure that this is not the case on your system? When you check it with regedit and you open it before the delete, you have to refresh it with F5.

    With kind regards,

    Konrad

    Friday, May 4, 2012 5:23 PM
  • Hi Konrad:

    It works very well with the user that I am running the program from. but when I logged out and then went back to the other non-admin account, "sometimes" the registries stayed. 

    I am still very happy with the solution, thank you so much.

    Howie


    Howie Zhu

    Sunday, May 6, 2012 3:10 PM