Trying to modify the registry value of Network Adapter Friendly Name Windows 2016 Server

Anonymous
2021-01-21T13:54:09.967+00:00

Thank you very much for any help. I have been trying this for a good while.

Using C# console application, I am trying to edit the FriendlyName of the Network Adapter on a Windows 2016 Server system. I am running the command prompt As Administrator. I can accomplish the change if I manually use regedit and change permissions by adding Administrator account and giving Full Control but I wanted to be able to accomplish using a C# application.

RegistryKey myRk = regKey.OpenSubKey("System\\ControlSet001\\Enum\\PCI\\VEN_14E4&DEV_1657&SUBSYS_22BE103C&REV_01\\000098F2B3287D4800");

RegistrySecurity myRS = myRk.GetAccessControl();

string user = Environment.UserDomainName + "\\" + Environment.UserName;

myRS.AddAccessRule(new RegistryAccessRule(user,
                    RegistryRights.TakeOwnership,
                    InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
                    PropagationFlags.None,
                    AccessControlType.Allow));

var ntAccount = new NTAccount(Environment.UserDomainName, Environment.UserName);
myRS.SetOwner(ntAccount);

myRk.SetAccessControl(myRS);

Registry.SetValue("HKEY_LOCAL_MACHINE" + "\\" + "System\\ControlSet001\\Enum\\PCI\\VEN_14E4&DEV_1657&SUBSYS_22BE103C&REV_01\\000098F2B3287D4800", "FriendlyName", "331i Adapter", RegistryValueKind.String);

I am seeing an "UnauthorizedException" "Cannot write to the registry key" on SetAccessControl() Here is the code I am using:

