c# wmi远程调用服务器命令,并返回命令结果,如何获取命令结果?

c# wmi远程调用服务器命令,并返回命令结果,如何获取命令结果?,第1张

如果你不介意用第三方工具的话,那么介绍你一个微软合作伙伴赛门铁克出品的鼎鼎有名的psexec。该工具可以简单的远程执行命令/程序

比方说你想远程操作192.168.0.102上面D盘根目录下的名叫abc.cmd的批处理文件,并且得到输出结果,你可以这样写代码。

Process myProcess = new Process()

myProcess.StartInfo.UseShellExecute = false

myProcess.StartInfo.RedirectStandardOutput = true

myProcess.StartInfo.FileName = "psexec"

myProcess.StartInfo.Arguments = @"\\192.168.0.102 -u Administrator -p 123456 cmd /c d:\abc.cmd"

myProcess.Start()

myProcess.WaitForExit()

string strRst = myProcess.StandardOutput.ReadToEnd()

在本机测试时好的,但是连接远程服务器时一直提示“RPC 服务器不可用。 (异常来自 HRESULT:0x800706BA)”,开始怀疑相关服务没启动,检查后发现服务已经启动且状态正常。关闭服务器上的防火墙测试,程序运行正常,开启防火墙就会报上面的错误,确定是防火墙阻止了远程的连接,在网上找了些资料,最终找到一条解决方法:使用命令:netsh firewall set service RemoteAdmin 使防火墙允许远程的登录,开启防火墙,测试程序运行正常。

WMI 最初于1998年作为一个附加组件与 Windows NT 4.0 Service Pack 4 一起发行,是内置在Windows 2000、 Windows XP和Windows Server 2003 系列操作系统中核心的管理支持技术。基于由 Distributed Management Task Force (DMTF) 所监督的业界标准,WMI是一种规范和基础结构,通过它可以访问、配置、管理和监视几乎所有的Windows资源。大多用户习惯于使用众多的图形化管理工具来管理Windows资源,在WMI之前这些工具都是通过 Win32应用程序编程接口(Application ProgrammingInterfaces,API)来访问和管理Windows资源的。只要你熟悉系统编程你就知道API有多么重要。但是大多数脚本语言都不能直接调用Win32 API,WMI的出现使得系统管理员可以通过一种简便的方法即利用常见的脚本语言实现常用的系统管理任务。

利用WMI需要和脚本如WSH和VBScript结合起来,可以实现的功能大家可以看微软的MSDN文档。

在编写我们自己的脚本之前,我们需要对WMI的体系结构有个基本的了解。如图一:(1.gif)

在WMI 体系结构中我们最需要关心的就是WMI提供程序,WMI提供程序在WMI和托管资源之间扮演着中间方的角色。提供程序代表使用者应用程序和脚本从WMI托管资源请求信息,并发送指令到WMI托管资源。下面是我们利用WMI编程经常要用到的WMI内置提供程序清单,以供编程参考。

1.Active Directory提供程序

链接库文件:dsprov.dll

命名空间:root\directory\ldap

作用:将Active Directory 对象映射到 WMI。

2.事件日志提供程序

链接库文件:ntevt.dll

命名空间:root\cimv2

作用:管理 Windows 事件日志,例如,读取、备份、清除、复制、删除、监视、重命名、压缩、解压缩和更改事件日志设置。

3.注册表提供程序

链接库文件:stdprov.dll

命名空间:root\default

作用:读取、写入、枚举、监视、创建、删除注册表项和值。

4.Win32 提供程序

链接库文件:cimwin32.dll

命名空间:root\cimv2

作用:提供关于计算机、磁盘、外围设备、文件、文件夹、文件系统、网络组件、操作系统、打印机、进程、安全性、服务、共享、SAM 用户及组,以及更多资源的信息。

5.Windows 安装程序提供程序

链接库文件:msiprov.dll

命名空间:root\cimv2

作用:提供对已安装软件信息的访问。

