79430981

Date: 2025-02-11 18:26:16
Score: 0.5
Natty:
Report link
Add-Type @'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Principal;
using LSA_HANDLE = System.IntPtr;

public class UserRightsLsa
{
    private const int POLICY_CREATE_ACCOUNT = 0x00000010;
    private const int POLICY_LOOKUP_NAMES = 0x00000800;

    private const int STATUS_SUCCESS = 0x00000000;
    private const int STATUS_ACCESS_DENIED = unchecked((int)0xC0000022);
    private const int STATUS_INSUFFICIENT_RESOURCES = unchecked((int)0xC000009A);
    private const int STATUS_NO_MEMORY = unchecked((int)0xC0000017);

    [DllImport("advapi32.dll")]
    private static extern uint LsaNtStatusToWinError(int Status);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    private struct LSA_UNICODE_STRING
    {
        internal ushort Length;
        internal ushort MaximumLength;
        internal string Buffer;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LSA_OBJECT_ATTRIBUTES
    {
        internal uint Length;
        internal IntPtr RootDirectory;
        internal IntPtr ObjectName;
        internal uint Attributes;
        internal IntPtr SecurityDescriptor;
        internal IntPtr SecurityQualityOfService;
    }

    [DllImport("advapi32.dll")]
    private static extern int LsaOpenPolicy(
        LSA_UNICODE_STRING[] SystemName,
        ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
        uint DesiredAccessMask,
        out LSA_HANDLE PolicyHandle
    );

    [DllImport("advapi32.dll")]
    private static extern int LsaAddAccountRights(
        LSA_HANDLE PolicyHandle,
        byte[] AccountSid,
        LSA_UNICODE_STRING[] UserRights,
        uint CountOfRights
    );

    [DllImport("advapi32.dll")]
    private static extern int LsaClose(LSA_HANDLE ObjectHandle);

    private static Exception HandleLsaError(int ntStatus)
    {
        switch (ntStatus)
        {
            case STATUS_SUCCESS:
                return null;
            case STATUS_ACCESS_DENIED:
                return new UnauthorizedAccessException();
            case STATUS_INSUFFICIENT_RESOURCES:
            case STATUS_NO_MEMORY:
                return new OutOfMemoryException();
            default:
                return new Win32Exception((int)LsaNtStatusToWinError(ntStatus));
        }
    }

    private static LSA_UNICODE_STRING InitLsaString(string szString)
    {
        if (szString.Length > 0x7ffe)
            throw new ArgumentException("szString");

        return new LSA_UNICODE_STRING
        {
            Buffer = szString,
            Length = (ushort)(szString.Length * sizeof(char)),
            MaximumLength = (ushort)((szString.Length + 1) * sizeof(char))
        };
    }

    public static void Add(string username, string[] rights)
    {
        if (rights == null || rights.Length == 0)
            throw new ArgumentNullException("rights");

        SecurityIdentifier user;
        if (string.IsNullOrEmpty(username))
        {
            user = WindowsIdentity.GetCurrent().User;
        }
        else
        {
            try
            {
                user = new SecurityIdentifier(username);
            }
            catch
            {
                user = (SecurityIdentifier) new NTAccount(username).Translate(typeof(SecurityIdentifier));
            }
        }

        var sid = new byte[user.BinaryLength];
        user.GetBinaryForm(sid, 0);

        var userRights = new LSA_UNICODE_STRING[rights.Length];
        for (var i = 0; i < userRights.Length; ++i)
            userRights[i] = InitLsaString(rights[i]);

        var objectAttributes = new LSA_OBJECT_ATTRIBUTES();
        var lsaPolicyHandle = LSA_HANDLE.Zero;
        try
        {
            Exception ex;
            if ((ex = HandleLsaError(LsaOpenPolicy(null, ref objectAttributes,
                    POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES, out lsaPolicyHandle))) != null)
                throw ex;

            if ((ex = HandleLsaError(LsaAddAccountRights(lsaPolicyHandle, sid, userRights, (uint)userRights.Length))) !=
                null)
                throw ex;
        }
        finally
        {
            if (lsaPolicyHandle != LSA_HANDLE.Zero)
                LsaClose(lsaPolicyHandle);
        }
    }
}
'@

function Add-UserRight {
    param(
        [string]$Username,
        [parameter(Mandatory)][string[]]$Rights
    )

    [UserRightsLsa]::Add($Username, $Rights)
}

I simplified https://stackoverflow.com/a/14469248, whittled down the requested access mask for the LSA handle to the bare minimum that's required to call LsaAddAccountRights, added the ability to assign multiple rights in one call and took the idea of being able to pass a SID (in string form) from UserRights.psm1 (which you might prefer instead if you want something a lot more featureful). C# 5 is targeted to retain PowerShell 5.1 compatibility.

Call it with Add-UserRight -Username username -Right SeUndockPrivilege,SeShutdownPrivilege. Username is a bit of a misnomer - you can specify other accounts, like Groups etc.

A possible pitfall is that if Username is omitted/is null or empty, the rights you specify for adding will be added to the user the script is running as.

Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: 93270