I appreciate the help,
Michael McIntyre (HPE)

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,179 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 81,356 Reputation points
    2021-01-22T14:37:58.683+00:00

    I cannot test on Windows Server, but on Windows 10, this works for me, as Administrator (Manifest)
    (from Accessing Device Instance SPDRP_Xxx Properties, it should work on Windows Server...)

    For the test, this changes a Friendly Name "Test" into "New Name" =>

    DEVPKEY_Device_FriendlyName = new DEVPROPKEY();  
    DEVPKEY_Device_FriendlyName.fmtid = new Guid("A45C254E-DF1C-4EFD-8020-67D146A850E0");  
    DEVPKEY_Device_FriendlyName.pid = 14;  
      
    string sOldName = "Test";  
    string sNewName = "New Name";  
      
    IntPtr hDeviceInfo = SetupDiGetClassDevs(ref GUID_DEVCLASS_NET, IntPtr.Zero, IntPtr.Zero, DIGCF_PRESENT);  
    if (hDeviceInfo != IntPtr.Zero)  
    {  
        var DeviceInfoData = new SP_DEVINFO_DATA() { cbSize = Marshal.SizeOf(typeof(SP_DEVINFO_DATA)) };  
        int nNumberOfDevicesPresent = 0;  
        while (SetupDiEnumDeviceInfo(hDeviceInfo, nNumberOfDevicesPresent, ref DeviceInfoData))  
        {  
            StringBuilder sbDeviceName = new StringBuilder(260);  
            sbDeviceName.Capacity = 260;  
            bool bRet = SetupDiGetDeviceRegistryProperty(hDeviceInfo, ref DeviceInfoData, SPDRP_FRIENDLYNAME, 0, sbDeviceName, (uint)sbDeviceName.Capacity, IntPtr.Zero);  
            if (bRet)  
            {  
                Console.WriteLine("Device Name : {0}", sbDeviceName.ToString());                             
                if (sbDeviceName.ToString() == sOldName)  
                {  
                    StringBuilder sbNewDeviceName = new StringBuilder(sNewName);  
                    bRet = SetupDiSetDeviceRegistryProperty(hDeviceInfo, ref DeviceInfoData, SPDRP_FRIENDLYNAME, sbNewDeviceName, (uint)(sbNewDeviceName.Capacity * Marshal.SystemDefaultCharSize));  
                    if (!bRet)  
                    {  
                        int nError = Marshal.GetLastWin32Error();  
                        string sErrorMessage = new Win32Exception(nError).Message;  
                        System.Windows.Forms.MessageBox.Show("Error : " + nError.ToString() + Environment.NewLine + sErrorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);  
                    }  
                }  
            }  
            else  
            {  
                bRet = SetupDiGetDeviceRegistryProperty(hDeviceInfo, ref DeviceInfoData, SPDRP_DEVICEDESC, 0, sbDeviceName, (uint)sbDeviceName.Capacity, IntPtr.Zero);  
                if (bRet)  
                {  
                    Console.WriteLine("Device Description : {0}", sbDeviceName.ToString());  
                }  
            }  
            nNumberOfDevicesPresent++;  
        }  
    }  
    

    Declarations :

    public const int DIGCF_PRESENT = 0x00000002;  
    public const int DIGCF_DEVICEINTERFACE = 0x00000010;  
    public const int ERROR_INSUFFICIENT_BUFFER = 122;  
      
    public static Guid GUID_DEVCLASS_NET = new Guid("4d36e972-e325-11ce-bfc1-08002be10318");  
      
    [DllImport("Setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]  
    public static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hWndParent, int Flags);  
      
    [DllImport("Setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]  
    public static extern bool SetupDiEnumDeviceInfo(IntPtr DeviceInfoSet, int MemberIndex, ref SP_DEVINFO_DATA DeviceInfoData);  
      
    [DllImport("Setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]  
    public static extern bool SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, uint Property,  
        uint PropertyRegDataType, StringBuilder PropertyBuffer, uint PropertyBufferSize, IntPtr RequiredSize);  
      
    [DllImport("Setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]  
    public static extern bool SetupDiSetDeviceRegistryProperty(IntPtr DeviceInfoSet, ref SP_DEVINFO_DATA DeviceInfoData, uint Property,  
    StringBuilder PropertyBuffer, uint PropertyBufferSize);  
      
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]  
    public struct DEVPROPKEY  
    {  
        public Guid fmtid;  
        public uint pid;  
    }  
      
    DEVPROPKEY DEVPKEY_Device_FriendlyName;       
      
    public const int SPDRP_DEVICEDESC = (0x00000000);  // DeviceDesc (R/W)  
    public const int SPDRP_FRIENDLYNAME = (0x0000000C); // FriendlyName (R/W)  
    public const int SPDRP_LOCATION_INFORMATION = (0x0000000D);  // LocationInformation (R/W)  
      
    #if WIN64  
            public const int PACK_SIZE = 8;  
    #else  
            public const int PACK_SIZE = 1;  
    #endif  
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = PACK_SIZE)]  
    public struct SP_DEVINFO_DATA  
    {  
        public int cbSize;  
        public Guid ClassGuid;  
        public int DevInst;  
        public IntPtr Reserved;  
    }  
    
    0 comments No comments

6 additional answers

Sort by: Most helpful
  1. Michael Taylor 47,471 Reputation points
    2021-01-21T15:01:53.26+00:00

    Do you have UAC enabled? When you say you run the app as an admin are you saying you have admin privileges and are running it or that you right clicked the command prompt and selected Run as Administrator?

    On the code side you are setting the current user as owner. That isn't right to me. At a minimum you'd set the Administrators group as the owner, not a personal account. For that use the pre-defined Windows Identity.

    var admins = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
    

    But that step might not be needed at all. If it is needed then you should set the owner first and then change the access rules.

    Also note that writes to certain areas (such as HKLM) may be virtualized. Therefore modify your call to OpenSubKey to include the flag that you intend to write to it. This ensures you open the correct key for writing. Later to set the value use the RegistryKey value you already have, don't use the Registry.SetValue method.

    myRk.SetValue("FriendlyName", "");
    

    Lastly note that you're trying to write to ControlSet001. I don't believe that to be the correct location. Things could have changed but the CurrentControlSet is where Windows gets all this information. It creates a backup to ControlSet001 (and higher numbers) after certain changes. If you restart Windows and it detects issues it gives you the option of starting from "last known good". If you select that option then it overwrites CurrentControlSet with ControlSet001. If you want to modify the "current" settings you should be setting CurrentControlSet.

    0 comments No comments

  2. Anonymous
    2021-01-21T16:19:29.627+00:00

    Thank you very much for the reply!

    I have tried both, right-clicking the command prompt at open and selecting Run As Administrator and also right-clicking the icon for the application icon on the desktop and Run as administrator.

    Interestingly, the owner of the key is already Administrators. For me to get it to work, I have to manually make it Administrator, which is the account I am logging in with.

    If I try including the write flag on the OpenSubKey() call, I get System.Security.Exception Requested registry access is not allowed.

    RegistryKey myRk = regKey.OpenSubKey("System\\ControlSet001\\Enum\\PCI\\VEN_14E4&DEV_1657&SUBSYS_22BE103C&REV_01\\000098F2B3287D4800", true);
    

    Regarding the location. I agree CurrentControlSet would make more sense but, CurrentControlSet doesn't have the ENUM hive that ControlSet001 does. If I manually change the permissions and effect the FriendlyName change in the ControlSet001 hive, it does persists after a reboot.

    In my searching and experimenting, I have found and tried using RegistryRights.ChangePermissions, RegistryRights.TakeOwnership, and RegistryRights.FullControl on the OpenSubKey() call without any luck...

    0 comments No comments

  3. Michael Taylor 47,471 Reputation points
    2021-01-21T16:51:38.447+00:00

    Hmm, works fine for me. Note that since Administrators is already the owner you don't need to change any security settings. This code correctly sets the friendly name of an arbitrary PCI object in CurrentControlSet for me when run as administrator.

    static void ChangeFriendlyName ( string deviceName, string friendlyName )
    {
        var keyPath = @"System\CurrentControlSet\Enum\PCI\" + deviceName;
        using (var key = Registry.LocalMachine.OpenSubKey(keyPath, true))
        {   
            key.SetValue("FriendlyName", friendlyName);
        };
    }
    

    I changed it to work against ControlSet001 and it also worked.

    Given the exception it seems to me that the account you're using isn't actually an admin and/or setting the owner is messing things up. In general if an admin level user (elevated) takes ownership or otherwise makes changes to security then Windows uses the Administrators group instead. But I'm wondering if that isn't happening here. Try setting a different key that you haven't touched yet. Before you do look at the owner and permissions. Then run your code. If it works then your original test key's security is messed up. Potentially because of your code. Reset the original key's permissions and try again. If it still doesn't work then use the Effective RIghts UI against the user account you're running and see what Windows thinks your permissions are.

    0 comments No comments

  4. Anonymous
    2021-01-21T17:28:45.093+00:00

    Ahhh...Ok Your guidance got me back on track.

    I could have sworn that CurrentControlSet didn't have the Enum hive. But, upon further review, it does!

    I used the simple code you provided against the CurrentControlSet and it appears to work fine!

    Thank you for the help!!!

    0 comments No comments