Scripts/Remove-Privilege.ps1

Function Remove-Privilege {
    <#
        .SYNOPSIS
            Removes a specified privilege for a user or group

        .DESCRIPTION
            Removes a specified privilege for a user or group. This will remain until
            re-added using Add-Privilege or a policy is refreshed.

        .PARAMETER AccountName
            The user or group which will have the privilege removed.
        
        .PARAMETER Privilege
            Specific privilege/s to remove from the local machine
        
        .NOTES
            Name: Remove-Privilege
            Author: Boe Prox
            Version History:
                1.0 - Initial Version

        .EXAMPLE
        Remove-Privilege -AccountName Domain\SomeUser -Privilege SeBackupPrivilege

        Description
        -----------
        Removes the SeBackupPrivilege privilege for Domain\SomeUser on the local machine
        
    #>

    [cmdletbinding(
        SupportsShouldProcess = $True
    )]
    Param (
        [parameter(Mandatory=$True)]
        [string]$AccountName,
        [parameter(Mandatory=$True)]
        [Privileges[]]$Privilege
    )
    #No point going through everything if just using -WhatIf
    If ($PSCmdlet.ShouldProcess($AccountName,"Remove Privilege(s): $($Privilege -join ', ')")) {
        #region SID Information
        Write-Verbose "Gathering SID information"
        $AccountSID = ([System.Security.Principal.NTAccount]$AccountName).Translate([System.Security.Principal.SecurityIdentifier])
        $ByteBuffer = New-Object Byte[] -ArgumentList $AccountSID.BinaryLength
        $AccountSID.GetBinaryForm($ByteBuffer,0)
        $SIDPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($AccountSID.BinaryLength)
        [System.Runtime.InteropServices.Marshal]::Copy(
            $ByteBuffer, 
            0, 
            $SIDPtr, 
            $AccountSID.BinaryLength
        )
        #endregion SID Information

        #region LsaOpenPolicy
        $Computer = New-Object LSA_UNICODE_STRING
        $Computer.Buffer = $env:COMPUTERNAME
        $Computer.Length = ($Computer.buffer.length * [System.Text.UnicodeEncoding]::CharSize)
        $Computer.MaximumLength = (($Computer.buffer.length+1) * [System.Text.UnicodeEncoding]::CharSize)
        $PolicyHandle = [intptr]::Zero
        $ObjectAttributes = New-Object LSA_OBJECT_ATTRIBUTES
        [uint32]$Access = [LSA_AccessPolicy]::POLICY_CREATE_ACCOUNT -BOR [LSA_AccessPolicy]::POLICY_LOOKUP_NAMES
        Write-Verbose "Opening policy handle"
        $NTStatus = [PoShPrivilege]::LsaOpenPolicy(
            [ref]$Computer,
            [ref]$ObjectAttributes,
            $Access,
            [ref]$PolicyHandle
        )

        #region winErrorCode
        If ($NTStatus -ne 0) {
            $Win32ErrorCode = [PoShPrivilege]::LsaNtStatusToWinError($return)
            Write-Warning $(New-Object System.ComponentModel.Win32Exception -ArgumentList $Win32ErrorCode)
            BREAK
        }
        #endregion winErrorCode
        #endregion LsaOpenPolicy

        #region LsaAddAccountRights
        ForEach ($Priv in $Privilege) {
            $PrivilegeName = [privileges]::$Priv
            $_UserRights = New-Object LSA_UNICODE_STRING
            $_UserRights.Buffer = $Priv.ToString()
            #SF edts: replaced the two below lines to fix the buffer size
            $_UserRights.Length = ($_UserRights.Buffer.length * [System.Text.UnicodeEncoding]::CharSize)
            $_UserRights.MaximumLength = ($_UserRights.Length + [System.Text.UnicodeEncoding]::CharSize)
            $UserRights = New-Object LSA_UNICODE_STRING[] -ArgumentList 1
            $UserRights[0] = $_UserRights
           Write-Verbose "Removing Privilege: $($PrivilegeName.ToString())"
            $NTStatus = [PoShPrivilege]::LsaRemoveAccountRights(
                $PolicyHandle,
                $SIDPtr,
                $false, #SF edit: originally was true which would delete all privs and the account
                $UserRights,
                1    
            )

            #region winErrorCode
            If ($NTStatus -ne 0) {
                $Win32ErrorCode = [PoShPrivilege]::LsaNtStatusToWinError($return) 
                Write-Warning $(New-Object System.ComponentModel.Win32Exception -ArgumentList $Win32ErrorCode)
                BREAK
            }
        }
        #endregion winErrorCode

        #endregion LsaAddAccountRights

        #region Cleanup
    
        #region Close Policy Handle
        Write-Verbose "Closing policy handle"
        [void][PoShPrivilege]::LsaClose($PolicyHandle)
        #endregion Close Policy Handle

        #region Clear Pointers
        Write-Verbose "Clearing SID pointers"
        [void][System.Runtime.InteropServices.Marshal]::FreeHGlobal($SIDPtr)
        #endregion Clear Pointers

        #endregion Cleanup
    }
}