您好,KF。 您知道,我们的第一个想法是告诉您使用 ADSI 并尝试在计算机上绑定本地管理员;如果尝试失败,则意味着该计算机上不存在名为 Administrator 的帐户。 其次,有可能是重命名或删除了该帐户。
但是另一方面,我们对此也稍加考虑过。 (是的,一天内有两种想法便是脚本专家的记录。) 假定本地管理员帐户已重命名。 在此情况下,您可能想知道该帐户的新名称。 那么,我们真正想知道的是本地管理员帐户的名称。 仅此而已。
但是如果已重命名了帐户,我们如何才能知道帐户的名称? (此脚本等同于“如果森林中有一棵树倒下了,而附近却没有人听到,那么这棵树在倒下时还会发出声音吗?”) 嗯,当然是通过“众所周知的 SID”的神奇作用。 您可能知道,SID 是“安全标识符”,是分配给计算机上每一个帐户的唯一标识符。 实际上,计算机使用 SID 来跟踪每个帐户: 如果重命名管理员帐户,计算机仍然知道哪个帐户是管理员帐户。 这是因为 SID 不同于名称,它永远不会更改。
这听起来还相当不错,除了以下一点: 如果 SID 是唯一的标识符,那么我们如何才能确定哪个 SID 代表管理员帐户? 这是“众所周知”的部分传入的位置。在计算机上,本地管理员的 SID 将始终以 S-1-5- 开始,以 -500 结束。 (这就是管理员 SID 及诸如 Guest 帐户的 SID 之类的其它 SID 被视为众所周知的原因。) 例如,您可能具有一个类似于下列内容的 SID:
S-1-5-21-1559272821-92556266-1055285598-500
正如您所看到的那样,我们的 SID 以 S-1-5- 开始,以 -500 结束。如果我们能够找到符合该模式的 SID,就找到了我们的本地管理员帐户。
那么,我们能够找到符合该模式的 SID 吗? 是的,通过使用类似于下列内容的脚本便能找到:
strComputer = "."
Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2")
Set colAccounts = objWMIService.ExecQuery _
("Select * From Win32_UserAccount Where LocalAccount = TRUE")
For Each objAccount in colAccounts
If Left (objAccount.SID, 6) = "S-1-5-" and Right(objAccount.SID, 4) = "-500" Then
Wscript.Echo objAccount.Name
End If
Next
|
注意: 此特定脚本只在 Windows XP 和 Windows Server 2003 上有效。我们马上会向您演示在 Windows 2000 Server 或 Windows NT Server 4.0 上执行同一任务的方法。 |
我们首先连接到计算机上的 WMI 服务,然后使用以下查询检索本地计算机帐户的列表:
Set colAccounts = objWMIService.ExecQuery _
("Select * From Win32_UserAccount Where LocalAccount = TRUE")
请注意 Where 子句 Where LocalAccount = TRUE 的用法。 该子句可确保我们只返回本地帐户;我们对浏览域帐户不感兴趣。 这也是该特定脚本不在 Windows 2000 或 Windows NT 4.0 上运行的原因;在 Windows XP 之前未引入 LocalAccount 属性。
返回本地用户帐户集合后,我们要设置 For Each 循环并遍历该集合。 对于每一个帐户,我们可以使用下面一行代码来查看该帐户是否符合众所周知的 SID 模式:
If Left (objAccount.SID, 6) = "S-1-5-" and Right(objAccount.SID, 4) = "-500" Then
正如您所看到的那样,我们仅查看字符串的前六个字符是否等于 S-1-5-、后四个字符是否等于 -500。 如果字符串符合上述要求,就说明我们找到了本地管理员帐户,并将回显帐户名。 否则,我们会继续检查集合中的下一个帐户。
如果您是在 Windows XP 或 Windows Server 2003 上运行脚本,则这样做就可以达到目的。如果您是在 Windows 2000 Server 或 Windows NT Server 4.0 上运行,则可使用此代码的变体。 (这在 Windows XP 和 Windows Server 2003 上也有效。) 在此脚本中,我们首先将计算机的名称分配给变量 strComputer;另外请注意:我们需要使用实际的计算机名而不是圆点(一种指示本地计算机的 WMI 快捷方法)。 我们必须使用计算机名是因为我们要使用此变量来查找具有与计算机名匹配的“域”的帐户。 (这令人感到困惑,但就技术意义来说,计算机是一个域,虽然它显然与 Active Directory 不同。) 尽管圆点可以代表 WMI 中的本地计算机名,但它并不代表域名。 因此,我们必须非常明确地指定计算机名称。
并且,是的,处理本地计算机帐户时域名相当于计算机名称。 如果您具有名为 kmyer 的用户和名为 atl-ws-01 的计算机,则域名将为 atl-ws-01,用户名将为 kmyer。
然后,我们使用修改后的查询来返回帐户的集合,其中 Domain 相当于本地计算机的名称;这将会排除 Active Directory 帐户且仅返回本地帐户。
脚本如下:
strComputer = "atl-ws-01"
Set objWMIService = GetObject("winmgmts://" & strComputer & "/root/cimv2")
Set colAccounts = objWMIService.ExecQuery _
("Select * From Win32_UserAccount Where Domain = '" & strComputer & "'")
For Each objAccount in colAccounts
If Left (objAccount.SID, 6) = "S-1-5-" and Right(objAccount.SID, 4) = "-500" Then
Wscript.Echo objAccount.Name
End If
Next
为什么我们如此关心将返回的集合限制为本地帐户? 嗯,如果没有该子句,Win32_UserAccount 类将会尝试返回 Active Directory 中所有用户帐户的列表以及所有本地用户帐户。 如果您有一或两个(或三个)小时可以消磨,那么没什么,请: 继续并返回 – 并浏览 – 几千个用户帐户(您希望这样)。 否则,您最好将返回的数据只限制为本地帐户。