First we try, then we trust

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、问题提出

当上实验中心主任后的一个棘手的问题就是机房管理。机房不大,只有60多台电脑,而且已经装上了海光硬盘保护卡豪华版,可以直接网络GHOST硬盘。只要安装好一台电脑,就可以在6个小时左右将40G硬盘信息传遍每一台电脑。

虽然是一个小小的实验中心,也要为大家上机服务,什么等级考试、财务会计、外贸模拟、软件开发样样具全。这样,在40G硬盘中装了6个操作系统(DOS、Win 98、Win 2003 Server、Win 2000 Server、WinXP、Win 2000 Server(英文版MCSE用))。在与补丁和病毒做了一番斗争后,剩下的问题就是自动更新IP地址与计算机名。机房中的每台机器都有一个编号,机器的IP分配也与编号相关。海光蓝卡虽然提供自动修改IP的功能,但对Server版的操作系统不起作用(修改完后,系统就瘫痪了),对非Server版的操作系统虽然起作用,但IP地址分配是随机的,如果想人为定制,必须自己建立MAC地址与IP地址的映射表。总之,使用起来非常不方便,何况还没法对NT Server修改IP呢。打电话咨询海光公司,回话是:你用的保护卡不具备修改NT Server IP地址的功能,我们这里的最新产品是MAX版,可以解决你的问题。这不是又要从兜里掏银子吗!还是自己动手解决吧。


二、解决办法

一开始,我使用DHCP动态分配IP,对每台机器保留一固定IP地址,但由于所有的机器都是克隆出来的,机器名完全一样,每次启机都报有重名计算机存在,还影响了网上邻居的使用。最后一生气,干脆自己编一个自动修改机器名与IP地址的程序。

考查了一下,可以使用Windows Script或是WinBatch实现,不过需要在机器上安装这些软件,似乎有些大材小用。最后决定使用Delphi自己编写一个自动修改IP的程序。这样,借助海光蓝卡上自动修改IP的功能(说是自动修改IP,经我研究,实际上就是解开硬盘保护,自动将每个系统重新启动一下,在启动的过程中,海光自己的驱动程序完成修改工作。),实现自己修改IP。具体方法就是,不再安装海光自动修改IP的程序,改成自己的程序,让系统在第一次启动的时候自动修正IP和计算机名,并重新启动机器。

说干就干,首先将所有机器号与MAC映射表存储成Access数据库,并将IP地址设置为自动获取DHCP,防止启机时冲突。然后在Delphi中编写如下程序:

unit UpdateIP;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, NB30, StdCtrls, DB, ADODB;

