关于获取域中远程电脑的信息

最近需要收集公司各电脑的CPU、硬盘、内存等数据信息,于是做了一些研究,现在做个总结。算是一个记录,同时帮助更多的人找到思路吧。

首先得知道一个前提,在域服务器无法主动地直接获取用户电脑的硬件信息,只可以简单获取到用户的用户名和电脑名。而要获取更深层的硬件信息,则需要用户端主动把硬件信息发送到服务端再收集起来。而让用户端发送硬件信息的方式开发过程中接触到了三种:

1. 在用户电脑安装个客户端,类似于电脑监控那类软件,随时都可以通过客户端把数据信息发送到服务端。此法不推荐,开发麻烦,使用网上现成的又要付费,而且最重要的是客户端会给员工一种抵触心理,觉得自己无时无刻被公司监控。当然如果确实需要监控另说。优势就是随时都可以方便地获取用户电脑的信息。

对于解决抵触心理,有个办法,可以使用域策略ou推送软件到用户电脑上,收集完信息再马上卸载。但一样不合适,就本人公司测试结果来说,首先域策略推送软件不能推送exe格式,只能推送msi格式,而且推送完还得在用户电脑进入控制面板进行一些操作,才能真正完成安装。然后这种方式也麻烦,每次收集信息都要推送一次。

2. 使用WMI获取信息,WMI其实是系统提供的一个接口集,相当于系统内置的一个客户端。此法你得知道用户电脑的IP(或者电脑名)和管理员登录名和密码(密码不能为空),可以使用域管理员进行连接(加域后用户电脑上默认把域管理员账号密码设置为隐藏管理员),电脑加域的时候就会把域管理员用户设置为电脑本地的隐藏管理员。此法可以在用户不知不觉中获取。java可以通过J-Interop或Jacob调用WMI接口。其中J-Interop网上说要让远程电脑允许远程管理(这个如果真需要可以通过域策略开机脚本实现)和关闭防火墙。但是我使用Jacob时只是在远程电脑关闭了防火墙,就实现了。至于J-interop是否真的需要开启远程管理,我就不清楚了。

关于两个框架的代码,百度找到的都是会出错的,而且相关知识信息又太少了,搞得我两个多星期都在烦恼中度过,只能靠自己去看代码研究。后来又去google了解了一下,才总算运行成功,获取到了远程电脑的信息。相关代码记录一下,也希望能帮你们减少些烦恼。

首先是Jacob的代码,这个我运行成功了,获取到了远程电脑硬盘的大小。想获取其它数据信息,可以通过不同的WMI查询语句实现。关于Jacob的jar和dll的获取,可以到github上导入源码项目来自己构建:https://github.com/freemansoft/jacob-project。这个一定要仔细看build.xml中的每个注释,我刚开始没有认真仔细看,走了很多弯路。Ant项目后就能获取jar和dll,其中dll放在jdk路径下的bin文件夹里面。网上很多说放到C:\Windows\System32路径下,我也通过代码了解到确实是有到这个路径去获取dll,但是我这不知道什么情况,放那里一样报错,放jdk的bin里面才运行成功。

public class WMIByJacob {

	public static void main(String[] args) {
		// WMI查询语句可以上网查找一下
        Variant wmiNoParam = getWMI("SELECT Size FROM Win32_DiskDrive WHERE Index = 0");
        printProperty(wmiNoParam,"size");
    }

    private static void printProperty(Variant vCollection, String... properties) {
        EnumVariant enumVariant = new EnumVariant(vCollection.toDispatch());

        while (enumVariant.hasMoreElements()) {
            Dispatch item = enumVariant.nextElement().toDispatch();
            for (String property : properties) {
                Variant variant = Dispatch.call(item, property);
                System.out.println(variant);
            }
        }
    }

    public static Variant getWMI(String query, Object... param) {
//        String host = "localhost";
//        String connectStr = String.format("winmgmts:\\\\%s\\root\\CIMV2", host);// only can run on localhost
        ActiveXComponent wmi = new ActiveXComponent("WbemScripting.SWbemLocator");
        Variant variantParameters[] = new Variant[4];
	    variantParameters[0] = new Variant("remoteComputerNameOrIP");
	    variantParameters[1] = new Variant("root\\CIMV2");
	    variantParameters[2] = new Variant("username");
	    variantParameters[3] = new Variant("password");
	    Dispatch services = wmi.invoke("ConnectServer", variantParameters).toDispatch();
	    wmi = new ActiveXComponent(services);
        Variant[] vs = new Variant[param.length + 1];
        vs[0] = new Variant(query);
        for (int i = 0; i < param.length; i++) {
            vs[i + 1] = new Variant(param[i]);
        }
        Variant vCollection = wmi.invoke("ExecQuery", vs);
        return vCollection;
    }

}

