WMI脚本权限管理指南

在Windows管理指令(WMI)中,权限管理是一个重要的环节,它决定了脚本能访问哪些资源和执行哪些操作。本文将介绍如何通过WMI脚本管理权限,包括使用WMI脚本API和.NET Framework进行权限管理。

权限列表

WMI提供了一系列的权限,这些权限可以在找到。权限可以通过两种方式分配:

  • 使用WMI标识符(moniker)
  • 使用WMI脚本API中的SWbemPrivilege和SWbemPrivilegeSet对象

通常情况下,WMI脚本不需要分配任何权限即可正常工作。例如,以下是一个简单的VBScript脚本,它连接到本地WMI服务并输出应用程序事件日志中的所有事件消息,而不需要分配任何权限:

Set objSWbemServices = GetObject("winmgmts:") Set colEvents = objSWbemServices.ExecQuery("Select * From Win32_NTLogEvent Where LogFile = 'Application'") For Each objEvent In colEvents WScript.Echo objEvent.Message Next

这个脚本使用了最基本的标识符连接到WMI服务,并且没有分配任何权限,但是是否隐式地分配了权限呢?以下是一个测试脚本:

Set objSWbemServices = GetObject("winmgmts:") Set objSWbemPrivileges = objSWbemServices.Security_.Privileges WScript.Echo "WMI privilege count: " & objSWbemPrivileges.Count

输出结果为:

WMI privilege count: 0

因此,无论是显式还是隐式,都没有分配任何权限。这对于应用程序事件日志来说是可以的,但如果尝试枚举安全事件日志中的事件:

Set objSWbemServices = GetObject("winmgmts:") Set colEvents = objSWbemServices.ExecQuery("Select * From Win32_NTLogEvent Where LogFile = 'Security'") WScript.Echo colEvents.Count For Each objEvent In colEvents WScript.Echo objEvent.Message Next

如果没有分配权限,即使安全事件日志中充满了条目,也不会枚举出任何事件,SWbemObjectSet.Count的值为0。要使这个脚本正常工作,需要为SWbemServices分配wbemPrivilegeSecurity(7)权限,以下是使用WMI标识符分配权限的方法:

Set objSWbemServices = GetObject("winmgmts:{(Security)}") Set colEvents = objSWbemServices.ExecQuery("Select * From Win32_NTLogEvent Where LogFile = 'Security'") WScript.Echo colEvents.Count For Each objEvent In colEvents WScript.Echo objEvent.Message Next

当使用标识符添加权限时,权限名称实际上是‘Security’,而不是wbemPrivilegeSecurity。可以在找到其他适合与标识符一起使用的权限名称(在‘Scripting short name’下)。

如何知道获取安全事件日志条目需要特殊权限?这是有文档记录的,因此在编写WMI脚本时阅读WMI类文档是个好主意。

有趣的是,如果不分配权限,脚本将不会工作,但不会有任何错误——SWbemServices.ExecQuery将只返回一个空集合。

以下是另一个没有适当权限就无法工作的示例脚本:

Set objSWbemServices = GetObject("winmgmts:") Set colProcesses = objSWbemServices.ExecQuery("Select * From Win32_Process Where Name = 'sqlservr.exe'") For Each objProcess In colProcesses WScript.Echo objProcess.Terminate Next

SQL Server在SYSTEM账户下运行,因此Win32_Process.Terminate()将返回错误代码2——‘访问被拒绝’,因为没有以SYSTEM账户连接到WMI(这是有文档记录的)。在这种情况下,需要使用wbemPrivilegeDebug(19)。以下是工作的脚本:

Set objSWbemServices = GetObject("winmgmts:{(Debug)}") Set colProcesses = objSWbemServices.ExecQuery("Select * From Win32_Process Where Name = 'sqlservr.exe'") For Each objProcess In colProcesses WScript.Echo objProcess.Terminate Next

备份事件日志文件是另一个需要特殊权限的操作——wbemPrivilegeBackup(16):

Set objSWbemServices = GetObject("winmgmts:") Set colEventLogFiles = objSWbemServices.ExecQuery("Select * From Win32_NTEventLogFile Where LogFileName = 'Application'") For Each objEventLogFile In colEventLogFiles WScript.Echo objEventLogFile.BackupEventLog("C:\\scripts\\Application.evt") Next

如果运行这个脚本,将得到以下错误:

SWbemObjectEx: Access denied

当使用wbemPrivilegeBackup时,脚本将工作:

Set objSWbemServices = GetObject("winmgmts:{(backup)}") Set colEventLogFiles = objSWbemServices.ExecQuery("Select * From Win32_NTEventLogFile Where LogFileName = 'Application'") For Each objEventLogFile In colEventLogFiles WScript.Echo objEventLogFile.BackupEventLog("C:\\scripts\\Application.evt") Next

