欢迎各位兄弟 发布技术文章
这里的技术是共享的
以下是针对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 → 本地时间 的转换正确!