locked
Powershell and ACL regedit RRS feed

  • Question

  • Hi guys,

    I have to modify a registry key with GPO for my IT enviroment (for disabling "Network" in the navigation pane --> like for a kiosk workstation), but i got some trouble that i can't figure out...

    The key that i have to change is (inside this direcotry) in this location:

    HKEY_CLASSES_ROOT\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder

    And i know that there is like an alyas for this registry key:

    HKLM:\SOFTWARE\Classes\CLSID\"{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}"\ShellFolder

    So I just tryed to change it with GPO (modify registry key) but there is a permission problem (admin can only read and not write inside this directory).. Therefore i decided to create a script that takes ACL from an exported key in a shared location (with right permissions), and "Paste" them in the "ShellFolder" for making work my gpo law. But i got some errors...

    I tryed to use this "easy" powershell script:

    PS C:\>$Stdkey= Get-Acl 'C:\Stdkey.reg' ---> Example: Random key in a random location PS C:\>Set-Acl -Path HKLM:\SOFTWARE\Classes\CLSID\"{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}"\ShellFolder -AclObject $Stdkey

    But it doesn't work.. it gives me an error about an invalid argument "securityDescriptor" (but as you can see this script doesn't call or changes nothing)

    Did I make something wrong? Is there a better way for doing it (I mean with another powershell script)?

    Thanks.

    Th3nshi.

    NB: English is not my main language, I hope that you can understand :)

    Wednesday, November 26, 2014 10:21 AM

Answers

  • Hi Th3nshi,

    For the GPO part in this issue, please post in the dedicated Group Policy forum for more efficient support, and  changing registry value or the registry permission is on your own risk:

    https://social.technet.microsoft.com/Forums/windowsserver/en-US/home?forum=winserverGP

    However, To change the permission of registry value via powershell, I checked the registry and found its permission is inherited by parent by default, and the owner is system:

    To change the permission we need takeownership and add current logon user has full controll permission, I tested the script below:

    function enable-privilege {
      param(
        ## The privilege to adjust. This set is taken from
        ## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
        [ValidateSet(
          "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
          "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
          "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
          "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
          "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
          "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
          "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
          "SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
          "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
          "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
          "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
        $Privilege,
        ## The process on which to adjust the privilege. Defaults to the current process.
        $ProcessId = $pid,
        ## Switch to disable the privilege, rather than enable it.
        [Switch] $Disable
      )
    
      ## Taken from P/Invoke.NET with minor adjustments.
      $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 relen);
       
        [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 SE_PRIVILEGE_DISABLED = 0x00000000;
        internal const int TOKEN_QUERY = 0x00000008;
        internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
        public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
        {
          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;
          if(disable)
          {
            tp.Attr = SE_PRIVILEGE_DISABLED;
          }
          else
          {
            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 $ProcessId).Handle
      $type = Add-Type $definition -PassThru
      $type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
    }
    
    start-sleep 10
    
    enable-privilege SeTakeOwnershipPrivilege 
    
    $user= whoami
    $path="SOFTWARE\Classes\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder"
    
    #take ownership
    
    $key1 = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path,[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::takeownership)
    $acl1 = $key1.GetAccessControl()
    $me = [System.Security.Principal.NTAccount]$user
    $acl1.SetOwner($me)
    $acl1
    
    $key1.SetAccessControl($acl1)
    
    #change permission add fullcontrol to logon user
    $key2 = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path,[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::ChangePermissions)
    $acl2 = $key2.GetAccessControl()
    $rule = New-Object System.Security.AccessControl.RegistryAccessRule ($user,"FullControl","Allow")
    $acl2.addAccessRule($rule)
    $acl2.access
    
    $key2.SetAccessControl($acl2)
    
    

    The function enable-privilege is quoted from this article:

    Adjusting Token Privileges in PowerShell

    If there is anything else regarding this issue, please feel free to post back.

    Best Regards,

    Anna Wang

    • Proposed as answer by AnnaWY Monday, December 1, 2014 1:34 AM
    • Marked as answer by AnnaWY Wednesday, December 3, 2014 10:48 AM
    Friday, November 28, 2014 3:25 AM

All replies

  • There are explicit GPOs for altering the desktop and Explorer settings. Post in GP forum for help.


    ¯\_(ツ)_/¯

    Wednesday, November 26, 2014 6:27 PM
  • Hi Th3nshi,

    For the GPO part in this issue, please post in the dedicated Group Policy forum for more efficient support, and  changing registry value or the registry permission is on your own risk:

    https://social.technet.microsoft.com/Forums/windowsserver/en-US/home?forum=winserverGP

    However, To change the permission of registry value via powershell, I checked the registry and found its permission is inherited by parent by default, and the owner is system:

    To change the permission we need takeownership and add current logon user has full controll permission, I tested the script below:

    function enable-privilege {
      param(
        ## The privilege to adjust. This set is taken from
        ## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
        [ValidateSet(
          "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
          "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
          "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
          "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
          "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
          "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
          "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
          "SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
          "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
          "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
          "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
        $Privilege,
        ## The process on which to adjust the privilege. Defaults to the current process.
        $ProcessId = $pid,
        ## Switch to disable the privilege, rather than enable it.
        [Switch] $Disable
      )
    
      ## Taken from P/Invoke.NET with minor adjustments.
      $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 relen);
       
        [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 SE_PRIVILEGE_DISABLED = 0x00000000;
        internal const int TOKEN_QUERY = 0x00000008;
        internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
        public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
        {
          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;
          if(disable)
          {
            tp.Attr = SE_PRIVILEGE_DISABLED;
          }
          else
          {
            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 $ProcessId).Handle
      $type = Add-Type $definition -PassThru
      $type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
    }
    
    start-sleep 10
    
    enable-privilege SeTakeOwnershipPrivilege 
    
    $user= whoami
    $path="SOFTWARE\Classes\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder"
    
    #take ownership
    
    $key1 = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path,[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::takeownership)
    $acl1 = $key1.GetAccessControl()
    $me = [System.Security.Principal.NTAccount]$user
    $acl1.SetOwner($me)
    $acl1
    
    $key1.SetAccessControl($acl1)
    
    #change permission add fullcontrol to logon user
    $key2 = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($path,[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::ChangePermissions)
    $acl2 = $key2.GetAccessControl()
    $rule = New-Object System.Security.AccessControl.RegistryAccessRule ($user,"FullControl","Allow")
    $acl2.addAccessRule($rule)
    $acl2.access
    
    $key2.SetAccessControl($acl2)
    
    

    The function enable-privilege is quoted from this article:

    Adjusting Token Privileges in PowerShell

    If there is anything else regarding this issue, please feel free to post back.

    Best Regards,

    Anna Wang

    • Proposed as answer by AnnaWY Monday, December 1, 2014 1:34 AM
    • Marked as answer by AnnaWY Wednesday, December 3, 2014 10:48 AM
    Friday, November 28, 2014 3:25 AM
  • Hi,Thanks Anna.

    Regards

    Friday, November 28, 2014 10:51 AM