从上面可以看出在WMI中类(即内置提供程序)被分组到命名空间中,命名空间可以看成是一个组。比如,命名空间 root\cimv2 包括大部分表示通常与计算机和操作系统相关联的资源的类。在使用类的时候要说明类所在的命名空间。类由属性和方法构成。这是可视化编程中的两个重要的概念。属性描述的是对象的状态,方法是对象可以执行的操作。

理论知识学起来很枯燥,下面让我们边分析高手的脚本源码边进行理论知识的巩固吧。

二:解析RTCS.VBS主要代码

=====================================================================================

有时候阅读别人的源码未尝不是一个好而且快捷的办法,下面就让我们来认真学习zzzEVAzzz编写的一个可以远程开启telnet服务的脚本RTCS.VBS。

该脚本可以直接访问目标的WMI,不依赖于目标的ipc$,实现远程开启/关闭目标telnet服务,为了方便大家学习我抽出了最主要的代码,具体分析如下:

set objlocator=createobject("wbemscripting.swbemlocator")

//创建WbemScripting.SwbemLocator对象(脚本接口)。

//可以看出WMI其实就是把Com组件WbemScripting.SWbemLocator封装起来罢了。

set objswbemservices=objlocator.connectserver(ipaddress,"root/default",username,password)

//通过ConnectServer函数请求连接到WMI控件服务上,root/default为命名空间。

set objinstance=objswbemservices.get("stdregprov")

//建立访问注册表的实例。

set objmethod=objinstance.methods_("SetDWORDvalue")

//建立可以更改注册表键值的方法。

set objinparam=objmethod.inparameters.spawninstance_()

//MethodData.InParameters用于获取或设置方法的输入参数。这里用spawninstance方法为它建立一个子实例,下面就可以将参数值赋予这个对象的属性。

objinparam.hdefkey=&h80000002

//hdefkey表示根键,根键的十六制值如下:

//HKEY_CLASSES_ROOT (&H80000000)

//HKEY_CURRENT_USER (&H80000001)

//HKEY_LOCAL_MACHINE (&H80000002)

//HKEY_USERS (&H80000003)

//HKEY_CURRENT_CONFIG (&H80000005)

objinparam.ssubkeyname="SOFTWARE\Microsoft\TelnetServer\1.0"

//ssubkeyname表示子键。

objinparam.svaluename="NTLM"

//svaluename表示属性名。

objinparam.uvalue=ntlm

//uvalue表示键值。

set objoutparam=objinstance.execmethod_("SetDWORDvalue",objinparam)

//利用execmethod执行方法,这里才真正改写了注册表。

//下面是修改telnet服务的TelnetPort值,原理同上。

objinparam.svaluename="TelnetPort"

objinparam.uvalue=port

set objoutparam=objinstance.execmethod_("SetDWORDvalue",objinparam)

修改telnet的注册表部分就完成了,将NTLM和TelnetPort进行了修改,要是对方的telnet服务没有开启呢?下面就需要根据telnet的具体情况,来启动telnet服务,继续看代码。

//首先查询远程主机上tlntsvr的启动方式。

set objswbemservices=objlocator.connectserver(ipaddress,"root\cimv2",username,password)

//win32_service类在root\cimv2命名空间中,作用没忘记吧?快看基础知识呵。

set colinstances=objswbemservices.execquery("select * from win32_service where name='tlntsvr'")

//注意:查询都是通过枚举来实现的。

for each objinstance in colinstances

if objinstance.startmode="Disabled" then

set objmethod=objinstance.methods_("changestartmode")

//创建changestartmode方法来改变tlntsvr的启动方式。

set objinparam=objmethod.inparameters.spawninstance_()

objinparam.startmode="Manual"

//将启动方式改为手动方式。

set objoutparam=objinstance.execmethod_("changestartmode",objinparam)

end if

//下面启动我们的telnet服务。这里zzzEVAzzz的思路好象有点不对,也不知道是不是他的疏忽,我个人认为当telnet服务已经启动时不应该用stopservice方法停止服务。

if objinstance.started=true then

intstatus=objinstance.stopservice()

//stopservice是WMI中用于停止服务实例的服务的方法。

else

intstatus=objinstance.startservice()

