Adjusting Token Privileges in PowerShell

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

002003

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;

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)

8 Responses to “Adjusting Token Privileges in PowerShell”

  1. David Wetherell writes:

    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

  2. Toby writes:

    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.

  3. Andy writes:

    Awesome to know this. I tried to run your script without any luck. Most of the errors are thrown on the Add-Type statement. “: Unexpected character ‘x'” Are there any issues with Windows 7 and using this script that you know of? I know it’s been a while, but I would love to use this similar to what Toby is doing.

  4. Oliver writes:

    @Andy
    I’ve run into the same issue. Did you found a solution for this?

  5. Lee Holmes writes:

    Hmm, looks like WordPress is replacing the “0x” with “0” and then the × HTML character. If you go to these four lines:

    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;

    Just replace the little x with a regular x from your keyboard.

  6. Greg Bray writes:

    See https://gist.github.com/fernandoacorreia/3997188/raw/0f2c654e509f1008b67f7e19308bb948029e9409/restore-wallpaper-rights.ps1 for another example of how to use this function in powershell.

  7. Scott writes:

    What’s not remote clear is actually how do you USE this script? An example of actually using it to allow the privilege would be nice as we’re not all Powershell experts – I assume you need to call EnablePrivilege and pass the security token you want but what other parameters are expected in what form? I can’t quiter make that out from looking at the code and could not make it work when I tried.

  8. Lee Holmes writes:

    Scott – there are a few examples of running this script here in the comments, but here’s a simple example to enable the SeTimeZone privilege:

    Set-TokenPrivilege -Privilege SeTimeZonePrivilege

Leave a Reply