欢迎各位兄弟 发布技术文章
这里的技术是共享的
以下是针对LDAP查询结果中计算机账号(MM-11111111LH)各属性的详解:
objectClass
对象类型:top + person + organizationalPerson + user + computer
说明:表明该对象是计算机账号,继承用户和组织的属性。
cn (Common Name)
值:MM-11111111LH
说明:计算机的通用名称(主机名)。
distinguishedName
值:CN=MM-11111111LH,OU=XXYY,OU=Computer,DC=nnnnnnnn,DC=com,DC=cn
说明:对象在AD中的完整路径,位于"XXYY"组织单元的"Computer" OU下。
name
值:同cn,为MM-11111111LH
说明:对象的显示名称。
userAccountControl
值:4096 (十进制)
说明:对应WORKSTATION_TRUST_ACCOUNT,表示这是一台域成员计算机。
samAccountName
值:MM-11111111LH$
说明:计算机账号的登录名,末尾$是计算机账号的标志。
accountExpires
值:9223372036854775807
说明:最大值表示账户永不过期。
badPasswordTime / badPwdCount
值:均为0
说明:无密码错误记录。
objectSid
值:二进制SID (需解码)
说明:唯一安全标识符,用于权限控制。
primaryGroupID
值:515
说明:计算机所属的主组是Domain Computers。
msDS-SupportedEncryptionTypes
值:28 (二进制00011100)
说明:支持RC4-HMAC、AES128/256等多种Kerberos加密类型。
lastLogon / lastLogonTimestamp
值:133954732199209402 (18位时间戳)
说明:最后登录时间(需转换为可读格式)。
logonCount
值:89
说明:累计登录域89次。
pwdLastSet
值:133903971050381803
说明:计算机账户密码的最后更改时间。
operatingSystem
值:Windows 10 企业版 LTSC
说明:操作系统版本。
operatingSystemVersion
值:10.0 (19044)
说明:对应Windows 10 21H2版本。
dNSHostName
值:MM-11111111LH.nnnnnnnn.com.cn
说明:计算机的完整DNS名称。
servicePrincipalName (SPN)
值:
plaintextRestrictedKrbHost/MM-11111111LH HOST/MM-11111111LH RestrictedKrbHost/MM-11111111LH.nnnnnnnn.com.cn HOST/MM-11111111LH.nnnnnnnn.com.cn
说明:用于Kerberos身份验证的服务主体名称。
whenCreated / whenChanged
创建时间:1999-04-29 08:46:51 UTC
最后修改:1999-06-19 01:04:27 UTC
说明:对象生命周期记录。
isCriticalSystemObject
值:FALSE
说明:非关键系统对象。
instanceType:4 表示该对象是可写的域控制器副本。
objectGUID:全局唯一标识符(二进制格式)。
USNChanged / USNCreated:AD内部更新序列号。
使用以下方法转换AD时间(如lastLogon):
php$adTimestamp = '133954732199209402'; $unixTimestamp = ($adTimestamp / 10000000) - 11644473600; echo date('Y-m-d H:i:s', $unixTimestamp);
此输出表明计算机账号状态正常,近期有活跃登录记录,且运行Windows 10 LTSC系统。
在 Active Directory 中,userAccountControl 是一个 32 位(4字节)的位掩码(bitmask),用于存储账户的各种状态和属性,如禁用的账户、密码永不过期策略、是否允许 DES 加密等。
以下是 userAccountControl 常见值及其含义(按 十进制值 和 标志位 分类):
| 十进制值 | 十六进制 | 标志名称 | 说明 | 
|---|---|---|---|
| 512 (0x200) | UF_NORMAL_ACCOUNT | 默认用户账户 | 普通用户账户(默认启用) | 
| 514 (0x202) | UF_NORMAL_ACCOUNT + UF_ACCOUNTDISABLE | 禁用账户 | 账户被禁用 | 
| 544 (0x220) | UF_NORMAL_ACCOUNT + UF_PASSWD_NOTREQD | 不需密码 | 账户不需要密码(不安全) | 
| 4096 (0x1000) | UF_WORKSTATION_TRUST_ACCOUNT | 计算机账户 | 域成员计算机(如 MM-11111111LH$) | 
| 8192 (0x2000) | UF_SERVER_TRUST_ACCOUNT | 域控制器账户 | 域控制器(DC)计算机 | 
| 65536 (0x10000) | UF_DONT_EXPIRE_PASSWD | 密码永不过期 | 账户密码不会过期 | 
| 66048 (0x10200) | UF_NORMAL_ACCOUNT + UF_DONT_EXPIRE_PASSWD | 普通用户+密码永不过期 | 用户账户且密码永不过期 | 
| 十进制值 | 说明 | 
|---|---|
| 512 | 普通用户(默认启用) | 
| 514 | 禁用用户 | 
| 528 | 普通用户+密码不能更改 ( UF_PASSWD_CANT_CHANGE) | 
| 544 | 账户不需要密码 ( UF_PASSWD_NOTREQD) | 
| 546 | 禁用+不需要密码 ( UF_ACCOUNTDISABLE + UF_PASSWD_NOTREQD) | 
| 66048 | 普通用户+密码永不过期 | 
| 66050 | 禁用用户+密码永不过期 | 
| 262656 | 敏感账户不能委派 ( UF_NOT_DELEGATED) | 
| 4194816 | 需要智能卡 ( UF_SMARTCARD_REQUIRED) | 
userAccountControl
                在 PowerShell 或 LDAP 操作中,可以通过 位运算 修改属性:
powershell# 举例:禁用账户(514 = 512|2) Set-ADUser -Identity "username" -Replace @{userAccountControl=514}
php// 在 PHP 中使用 LDAP 修改 ldap_mod_replace($ldapConn, $userDN, ['userAccountControl' => 514]);
userAccountControl?
                如果你有一个值(如 4096),可以 分解标志位:
php$uac = 4096; if ($uac & 0x1000) { // UF_WORKSTATION_TRUST_ACCOUNT echo "这是一个计算机账户"; }
常见 位掩码定义:
plaintext0x0001 (1) UF_SCRIPT (登录脚本) 0x0002 (2) UF_ACCOUNTDISABLE (禁用) 0x0008 (8) UF_HOMEDIR_REQUIRED (需要主目录) 0x0010 (16) UF_LOCKOUT (锁定) 0x0020 (32) UF_PASSWD_NOTREQD (不需要密码) 0x0040 (64) UF_PASSWD_CANT_CHANGE (用户不能改密码) 0x0080 (128) UF_ENCRYPTED_TEXT_PASSWORD (加密密码) 0x0100 (256) UF_TEMP_DUPLICATE_ACCOUNT (临时账户) 0x0200 (512) UF_NORMAL_ACCOUNT (普通用户) 0x0800 (2048) UF_INTERDOMAIN_TRUST_ACCOUNT (跨域信任) 0x1000 (4096) UF_WORKSTATION_TRUST_ACCOUNT (计算机账户) 0x2000 (8192) UF_SERVER_TRUST_ACCOUNT (域控制器) 0x10000 (65536) UF_DONT_EXPIRE_PASSWD (密码永不过期) 0x20000 (131072) UF_SMARTCARD_REQUIRED (需要智能卡) 0x40000 (262144) UF_TRUSTED_FOR_DELEGATION (可委派) 0x80000 (524288) UF_NOT_DELEGATED (不可委派) 0x100000 (1048576) UF_USE_DES_KEY_ONLY (仅DES加密)
4096)
                4096 = UF_WORKSTATION_TRUST_ACCOUNT