type
  TfrmUpdateIPAddress = class(TForm)
    adoCntAccess: TADOConnection;
    adoDSMacAddress: TADODataSet;
    procedure adoCntAccessBeforeConnect(Sender: TObject);
    procedure FormShow(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmUpdateIPAddress: TfrmUpdateIPAddress;

implementation

{$R *.dfm}

//============================================================
// 设置数据库路径
//============================================================
procedure TfrmUpdateIPAddress.adoCntAccessBeforeConnect(Sender: TObject);
begin
  adoCntAccess.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Password="";' +
    'User ID=Admin;Data Source=' + ExtractFilePath(Application.ExeName) +
    '\MacData.mdb;Mode=Share Deny None;Extended Properties=""';
end;

//============================================================
// 获取计算机的 MAC 地址
//============================================================
function NBGetAdapterAddress(a :Integer) : string;
var
  NC : TNCB;
  ADAPTE : TADAPTERSTATUS;
  LANAENU : TLANAENUM;
  intId : Integer;
  cR : Char;
  strTem : string;
begin
  Result := '';
  try
    ZeroMemory(@NC, SizeOf(NC));
    NC.ncb_command := Chr(NCBENUM);
    cR := NetBios(@NC);
 
    //Reissue enum command
    NC.ncb_buffer := @LANAENU;
    NC.ncb_length := SizeOf(LANAENU);
    cR := NetBios(@NC);
    if Ord(cR) <> 0 then
      exit;
 
    ZeroMemory(@NC, SizeOf(NC));
    NC.ncb_command := Chr(NCBRESET);
    NC.ncb_lana_num := LANAENU.lana[a];
    cR := NetBios(@NC);
    if Ord(cR) <> 0 then
      exit;
 
    ZeroMemory(@NC, SizeOf(NC));
    NC.ncb_command := Chr(NCBASTAT);
    NC.ncb_lana_num := LANAENU.lana[a];
    StrPCopy(NC.ncb_callname, '*');
    NC.ncb_buffer := @ADAPTE;
    NC.ncb_length := SizeOf(ADAPTE);
    cR := NetBios(@NC);
    strTem := '';
    for intId := 0 To 5 do
      strTem := strTem+ InttoHex(Integer(ADAPTE.adapter_address[intId]), 2);
    Result := strTem;
  finally
  end;
end;

//============================================================
// 设置计算机名
//============================================================
function SetComputerName(AComputerName: string): Boolean;
var
  ComputerName: array[0..MAX_COMPUTERNAME_LENGTH + 1] of Char;
begin
  StrPCopy(ComputerName, AComputerName);
  Result := Windows.SetComputerName(ComputerName);
end;

//============================================================
// 启动时自动修改IP地址以及计算机名
//============================================================
procedure TfrmUpdateIPAddress.FormShow(Sender: TObject);
var
  sMac, sNum, sComputerName, BatchFileName:  string;
  ProcessInfo:  TProcessInformation;
  StartUpInfo:  TStartupInfo;
begin
  sMac := NBGetAdapterAddress(0);

  AdoCntAccess.Connected := True;
  adoDSMacAddress.Close;
  adoDSMacAddress.Parameters.ParamByName('mac').Value := sMac;
  adoDSMacAddress.Open;

  if adoDSMacAddress.RecordCount = 0 then
    Application.Terminate;

  sNum := Trim(adoDSMacAddress.FieldByName('ComputerID').Value);

  //设置计算机名
  sComputerName := 'Stu_' + sNum;
  if not SetComputerName(sComputerName) then
  begin
    ShowMessage('计算机名没有设置成功!');
    Application.Terminate;
  end;

  //设置IP地址、DNS等
  BatchFileName  :=  ExtractFilePath(ParamStr(0))  +  'AutoUpdate.bat ' + sNum;
  StartUpInfo.dwFlags  :=  STARTF_USESHOWWINDOW;
  StartUpInfo.wShowWindow  :=  SW_Hide;
  if CreateProcess(nil, PChar(BatchFileName),  nil,  nil,
    False, IDLE_PRIORITY_CLASS, nil, nil, StartUpInfo, ProcessInfo) then
  begin
    CloseHandle(ProcessInfo.hThread);
    CloseHandle(ProcessInfo.hProcess);
  end;
  Application.Terminate;
end;

end.


该程序首先获取当前机器的MAC地址,然后从Access表中检索机器号,并根据机器号生成机器名“Stu_+机器号”。在修改完机器名后,自动启动一个外部批处理(在这里是一个BAT文件),进行挂参数的批处理调用,实现修改IP地址工作。如果有人问为什么要调用批处理的话,实际上我想将系统做成自删除的系统,程序执行完就将自己删除的干干静静,不留任何痕迹,这在后面再讨论。

批处理文件的内容如下:

@ECHO OFF
rem 修改IP地址、子网掩码、网关
cmd /c netsh interface ip set address name="本地连接" source=static addr=10.16.19.%1 mask=255.255.255.0 gateway=10.16.19.254 gwmetric=1

rem 修改DNS
cmd /c netsh interface ip set dns name="本地连接" source=static addr=210.31.198.65

rem 删除放在启动组中的快捷方式
del /q "C:\Documents and Settings\All Users\「开始」菜单\程序\启动\AutoUpdate.*"

rem 调用重启机的批处理文件
Restart.bat

从文件中可以看出,为了让系统在第一次运行时自动修改IP地址,在开始菜单的启动中创建了一个快捷方式,自动调用我的程序,程序执行完后,将启动菜单中快捷方式删除,然后重新启动。至于自删除的功能,这里我没有放上来,感兴趣的话,可以在Google中检索“Delphi 自己 删除”,能找到很多资料。

下面说说重新启动,Windows 98、Windows Me重新启动很简单,只要一条命令就可以了:

rundll32.exe shell32.dll,SHExitWindowsEx n

其中最后面的n表示:

0 - LOGOFF
1 - SHUTDOWN
2 - REBOOT
4 - FORCE
8 - POWEROFF

Window XP的重启不同于98,需要使用 shutdown 命令,具体可以参考手册。

最困难的是NT 2000的重启,使用上面的方法都不起作用。必须通过多条命令实现。下面看看NT 2000重启的批处理文件:

@ECHO OFF & cd/d %temp% & echo [version] > {out}.inf
(set inf=InstallHinfSection DefaultInstall)
echo signature=$chicago$ >> {out}.inf
echo [defaultinstall] >> {out}.inf
rundll32 setupapi,%inf% 1 %temp%\{out}.inf
del {out}.inf

有些乱,但很管用。

好了,所有的准备工作都已经具备,下面是实施办法:

1、首先需要准备一台机器做DHCP服务器,并且配置好IP地址池,但这个IP地址池不要与你想分配的IP地址相重复,否则会有不少麻烦。比如你想给克隆后的机器分配从10.16.19.1到10.16.19.100的IP地址段,那么你可以给你的DHCP服务器分配一个IP地址为192.168.1.1,并且配置可分配地址池为192.168.1.2到192.168.1.101,最好不要将租期设置的很长,否则可能出现IP不够分配的问题,或者在每次操作时清空一下租约。
2、安装客户端机器。
3、将编译好的可执行文件以及两个批处理文件还有一个Access数据库文件拷贝到一个目录中;
4、在目录“C:\Documents and Settings\All Users\「开始」菜单\程序\启动\”中建立一个指向该可执行文件的快捷方式(操作系统不同,目录可能也各不相同);
5、将客户端机器的IP地址设置为自动获取。
6、关闭计算机,使用海光蓝卡克隆硬盘;
7、从海光蓝卡上执行“分配IP地址”功能,所有机器自动重启,当机器启动起来后,首先会自动申请一IP地址,比如说192.168.1.2,并且所有机器IP不会冲突,从而避免因IP地址冲突造成无法正常获取MAC地址的问题出现。然后自己编写的程序将被调用,并完成自动修改IP,设置机器名称,重新启动的过程。这样,IP地址与计算机名就自动修正好了。(没有海光蓝卡的用户也可以通过手动重启机实现自动修正功能)


三、目前还存在的一些问题

目前还没有完全解决NT Server在克隆中的问题,比如说NT内部会有一唯一标识号,在克隆过程中也被复制了,而且上面的方法不能修改NT Server的AD域名。要想解决这个问题,需要从安装着手。Windows NT 2000的安装说明中有这方面的解决办法。如果哪位需要精益求精的话,可以找这方面的参考资料看看。

posted on 2004-09-03 09:42  吕震宇  阅读(28155)  评论(71编辑  收藏  举报