You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何读取计算机账户安全令牌以获取其组成员身份

获取计算机账户安全令牌的组成员身份

要获取计算机账户的组成员身份,不能直接用[Security.Principal.WindowsIdentity]::GetCurrent()——这个方法返回的是当前用户线程的安全令牌,而非计算机账户的令牌。DeviceClaims返回空也是因为当前令牌不属于设备(计算机)身份。

以下是不依赖Active Directory的PowerShell解决方案,通过调用Windows原生API获取计算机账户的令牌并枚举组:

实现步骤

  1. 定义所需的Windows API和结构体(用于P/Invoke)
  2. 获取系统核心进程(如lsass.exe)的句柄,它运行在本地系统上下文,包含计算机账户的组信息
  3. 打开该进程的安全令牌
  4. 查询令牌中的组信息并解析输出

完整代码

# 定义API和结构体
Add-Type @"
using System;
using System.Runtime.InteropServices;

public class TokenUtils {
    public enum TOKEN_INFORMATION_CLASS {
        TokenGroups = 2
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SID_AND_ATTRIBUTES {
        public IntPtr Sid;
        public uint Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct TOKEN_GROUPS {
        public uint GroupCount;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public SID_AND_ATTRIBUTES[] Groups;
    }

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);

    [DllImport("advapi32.dll", SetLastError = true)]
    public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, uint TokenInformationLength, out uint ReturnLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool CloseHandle(IntPtr hObject);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool ConvertSidToStringSid(IntPtr Sid, out IntPtr StringSid);
}
"@

# 定义令牌访问权限
$TOKEN_QUERY = 0x0008

# 获取lsass进程句柄(本地系统运行的进程)
$lsassProcess = Get-Process lsass -ErrorAction Stop
$processHandle = $lsassProcess.Handle

# 打开进程令牌
if (-not [TokenUtils]::OpenProcessToken($processHandle, $TOKEN_QUERY, [ref]$tokenHandle)) {
    throw "OpenProcessToken failed: $([System.ComponentModel.Win32Exception][System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
}

try {
    # 先获取所需的缓冲区大小
    [TokenUtils]::GetTokenInformation($tokenHandle, [TokenUtils+TOKEN_INFORMATION_CLASS]::TokenGroups, [IntPtr]::Zero, 0, [ref]$returnLength) | Out-Null

    # 分配缓冲区
    $buffer = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($returnLength)
    try {
        if (-not [TokenUtils]::GetTokenInformation($tokenHandle, [TokenUtils+TOKEN_INFORMATION_CLASS]::TokenGroups, $buffer, $returnLength, [ref]$returnLength)) {
            throw "GetTokenInformation failed: $([System.ComponentModel.Win32Exception][System.Runtime.InteropServices.Marshal]::GetLastWin32Error())"
        }

        # 解析TOKEN_GROUPS结构体
        $tokenGroups = [System.Runtime.InteropServices.Marshal]::PtrToStructure($buffer, [Type][TokenUtils+TOKEN_GROUPS])
        $groupCount = $tokenGroups.GroupCount

        # 遍历所有组
        for ($i = 0; $i -lt $groupCount; $i++) {
            # 计算每个SID_AND_ATTRIBUTES的偏移
            $sidOffset = $buffer + [System.Runtime.InteropServices.Marshal]::SizeOf([Type][TokenUtils+TOKEN_GROUPS]) + ($i * [System.Runtime.InteropServices.Marshal]::SizeOf([Type][TokenUtils+SID_AND_ATTRIBUTES]))
            $sidAndAttr = [System.Runtime.InteropServices.Marshal]::PtrToStructure($sidOffset, [Type][TokenUtils+SID_AND_ATTRIBUTES])

            # 将SID转换为字符串
            if ([TokenUtils]::ConvertSidToStringSid($sidAndAttr.Sid, [ref]$stringSid)) {
                $sidString = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($stringSid)
                # 获取SID对应的账户名
                $account = New-Object System.Security.Principal.SecurityIdentifier($sidString)
                $groupName = $account.Translate([System.Security.Principal.NTAccount]).Value
                Write-Output "组名: $groupName | SID: $sidString | 属性: $($sidAndAttr.Attributes)"
                [System.Runtime.InteropServices.Marshal]::FreeHGlobal($stringSid)
            }
        }
    }
    finally {
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($buffer)
    }
}
finally {
    [TokenUtils]::CloseHandle($tokenHandle)
}

代码说明

  • 借助lsass.exe进程(系统核心进程,运行在本地系统上下文)获取包含计算机账户组信息的令牌
  • 通过OpenProcessToken和GetTokenInformationAPI提取令牌中的组数据
  • 将SID转换为可读的组名,全程无需查询Active Directory

内容的提问来源于stack exchange,提问作者user2871239

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 10:55:29