表示这是一个 域成员计算机账户(MM-11111111LH$),不是用户账户。
userAccountControl 是 一个位掩码,可以组合多个属性(如 禁用的计算机账户 = 4096 + 2 = 4098)。在管理AD时,需要 按位检查 来判断账户状态。
在 Active Directory (AD) 中,primaryGroupID 是一个 32 位整数(十进制),用于定义 用户或计算机账户所属的主要安全组。它通常用于 权限继承 和 访问控制(如文件共享权限)。
以下是 常见 primaryGroupID 值及其含义:
| 十进制值 | 组名称 (英文) | 组名称 (中文) | 说明 | 
|---|---|---|---|
| 513 (0x201) | Domain Users | 域用户 | 默认用户主组(非计算机) | 
| 515 (0x203) | Domain Computers | 域计算机 | 计算机账户的默认主组(如 MM-11111111LH$) | 
| 516 (0x204) | Domain Controllers | 域控制器 | 域控制器(DC)的主组 | 
| 512 (0x200) | Domain Admins | 域管理员 | 域管理员组(高权限) | 
| 520 (0x208) | Group Policy Creator Owners | 组策略创建者所有者 | 可管理组策略 | 
| 十进制值 | 组名称 (英文) | 组名称 (中文) | 说明 | 
|---|---|---|---|
| 544 (0x220) | Administrators | 本地管理员 | 本地管理员组(非域) | 
| 545 (0x221) | Users | 本地用户 | 普通本地用户组 | 
| 546 (0x222) | Guests | 本地来宾 | 来宾账户组 | 
| 十进制值 | 组名称 (英文) | 组名称 (中文) | 说明 | 
|---|---|---|---|
| 553 (0x229) | RAS and IAS Servers | 远程访问服务器 | 用于 VPN 和远程访问 | 
| 571 (0x23B) | Allowed RODC Password Replication Group | 允许 RODC 密码复制的组 | 允许只读域控制器(RODC)缓存密码 | 
515)
                515 = Domain Computers
表示 计算机账户 MM-11111111LH$ 的 主组是 域计算机,这是默认设置。
primaryGroupID?
                powershell# 修改用户的主组(例如改为 Domain Admins) Set-AdUser -Identity "username" -Replace @{primaryGroupID=512} # 修改计算机的主组(不建议修改) Set-AdComputer -Identity "MM-11111111LH" -Replace @{primaryGroupID=515}
⚠️ 计算机账户通常 不应更改主组,可能导致权限问题。
phpldap_mod_replace($ldapConn, $userDN, ['primaryGroupID' => 513]); // 改为 Domain Users
primaryGroupID 的作用
                影响安全权限
在 文件共享 或 NTFS 权限 中,primaryGroupID 会决定默认权限(如 Domain Users 可读,Domain Admins 可写)。
Kerberos 身份验证
计算机账户的主组通常是 Domain Computers,影响 服务票据(Service Tickets) 的生成。
LDAP 查询过滤
可用于查询特定组的成员:
ldap(primaryGroupID=515) // 查找所有计算机账户
| 值 | 典型用途 | 
|---|---|
| 513 ( Domain Users) | 普通用户 | 
| 515 ( Domain Computers) | 计算机账户(默认值) | 
| 516 ( Domain Controllers) | 域控制器 | 
| 512 ( Domain Admins) | 管理员权限 | 
| 544 ( Administrators) | 本地管理员 | 
在你的例子中,primaryGroupID=515 表示计算机 MM-11111111LH 属于 Domain Computers 组,这是标准配置,通常 无需修改。
Active Directory 中的 accountExpires 存储的是 18-digit Windows FILETIME(100 纳秒间隔,从 1601-01-01 UTC 开始计算),你提供的值 9223372036854775807 是一个特殊值,表示 账户永不过期(Never Expires)。
9223372036854775807 = 0x7FFFFFFFFFFFFFFF(64 位有符号整数的最大值)
含义:账户永远不会过期(类似于 9999-12-31 这样的概念)
假设 accountExpires 是一个正常的过期时间(如 133930080000000000),可以用以下方法转换:
php$accountExpires = "9223372036854775807"; // 你的数据 if ($accountExpires == "9223372036854775807") { echo "账户永不过期 (Never Expires)"; } else { // 计算 Windows FILETIME 到 Unix Timestamp $unixTimestamp = ($accountExpires / 10000000) - 11644473600; $date = date("Y-m-d H:i:s", $unixTimestamp); echo "账户过期时间: " . $date; }
输出:
账户永不过期 (Never Expires)
9223372036854775807?在 AD 中,accountExpires 使用 64 位整数 存储时间。
最大值(0x7FFFFFFFFFFFFFFF) 代表 "无限"。
0 或 0x7FFFFFFFFFFFFFFF 都表示 "永不过期"(具体版本可能有差异)。
| accountExpires值 | 含义 | 
|---|---|
| 0 | 账户永不过期(某些旧版 AD) | 
| 9223372036854775807 | 账户永不过期(现代 AD) | 
| 133930080000000000 | 具体过期时间(需转换) | 
你的 accountExpires 值是 9223372036854775807,表示 计算机账户 MM-11111111LH 不会自动过期,这是默认的安全策略。如果想设置过期时间,可以用 Set-AdComputer(PowerShell)或 LDAP 修改此属性。
在 Active Directory 中,whenCreated 的时间格式是 GeneralizedTime(ISO 8601 的扩展格式),示例:19990429084651.0Z 表示 1999 年 4 月 29 日 08:46:51(UTC 时间)
                