然后是J-Interop的代码,这个我研究国内网上的代码一样没有运行成功,也去google了一下,但由于Jacob已经实现,就没有再去研究这个了。但是还是把google找到的与百度上使用不同接口的代码贴上来,有兴趣的可以自己去研究一下。

IJIAuthInfo authInfo = new JIDefaultAuthInfoImpl("remoteComputerIpAddress", "wmiUserName", "wmiUserPassword");
        IJIWinReg registry = null;
        try {
            registry = JIWinRegFactory.getSingleTon().getWinreg(authInfo, "remoteComputerIpAddress", true);
            JIPolicyHandle policyHandle = registry.winreg_OpenHKLM();
            JIPolicyHandle policyHandle2 = registry.winreg_OpenKey(policyHandle, "SOFTWARE\\wisemon",
                    IJIWinReg.KEY_ALL_ACCESS);
            // JIPolicyHandle policyHandle3 =
            // registry.winreg_OpenKey(policyHandle2,"wisemon",IJIWinReg.KEY_ALL_ACCESS);
            System.out.println("Printing first 1000 entries under HKEY_LOCAL_MACHINE\\BCD00000000...");
            for (int i = 0; i < 1; i++) {
                // String[] values = registry.winreg_EnumKey(policyHandle3,i);
                // Object[] values = registry.winreg_EnumValue(policyHandle3,i);
                Object[] values = registry.winreg_QueryValue(policyHandle2, "name", 100);
                Object[] values2 = registry.winreg_QueryValue(policyHandle2, "date", 100);
                System.out.println(new String((byte[]) values[1]));
                System.out.println(new String((byte[]) values2[1]));
            }
        } catch (UnknownHostException | JIException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            System.out.println("Closing registry connection");
            registry.closeConnection();
        } 

3. 让用户电脑运行脚本把信息发送到服务端。方法2最方便,而且可以随时获取,但是刚开始不知道域管理员是用户电脑的本地管理员。所以另外想了一个办法,该方法只能在用户登录时获取。

首先编写一个用户端运行的脚本,收集用户端电脑的数据信息。关于数据采集可以参照下面代码。