end if

next

三:手把手教你编写WMI版本的ROTS.vbs来开启3389

=====================================================================================

zzzVEAzzz 的脚本就分析到这里吧,怎么样?很EASY吧?!我相信大家现在一定蠢蠢欲动了?:)好,一起来写一个什么程序呢?ROTS.vbs我想大家一定都用过吧?什么东东啊?我……砸!大家应该知道这个ROTS是有它的使用条件的,不仅要有管理员帐号,还要允许进行ipc连接,在这个到处都是墙的年代,ipc 早就不实用了,而且ROTS.vbs早就被查杀了,那该怎么办?当然是自己动手了。能不能实现ROTS的一样的远程开启3389的功能而不受ipc的限制呢?答案自从我写了这篇文章后成为肯定的,哈哈,吹吹了。

当然我们也是要求系统至少是2000server及以上的,最近看到有个软件可以给2000pro开3389,由于比较忙,也没怎么去理它,这里我们暂且不说它,知道了原理一样好办。

开启3389有个注册表导入的方法,其它一些软件的开法,我想也大多是通过修改注册表实现的。这个方法需要导入如下的注册表:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\netcache]

"Enabled"="0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]

"ShutdownWithoutLogon"="0"

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]

"EnableAdminTSRemote"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]

"TSEnabled"=dword:00000001

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TermDD]

"Start"=dword:00000002

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TermService]

"Start"=dword:00000002

[HKEY_USERS\.DEFAULT\Keyboard Layout\Toggle]

"Hotkey"="1"

原理知道了就没什么难的了,先理清我们的思路,我们的主要任务是更改注册表里的键值。首先是创建WMI对象,然后是连接到远程WMI服务器,最后修改注册表键值。

部分主要代码如下(完整的代码和详细的注释请看附带的软件包)

on error resume next

//防止出现意外。

set outstreem=wscript.stdout

if (lcase(right(wscript.fullname,11))="wscript.exe") then

set objShell=wscript.createObject("wscript.shell")

objShell.Run("cmd.exe /k cscript //nologo "&chr(34)&wscript.scriptfullname&chr(34))

//cmd后带/K参数表示执行字符串指定的命令。

wscript.quit

end if

//进行简单的检查。

if wscript.arguments.count<3 then

usage()

wscript.echo "Not enough parameters."

wscript.quit

end if

//取出参数,分别赋予几个变量。

ipaddress=wscript.arguments(0)

username=wscript.arguments(1)

password=wscript.arguments(2)

option=wscript.arguments(3)

usage()

下面是核心代码,也是实现远程修改注册表的功能,我这里给出另外一种实现的方式,对照前面的代码很容易理解,我就只作简单的解释了。详细情况可以参阅MSDN文档中关于StdRegProv类的说明。

const HKEY_LOCAL_MACHINE = &H80000002

const HKEY_USERS=&H80000003

strComputer = ipaddress

//获取wmi对象

Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" &_

strComputer &"\root\default:StdRegProv")

strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\netcache"

strValueName = "Enabled"

strValue=0

oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

strKeyPath = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"

strValueName = "ShutdownWithoutLogon"

strValue=0

oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

strKeyPath = "SOFTWARE\Policies\Microsoft\Windows\Installer"

strValueName = "EnableAdminTSRemote"

strValue=1

oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

strKeyPath = "SYSTEM\CurrentControlSet\Control\Terminal Server"

strValueName = "TSEnabled"

strValue=1

oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

strKeyPath = "SYSTEM\CurrentControlSet\Services\TermDD"

strValueName = "Start"

strValue=2

oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

strKeyPath = "SYSTEM\CurrentControlSet\Services\TermService"

strValueName = "Start"

strValue=2

oReg.SetDWORDValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue

strKeyPath = ".DEFAULT\Keyboard Layout\Toggle"

strValueName = "Hotkey"

strValue=1

oReg.SetDWORDValue HKEY_USERS,strKeyPath,strValueName,strValue

//下面实现重启远程机器

if option="/r" then

outstreem.write "Now, rebooting target...."