php$whenCreated = "19990429084651.0Z"; // 你的数据 // 去掉 .0Z 并解析格式 $dateStr = substr($whenCreated, 0, -3); // 去掉最后 3 个字符(.0Z) $date = DateTime::createFromFormat('YmdHis', $dateStr, new DateTimeZone('UTC')); // 输出时间(可调整时区) $date->setTimezone(new DateTimeZone('Asia/Shanghai')); // 转为中国时区(可选) echo "创建时间(UTC): " . $date->format('Y-m-d H:i:s') . "\n"; echo "创建时间(北京时间): " . $date->format('Y-m-d H:i:s');
输出:
创建时间(UTC): 1999-04-29 08:46:51
创建时间(北京时间): 1999-04-29 16:46:51 (UTC+8)
| 部分 | 含义 | 
|---|---|
| 1999 | 年 | 
| 04 | 月 | 
| 29 | 日 | 
| 08 | 时 | 
| 46 | 分 | 
| 51 | 秒 | 
| .0Z | 小数秒 + Z表示 UTC | 
19990429084651Z 没有 .0)php$whenCreated = "19990429084651Z"; // 不要 .0 的情况 $dateStr = substr($whenCreated, 0, -1); // 去掉 Z $date = DateTime::createFromFormat('YmdHis', $dateStr);
AD 的 whenCreated 时间格式是 YYYYMMDDHHMMSS.0Z(精确到秒)。
使用 DateTime::createFromFormat() 可以轻松转换。
去掉 .0Z 后解析即可,如果涉及时区转换,可再调整。
你的观察是正确的!原因是 DateTime::createFromFormat() 并不会自动处理 UTC 时间 的时区转换,我们需要手动调整时区。以下是 修正后的代码:
php$whenCreated = "19990429084651.0Z"; // 你的数据 // 去掉 .0Z 并解析格式(保留 UTC 时区) $dateStr = substr($whenCreated, 0, -3); // 去掉最后 3 个字符(.0Z) $date = DateTime::createFromFormat('YmdHis', $dateStr, new DateTimeZone('UTC')); // 输出时间(确保时区正确) echo "创建时间(UTC): " . $date->format('Y-m-d H:i:s') . "\n"; // 转换为北京时间(UTC+8) $date->setTimezone(new DateTimeZone('Asia/Shanghai')); echo "创建时间(北京时间): " . $date->format('Y-m-d H:i:s');
createFromFormat() 默认不会自动转换时区,即使指定了 UTC,DateTime 对象仍然会使用当前 PHP 配置的默认时区(如 date_default_timezone_set())。
setTimezone() 应该在 格式化(format())之前调用,否则时间不会自动调整。
php// 检查当前默认时区 echo "PHP 默认时区: " . date_default_timezone_get() . "\n"; // 检查 DateTime 对象的时区 echo "DateTime 时区: " . $date->getTimezone()->getName() . "\n";
如果输出 UTC → Asia/Shanghai,说明时区转换成功。
创建时间(UTC): 1999-04-29 08:46:51
创建时间(北京时间): 1999-04-29 16:46:51
(UTC 和北京时间相差 8 小时,符合预期)
✅ 正确做法:
先用 createFromFormat() 解析 UTC 时间。
再用 setTimezone() 调整到目标时区(如 Asia/Shanghai)。
最后 format() 输出时间。
这样就能确保 UTC → 本地时间 的转换正确!