Adjusting Token Privileges in PowerShell
Friday, 24 September 2010
One thing you sometimes run into when it comes to some management tasks is the concept of ‘Token Privileges’. Now these aren’t just privileges that Windows gives you to make you feel better – those are Token Compliments.
Token Privileges are aspects of the things your user account can do, but you often don’t need that power enabled by default. For example, anybody can restart a computer, but windows doesn’t enable that privilege by default:
[C:\Users\leeholm] PS:112 > whoami /priv PRIVILEGES INFORMATION ---------------------- Privilege Name Description State ============================= ==================================== ======== SeShutdownPrivilege Shut down the system Disabled SeChangeNotifyPrivilege Bypass traverse checking Enabled SeUndockPrivilege Remove computer from docking station Disabled SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
When you try to run a command without a privilege enabled, you’ll usually get an ‘Access is Denied’ error. This doesn’t mean that you can’t do it – just that you need to enable the privilege before doing it.
However, if you’ve found this post, you probably know all of this :)
PowerShell doesn’t ship a cmdlet to adjust token privileges by default, but Add-Type makes it very reasonable. Here is Set-TokenPrivilege.ps1 in all its glory:
|
001
002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 |
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.Runtime.InteropServices; { [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); internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok); internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid); internal struct TokPriv1Luid { public int Count; public long Luid; public int Attr; } internal const int SE_PRIVILEGE_DISABLED = 0×00000000; internal const int TOKEN_QUERY = 0×00000008; internal const int TOKEN_ADJUST_PRIVILEGES = 0×00000020; { 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_DISABLED; } else { tp.Attr = SE_PRIVILEGE_ENABLED; } 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) |


Subscribe to this blog.
No. 1 — December 10th, 2010 at 3:43 pm
This is a great little example I’ve been trying to find something like this to set my privileges from powershell for sql installations, thanks
No. 2 — April 13th, 2011 at 2:26 pm
Thank you so much Lee.
After going to the trouble of using powershell’s SET-ACL to configure NTFS file auditing, I discovered SET-ACL fails if you are not the owner of every file and folder. Sadly, it tries to set the file owner and fails on any you don’t own.
Your script has let me enable the SeSecurityPrivilege and SeRestorePrivilege privileges to overcome this limitation. This is a much simpler solution than deploying the powershell community extensions to workaround the issue.