strwmiquery="select * from win32_operatingsystem where primary='true'"

set colinstances=objswbemservices.execquery(strwmiquery)

for each objinstance in colinstances

objinstance.win32shutdown(2)

end if

outstreem.write "Ok, rebooted the target."

//简单的用法说明的函数。

function usage()

wscript.echo string(60,"=")

wscript.echo "Wmi3389 v1.0.0"

wscript.echo "No ipc Open 3389, code written by pye."

wscript.echo "Welcome to visite www.coon.cn or Mail to grandh4408@yahoo.com.cn"

wscript.echo "Usage:"

wscript.echo "cscript "&wscript.scriptfullname&" targetIP username password [/r]"

wscript.echo "/r reboot the target this is optional"

wscript.echo "It use WMI to Open 3389 of target server."

wscript.echo string(60,"=")&vbcrlf

end function

将上面的代码复制带记事本里,保存为Wmi3389.vbs。然后在CMD里执行:

cscript Wmi3389.vbs ipaddress administrator password [/r]

看看是不是和ROTS.vbs有一样的效果啊?大家赶快实践实践吧。

四:最后的唠叨

=====================================================================================

大家可以看出WMI的功能是很强大的,这里要感谢MicroSoft了,它是永远都不会让我们失望的。WMI对象允许通过VB,VBA,WSH, VBScript, JScript,ASP,或是支持自动对象的其它环境,对WMI进行完全访问。在参考查询体系中加入 WMI Scripting V1.1 Library ,则Visual Basic或是VBA方案就可以访问这些对象了。支持ActiveX程序的操作平台可以通过对象类的代号,或是类的名称创建这些对象,这些对象的前缀是 WbemScripting,如 WbemScripting.SwbemLocator。所以大家有兴趣的完全可以利用VB,WSH,VBScript, JScript,ASP等编写更多的利用WMI的黑客程序。

----------------------------------------------------

最后给你附上一段程序

/* **********************************************

* Rainsoft Development Library for Microsoft.NET

*

* Copyright (c) 2004,2005 RainTrail Studio.China

* All Rigths Reserved!

* Author: Q.yuhen (qyuhen@hotmail.com)

********************************************** */

using System

using System.Management

using System.Collections

using System.Collections.Specialized

using System.Text

namespace Rainsoft.Management