值得注意的是,WMI在报告缺少权限时并不一致:在第一种情况下根本没有错误,在第二个例子中Win32_Process.Terminate返回了表示缺少权限的错误代码并继续,在第三个脚本中Win32_NTEventLogFile.BackupEventLog导致脚本崩溃——这在调试WMI脚本时并不是很有帮助。

这里还有一些更令人困惑的信息:要备份安全日志文件,需要同时拥有Security和Backup权限。如果只使用Security权限:

Set objSWbemServices = GetObject("winmgmts:{(Security)}") Set colEventLogFiles = objSWbemServices.ExecQuery("Select * From Win32_NTEventLogFile Where LogFileName = 'Security'") For Each objEventLogFile In colEventLogFiles WScript.Echo objEventLogFile.BackupEventLog("C:\\scripts\\Security.evt") Next

将得到‘访问被拒绝’的错误,但如果只使用Backup权限:

Set objSWbemServices = GetObject("winmgmts:{(Backup)}") Set colEventLogFiles = objSWbemServices.ExecQuery("Select * From Win32_NTEventLogFile Where LogFileName = 'Security'") For Each objEventLogFile In colEventLogFiles WScript.Echo objEventLogFile.BackupEventLog("C:\\scripts\\Security.evt") Next

Win32_NTEventLogFile.BackupeventLog将返回5,这是一个在文档中没有列出的错误代码。要使其工作,需要使用两个权限:

Set objSWbemServices = GetObject("winmgmts:{(Security, Backup)}") Set colEventLogFiles = objSWbemServices.ExecQuery("Select * From Win32_NTEventLogFile Where LogFileName = 'Security'") For Each objEventLogFile In colEventLogFiles WScript.Echo objEventLogFile.BackupEventLog("C:\\scripts\\Security.evt") Next

另一种分配WMI权限的方法是使用SWbemPrivilege和SWbemPrivilegeSet对象:

Set objSWbemServices = GetObject("winmgmts:") objSWbemServices.Security_.Privileges.AddAsString "SeSecurityPrivilege" objSWbemServices.Security_.Privileges.AddAsString "SeBackupPrivilege" Set colEventLogFiles = objSWbemServices.ExecQuery("Select * From Win32_NTEventLogFile Where LogFileName = 'Security'") For Each objEventLogFile In colEventLogFiles WScript.Echo objEventLogFile.BackupEventLog("C:\\scripts\\Security.evt") Next

SWbemService有一个名为Security_的属性,它实际上是一个SWbemSecurity对象,该对象又有一个Privileges属性。这是一个SWbemPrivilegeSet对象,可以使用它的AddAsString和Add方法为WMI分配权限。当使用AddAsString时,使用定义的权限名称(所有名称都以Se***开头,如SeDebugPrivilege),当使用Add方法时,使用代表特定权限的整数(例如,对于SeDebugPrivilege,将使用19)。

可以使用SWbemPrivilege对象列出所有可用的权限。上述链接列出了27个可用的权限,可以使用For循环将它们全部添加:

Set objSWbemServices = GetObject("winmgmts:") Set colPrivileges = objSWbemServices.Security_.Privileges For i = 1 To 27 colPrivileges.Add i Next For Each objPrivilege In colPrivileges WScript.Echo objPrivilege.Identifier & vbTab & objPrivilege.Name & vbTab & objPrivilege.DisplayName Next

并使用For..Each列出每个权限的信息。

.NET Framework的System.Management命名空间简化了所有这些:有一个名为ConnectionOptions.EnablePrivileges的属性,当设置为true时,启用所有可能的权限。以下是一个C#示例:

using System; using System.Management; class Program { static void Main() { ManagementScope scope = new ManagementScope(); scope.Options.EnablePrivileges = true; ObjectQuery query = new ObjectQuery(@" Select * From Win32_NtLogEvent " + @" Where LogFile = 'Security'"); ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query); foreach (ManagementObject logEvent in searcher.Get()) { Console.WriteLine(logEvent["Message"]); } } }

对于PowerShell,有一个名为–EnableAllPrivileges的开关用于V2,它也启用所有权限(全部在一行中):

Get-WmiObject Win32_NTLogEvent -filter "LogFile='Security'" -EnableAllPrivileges $Searcher = New-Object System.Management.ManagementObjectSearcher $Searcher.Scope.Options.EnablePrivileges = $true $Searcher.Query = "Select * From Win32_NTLogEvent Where LogFile = 'Security'" foreach ($Event in $Searcher.Get()) { $Event.EventCode $Event.TimeGenerated }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485