能否提取Carbon模块中Get-CPrivileges相关代码到自定义PowerShell脚本?
提取Carbon Get-CPrivileges核心实现(无需完整模块)
以下是从Carbon模块中剥离的独立实现,直接调用Windows原生advapi32.dll的LSA(本地安全授权)API读取权限,完全避免使用SecEdit和临时文件,也不需要依赖Carbon的冗余模块:
完整可运行代码
Add-Type -TypeDefinition @" using System; using System.Runtime.InteropServices; using System.Security.Principal; public static class LsaPrivilegeHelper { private const uint STATUS_SUCCESS = 0; private const uint STATUS_NO_MORE_ENTRIES = 0x8000001A; private const int POLICY_VIEW_LOCAL_INFORMATION = 0x00000001; [StructLayout(LayoutKind.Sequential)] private struct LSA_UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] private struct LSA_OBJECT_ATTRIBUTES { public int Length; public IntPtr RootDirectory; public IntPtr ObjectName; public uint Attributes; public IntPtr SecurityDescriptor; public IntPtr SecurityQualityOfService; } [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint LsaOpenPolicy( ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, int DesiredAccess, out IntPtr PolicyHandle); [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] private static extern uint LsaLookupNames2( IntPtr PolicyHandle, uint Flags, uint Count, ref LSA_UNICODE_STRING Names, out IntPtr ReferencedDomains, out IntPtr Sids); [DllImport("advapi32.dll", SetLastError = true)] private static extern uint LsaEnumerateAccountRights( IntPtr PolicyHandle, IntPtr Sid, out IntPtr UserRights, out uint Count); [DllImport("advapi32.dll")] private static extern uint LsaNtStatusToWinError(uint Status); [DllImport("advapi32.dll")] private static extern uint LsaClose(IntPtr Handle); [DllImport("kernel32.dll")] private static extern void LocalFree(IntPtr Mem); private static LSA_UNICODE_STRING CreateUnicodeString(string value) { LSA_UNICODE_STRING str = new LSA_UNICODE_STRING(); if (value != null) { str.Buffer = Marshal.StringToHGlobalUni(value); str.Length = (ushort)(value.Length * 2); str.MaximumLength = (ushort)(str.Length + 2); } return str; } private static void FreeUnicodeString(ref LSA_UNICODE_STRING str) { if (str.Buffer != IntPtr.Zero) { LocalFree(str.Buffer); str.Buffer = IntPtr.Zero; } } public static string[] GetUserPrivileges(string username) { IntPtr policyHandle = IntPtr.Zero; IntPtr sidPtr = IntPtr.Zero; IntPtr userRightsPtr = IntPtr.Zero; IntPtr referencedDomainsPtr = IntPtr.Zero; try { LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING(); LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES(); objectAttributes.Length = Marshal.SizeOf(objectAttributes); uint status = LsaOpenPolicy(ref systemName, ref objectAttributes, POLICY_VIEW_LOCAL_INFORMATION, out policyHandle); if (status != STATUS_SUCCESS) throw new System.ComponentModel.Win32Exception((int)LsaNtStatusToWinError(status)); LSA_UNICODE_STRING userName = CreateUnicodeString(username); try { status = LsaLookupNames2(policyHandle, 0, 1, ref userName, out referencedDomainsPtr, out sidPtr); if (status != STATUS_SUCCESS) throw new System.ComponentModel.Win32Exception((int)LsaNtStatusToWinError(status)); } finally { FreeUnicodeString(ref userName); } uint rightsCount; status = LsaEnumerateAccountRights(policyHandle, sidPtr, out userRightsPtr, out rightsCount); if (status != STATUS_SUCCESS && status != STATUS_NO_MORE_ENTRIES) throw new System.ComponentModel.Win32Exception((int)LsaNtStatusToWinError(status)); string[] privileges = new string[rightsCount]; for (uint i = 0; i < rightsCount; i++) { IntPtr rightPtr = Marshal.ReadIntPtr(userRightsPtr, (int)i * IntPtr.Size); LSA_UNICODE_STRING rightStr = Marshal.PtrToStructure<LSA_UNICODE_STRING>(rightPtr); privileges[i] = Marshal.PtrToStringUni(rightStr.Buffer); } return privileges; } finally { if (policyHandle != IntPtr.Zero) LsaClose(policyHandle); if (userRightsPtr != IntPtr.Zero) LocalFree(userRightsPtr); if (sidPtr != IntPtr.Zero) LocalFree(sidPtr); if (referencedDomainsPtr != IntPtr.Zero) LocalFree(referencedDomainsPtr); } } } "@ function Get-CPrivileges { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Username ) try { $privileges = [LsaPrivilegeHelper]::GetUserPrivileges($Username) [PSCustomObject]@{ Username = $Username Privileges = $privileges } } catch { Write-Error "Failed to retrieve privileges for $Username : $_" } }
使用说明
- 直接在PowerShell中运行上述代码,定义辅助类和函数
- 调用函数获取指定用户的权限,包括
SeBatchLogonRight:# 获取本地账户权限 Get-CPrivileges -Username "LocalAdmin" # 获取域账户权限 Get-CPrivileges -Username "CORP\DomainUser"
关键说明
- 完全依赖Windows原生
advapi32.dll,无需额外DLL或第三方模块 - 直接通过LSA API读取权限,不会生成任何临时文件,避免
SecEdit的安全风险 - 支持本地账户和域账户,返回所有已分配的权限名称(包括登录权限、特权等)
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