{

#region WMIPath

public enum WMIPath

{

// 硬件

Win32_Processor, // CPU 处理器

Win32_PhysicalMemory, // 物理内存条

Win32_Keyboard, // 键盘

Win32_PointingDevice, // 点输入设备,包括鼠标。

Win32_FloppyDrive, // 软盘驱动器

Win32_DiskDrive, // 硬盘驱动器

Win32_CDROMDrive, // 光盘驱动器

Win32_BaseBoard, // 主板

Win32_BIOS, // BIOS 芯片

Win32_ParallelPort, // 并口

Win32_SerialPort, // 串口

Win32_SerialPortConfiguration, // 串口配置

Win32_SoundDevice, // 多媒体设置,一般指声卡。

Win32_SystemSlot, // 主板插槽 (ISA &PCI &AGP)

Win32_USBController, // USB 控制器

Win32_NetworkAdapter, // 网络适配器

Win32_NetworkAdapterConfiguration, // 网络适配器设置

Win32_Printer, // 打印机

Win32_PrinterConfiguration, // 打印机设置

Win32_PrintJob, // 打印机任务

Win32_TCPIPPrinterPort, // 打印机端口

Win32_POTSModem, // MODEM

Win32_POTSModemToSerialPort, // MODEM 端口

Win32_DesktopMonitor, // 显示器

Win32_DisplayConfiguration, // 显卡

Win32_DisplayControllerConfiguration, // 显卡设置

Win32_VideoController, // 显卡细节。

Win32_VideoSettings, // 显卡支持的显示模式。

// 操作系统

Win32_TimeZone, // 时区

Win32_SystemDriver, // 驱动程序

Win32_DiskPartition, // 磁盘分区

Win32_LogicalDisk, // 逻辑磁盘

Win32_LogicalDiskToPartition, // 逻辑磁盘所在分区及始末位置。

Win32_LogicalMemoryConfiguration, // 逻辑内存配置

Win32_PageFile, // 系统页文件信息

Win32_PageFileSetting, // 页文件设置

Win32_BootConfiguration, // 系统启动配置

Win32_ComputerSystem, // 计算机信息简要

Win32_OperatingSystem, // 操作系统信息

Win32_StartupCommand, // 系统自动启动程序

Win32_Service, // 系统安装的服务

Win32_Group, // 系统管理组

Win32_GroupUser, // 系统组帐号

Win32_UserAccount, // 用户帐号

Win32_Process, // 系统进程

Win32_Thread, // 系统线程

Win32_Share, // 共享

Win32_NetworkClient, // 已安装的网络客户端

Win32_NetworkProtocol, // 已安装的网络协议

}

#endregion

/// <summary>

/// 获取系统信息

/// </summary>

/// <example>

/// <code>

/// WMI w = new WMI(WMIPath.Win32_NetworkAdapterConfiguration)

/// for (int i = 0i <w.Counti ++)

/// {

/// if ((bool)w[i, "IPEnabled"])

/// {

/// Console.WriteLine("Caption:{0}", w[i, "Caption"])

/// Console.WriteLine("MAC Address:{0}", w[i, "MACAddress"])

/// }

/// }

/// </code>

/// </example>

public sealed class WMI

{

private ArrayList mocs

private StringDictionary names// 用来存储属性名,便于忽略大小写查询正确名称。

/// <summary>

/// 信息集合数量

/// </summary>

public int Count

{

get { return mocs.Count}

}

/// <summary>

/// 获取指定属性值,注意某些结果可能是数组。

/// </summary>

public object this[int index, string propertyName]

{

get

{

try

{

string trueName = names[propertyName.Trim()]// 以此可不区分大小写获得正确的属性名称。

Hashtable h = (Hashtable)mocs[index]

return h[trueName]

}

catch

{

return null

}

}

}

/// <summary>

/// 返回所有属性名称。

/// </summary>

/// <param name="index"></param>

/// <returns></returns>

public string[] PropertyNames(int index)

{

try

{

Hashtable h = (Hashtable)mocs[index]

string[] result = new string[h.Keys.Count]

h.Keys.CopyTo(result, 0)

Array.Sort(result)

return result

}

catch

{

return null

}

}

/// <summary>

/// 返回测试信息。

/// </summary>

/// <returns></returns>

public string Test()

{

try

{

StringBuilder result = new StringBuilder(1000)

for (int i = 0i <Counti++)

{

int j = 0

foreach(string s in PropertyNames(i))

{

result.Append(string.Format("{0}:{1}={2}\n", ++j, s, this[i, s]))

if (this[i, s] is Array)

{

Array v1 = this[i, s] as Array

for (int x = 0x <v1.Lengthx++)

{

result.Append("\t" + v1.GetValue(x) + "\n")

}

}

}

result.Append("======WMI=======\n")

}

return result.ToString()

}

catch

{

return string.Empty

}

}

/// <summary>

/// 构造函数

/// </summary>

/// <param name="path"></param>

public WMI(string path)

{

names = new StringDictionary()

mocs = new ArrayList()

try

{

ManagementClass cimobject = new ManagementClass(path)

ManagementObjectCollection moc = cimobject.GetInstances()

bool ok = false

foreach(ManagementObject mo in moc)

{

Hashtable o = new Hashtable()

mocs.Add(o)

foreach (PropertyData p in mo.Properties)

{

o.Add(p.Name, p.Value)

if (!ok) names.Add(p.Name, p.Name)

}

ok = true

mo.Dispose()

}

moc.Dispose()

}

catch(Exception e)

{

throw new Exception(e.Message)

}

}

/// <summary>

/// 构造函数

/// </summary>

/// <param name="path"></param>

public WMI(WMIPath path): this(path.ToString())


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/280319.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-21
下一篇2023-04-21

发表评论

登录后才能评论

评论列表(0条)

    保存