@echo off
cls
color 0a
title 硬件检测
::mode con cols=90
sc config winmgmt start= auto >nul 2<&1
net start winmgmt 2>1nul
setlocal ENABLEDELAYEDEXPANSION
echo 主版:
for /f "tokens=1,* delims==" %%a in ('wmic BASEBOARD get Manufacturer^,Product^,Version^,SerialNumber /value') do (
set /a tee+=1
if "!tee!" == "3" echo 制造商 = %%b
if "!tee!" == "4" echo 型 号 = %%b
if "!tee!" == "5" echo 序列号 = %%b
if "!tee!" == "6" echo 版 本 = %%b
)
set tee=0
echo BIOS:
for /f "tokens=1,* delims==" %%a in ('wmic bios get CurrentLanguage^,Manufacturer^,SMBIOSBIOSVersion^,SMBIOSMajorVersion^,SMBIOSMinorVersion^,ReleaseDate /value') do (
set /a tee+=1
if "!tee!" == "3" echo 当前语言 = %%b
if "!tee!" == "4" echo 制造商 = %%b
if "!tee!" == "5" echo 发行日期 = %%b
if "!tee!" == "6" echo 版 本 = %%b
if "!tee!" == "7" echo SMBIOSMajorVersion = %%b
if "!tee!" == "8" echo SMBIOSMinorVersion = %%b 
)
set tee=0
echo.
echo CPU:
for /f "tokens=1,* delims==" %%a in ('wmic cpu get name^,ExtClock^,CpuStatus^,Description /value') do (
set /a tee+=1
if "!tee!" == "3" echo CPU个数 = %%b
if "!tee!" == "4" echo 处理器版本 = %%b
if "!tee!" == "5" echo 外 频 = %%b
if "!tee!" == "6" echo 名称及主频率 = %%b
)
set tee=0
echo.
echo 显示器:
for /f "tokens=1,* delims==" %%a in ('wmic DESKTOPMONITOR get name^,ScreenWidth^,ScreenHeight^,PNPDeviceID /value') do (
set /a tee+=1
if "!tee!" == "3" echo 类 型 = %%b
if "!tee!" == "4" echo 其他信息 = %%b
if "!tee!" == "5" echo 屏幕高 = %%b
if "!tee!" == "6" echo 屏幕宽 = %%b
)
set tee=0
echo.
echo 硬 盘:
for /f "tokens=1,* delims==" %%a in ('wmic DISKDRIVE get model^,interfacetype^,size^,totalsectors^,partitions /value') do (
set /a tee+=1
if "!tee!" == "3" echo 接口类型 = %%b
if "!tee!" == "4" echo 硬盘型号 = %%b
if "!tee!" == "5" echo 分区数 = %%b
if "!tee!" == "6" echo 容 量 = %%b
if "!tee!" == "7" echo 总扇区 = %%b
)
echo 分区信息:
wmic LOGICALDISK where mediatype='12' get description,deviceid,filesystem,size,freespace
set tee=0
echo.
echo 网 卡:
for /f "tokens=1,* delims==" %%a in ('wmic NICCONFIG where "index='1'" get ipaddress^,macaddress^,description /value') do (
set /a tee+=1
if "!tee!" == "3" echo 网卡类型 = %%b
if "!tee!" == "4" echo 网卡IP = %%b
if "!tee!" == "5" echo 网卡MAC = %%b
)
set tee=0
echo.
echo 打印机:
for /f "tokens=1,* delims==" %%a in ('wmic PRINTER get caption /value') do (
set /a tee+=1
if "!tee!" == "3" echo 打印机名字 = %%b
)
set tee=0
echo.
echo 声 卡:
for /f "tokens=1,* delims==" %%a in ('wmic SOUNDDEV get name^,deviceid /value') do (
set /a tee+=1
if "!tee!" == "3" echo 其他信息 = %%b
if "!tee!" == "4" echo 型 号 = %%b
)
set tee=0
echo.
echo 内 存: 
for /f "tokens=1,* delims==" %%a in ('systeminfo^|find "内存"') do (
echo %%a 4534 %%b 
)
echo.
echo 查询显卡(方式一):
wmic path Win32_VideoController get /value

echo.
echo 查询显卡(方式二):
del /f "%TEMP%\temp.txt" 2>nul
dxdiag /t %TEMP%\temp.txt
:显卡
rem 这里需要30秒左右!
if EXIST "%TEMP%\temp.txt" (
for /f "tokens=1,2,* delims=:" %%a in ('findstr /c:" Card name:" /c:"Display Memory:" /c:"Current Mode:" "%TEMP%\temp.txt"') do (
set /a tee+=1
if !tee! == 1 echo 显卡型号: %%b
if !tee! == 2 echo 显存大小: %%b
if !tee! == 3 echo 当前设置: %%b
) ) else (
ping /n 1 127.1>nul
goto 显卡
)
set /p var=需要显卡额外信息吗(y/n): 
if /i %var% == y notepad "%TEMP%\temp.txt"
del /f "%TEMP%\temp.txt" 2>nul
pause

然后把收集到的信息在脚本中通过http以下面的格式发送到服务端,服务端就可以把信息保存起来。

start http://服务地址与端口/computerInfo?CPUName="!CPUName: =%%20!"^&freeSpace="%freeSpace%"^&size="%size%"^&netIP="%netIP:~2,-2%"^&physical="!physical: =!"^&virtual="!virtual: =!"^&printer="!printer: =%%20!"^&userName="%username%"^&computerName="%computername%"

而让用户端电脑运行脚本的方式就是使用域策略登录脚本来让用户登录时自动运行这个脚本。在域服务器上打开AD,然后选择用户,右键打开属性界面,选择配置文件,然后在登录脚本那里输入脚本名称,然后把脚本文件拉到C:\Windows\SYSVOL\sysvol\**.com\scripts路径下,则当用户登录时即会自动运行该脚本。

此http方法是使用get方法传输数据的,那么用户那里会打开浏览器,可以选择用taskkill /f /t /im chrome.exe关闭浏览器进程,或者在页面放个公司logo,那么员工并不会觉得自己信息被获取,而只是会觉得是连接了公司的网络。

若不想让用户电脑打开浏览器,那么可以使用post方法传输,但是这种方法同样麻烦,需要到每台电脑上安装curl才能实现。

当然也还可以建个共享盘,在脚本运行时把信息存储到共享盘的文件中。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值