Delphi如何远程增加账号到本地管理员组同时远程添加计划任务

时间:2021-07-21 16:22:19

问题背景:

最近有大领导的硬盘坏了导致数据丢失,当然拿到外面去恢复,但没有全部恢复。所以这个incident就触发了一个问题, 如何避免发生类似的事情。所以我就想,能否尽可能早的检测出用户的硬盘的问题,在彻底坏之前就备份好数据并更换掉硬盘。

总体的思路:

我们知道如硬盘有问题了,比如坏道啊什么的,Windows系统会产生相应的一条日志。所以如果我们能够集中监测到用户的这类日志,就可以尽可能的避免数据丢失的事故发生。我们知道WINDOWS系统有一个event转发的功能,所以只要将所有用户的相应的日志转发到一台服务器上我们就可以实现集中监测了。同时我们知道:日志转发有两种方式:collector initiated和source initiated.  Source initiated 我们可以用GPO,但我们的GPO都要鬼佬来approve,如这样天知道什么时候能approve,甚至都不会approve.所以我就选择collector initiated。但这样就产生一个问题,如何在每台机器上启用日志转发,另外这种方法的日志转发需要将服务器添加到在每台用户的本机管理员组内。

 

下面是源代码(需要NTSET Collection控件):

unit EventForwarding;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdBaseComponent, IdComponent, IdRawBase, IdRawClient,ComObj,ComCtrls,
  IdIcmpClient,StdCtrls, NTCommon, UserMan;

type
  TForm1 = class(TForm)
    Button1: TButton;
    IdIcmpClient1: TIdIcmpClient;
    Edit1: TEdit;
    NTUserMan1: TNTUserMan;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Function PingResult(HostName:String):String;
    Function RunDosCommand(Command: string): string;
    Function GetTime(currenttime:TdateTime):String;
    Function WaitExeFinish(const sExeName: string):boolean;
    procedure Button1Click(Sender: TObject);
    Procedure OpenExcel(Path:string;sheetnumber:Integer);
    Function AddUserAccount(HostName,logonusername,logonpwd:string):string;
    Function AddComputerAccount(HostName,logonusername,logonpwd:string):string;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1; ExcelApp:Variant;

implementation

{$R *.dfm}


Function Tform1.AddUserAccount(HostName,logonusername,logonpwd:string):String;
begin
 NTUserman1.MachineName:=HostName;
 NTUserman1.LogonAs.UserName:=logonusername;
 NTUserman1.LogonAs.Password:=logonpwd;
Try
 if (NTUserman1.ConnectIPC=0) then
    begin
     NTUserman1.UserName:='账号';
     NTUserman1.MemberOfLocal.add('Administrators');
     Result:='成功加入';
  end else
    begin
      Result:='加入失败';
      end
  Except
   Result:='异常';
  end;
end;

Function Tform1.AddComputerAccount(HostName,logonusername,logonpwd:string):String;
begin
 NTUserman1.MachineName:=HostName;
 NTUserman1.LogonAs.UserName:=logonusername;
 NTUserman1.LogonAs.Password:=logonpwd;
 Try
 if (NTUserman1.ConnectIPC=0) then
    begin
     NTUserman1.UserName:='服务器名';
     NTUserman1.MemberOfLocal.add('Administrators');
     Result:='成功加入';
    end else
      begin
      Result:='加入失败';
      end
  Except
   Result:='异常';
  end;


end;

//执行DOS并返回结果
function Tform1.RunDosCommand(Command: string): string;
var
  hReadPipe: THandle;
  hWritePipe: THandle;
  SI: TStartUpInfo;
  PI: TProcessInformation;
  SA: TSecurityAttributes;
  //     SD   :   TSecurityDescriptor;
  BytesRead: DWORD;
  Dest: array[0..1023] of char;
  CmdLine: array[0..512] of char;
  TmpList: TStringList;
  Avail, ExitCode, wrResult: DWORD;
  osVer: TOSVERSIONINFO;
  tmpstr: AnsiString;
begin
  osVer.dwOSVersionInfoSize := Sizeof(TOSVERSIONINFO);
  GetVersionEX(osVer);

  if osVer.dwPlatformId = VER_PLATFORM_WIN32_NT then
  begin
  //         InitializeSecurityDescriptor(@SD,   SECURITY_DESCRIPTOR_REVISION);
  //         SetSecurityDescriptorDacl(@SD,   True,   nil,   False);
    SA.nLength := SizeOf(SA);
    SA.lpSecurityDescriptor := nil; //@SD;
    SA.bInheritHandle := True;
    CreatePipe(hReadPipe, hWritePipe, @SA, 0);
  end
  else
    CreatePipe(hReadPipe, hWritePipe, nil, 1024);
  try
    FillChar(SI, SizeOf(SI), 0);
    SI.cb := SizeOf(TStartUpInfo);
    SI.wShowWindow := SW_HIDE;
    SI.dwFlags := STARTF_USESHOWWINDOW;
    SI.dwFlags := SI.dwFlags or STARTF_USESTDHANDLES;
    SI.hStdOutput := hWritePipe;
    SI.hStdError := hWritePipe;
    StrPCopy(CmdLine, Command);
    if CreateProcess(nil, CmdLine, nil, nil, True, NORMAL_PRIORITY_CLASS, nil, nil, SI, PI) then
    begin
      ExitCode := 0;
      while ExitCode = 0 do
      begin
        wrResult := WaitForSingleObject(PI.hProcess, 500);
  //                 if   PeekNamedPipe(hReadPipe,   nil,   0,   nil,   @Avail,   nil)   then
        if PeekNamedPipe(hReadPipe, @Dest[0], 1024, @Avail, nil, nil) then
        begin
          if Avail > 0 then
          begin
            TmpList := TStringList.Create;
            try
              FillChar(Dest, SizeOf(Dest), 0);
              ReadFile(hReadPipe, Dest[0], Avail, BytesRead, nil);
              TmpStr := Copy(Dest, 0, BytesRead - 1);
              TmpList.Text := TmpStr;
              Result := tmpstr;
            finally
              TmpList.Free;
            end;
          end;
        end;
        if wrResult <> WAIT_TIMEOUT then ExitCode := 1;
      end;
      GetExitCodeProcess(PI.hProcess, ExitCode);
      CloseHandle(PI.hProcess);
      CloseHandle(PI.hThread);
    end;
  finally
    CloseHandle(hReadPipe);
    CloseHandle(hWritePipe);
  end;
end;

Function Tform1.PingResult(HostName:String):String;
Begin
IdIcmpClient1.Host:=HostName;
Try
  IdIcmpClient1.Ping;
   if (IdIcmpClient1.replyStatus.BytesReceived=0) or (IdIcmpClient1.ReplyStatus.TimeToLive=0) then
           begin
            Result:='该机器不存在或不在线';
            end else
              begin
                 Result:='该机器存在';
              end
     Except
       Result:='该机器不存在';
     end;
end;

Function Tform1.GetTime(currenttime:TdateTime):String;
var Hour, Min,Sec, MSec:Word;
begin
DecodeTime(currenttime,Hour, Min,Sec, MSec);
if (Min>=55) then
  begin
    Result:=IntTostr(Hour+1)+':'+'05';
  end else
 if (Min<5) then
   begin
    Result:=IntTostr(Hour)+':'+'0'+IntTostr(Min+5);
   end else
  Result:=IntTostr(Hour)+':'+IntTostr(Min+5);
end;

Function Tform1.WaitExeFinish(const sExeName: string):boolean;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
b:boolean;
begin
//ShowMessage('Ready to launch NotePad...');
FillChar(StartupInfo, SizeOf(StartupInfo), 0);
b:=CreateProcess( nil, PChar(sExeName), nil, nil, False, 0,
   nil, nil, StartupInfo, ProcessInfo);
with ProcessInfo do
begin
   CloseHandle(hThread);
   WaitForSingleObject(hProcess, INFINITE);
   CloseHandle(hProcess);
end;
Result := b;
//ShowMessage('NotePad has terminated.');
end;

Procedure Tform1.OpenExcel(Path:String;sheetnumber:Integer);

Begin
ExcelApp:=CreateoleObject('Excel.Application');
ExcelApp.Visible:=True;
ExcelApp.Workbooks.Open(Path);
ExcelApp.Worksheets[sheetnumber].Activate;
End;


procedure TForm1.Button1Click(Sender: TObject);
var introw,sheet: integer;
    pinable,targetTime,cmdstring,hostname,computername:string;
    logonusername, logonpassword:string;

begin
  sheet:=StrToInt(Trim(Edit2.Text));
  OpenExcel(Edit1.Text,sheet);
  introw:=2;
  While not (ExcelApp.Cells[introw,7].value ='')   do
     begin
       if (ExcelApp.Cells[introw,14].value ='') then
        begin
        hostname:=Trim(ExcelApp.cells[introw,7].value)+'.asia.jci.com';
        computername:='\\'+hostname;
        logonusername:=hostname+'\管理员账号';
        logonpassword:=‘管理员账号密码;
        ExcelApp.cells[introw,10].value:=form1.PingResult(hostname);
        pinable:= ExcelApp.cells[introw,10].value;
        if (pinable='该机器存在') then
          begin
            ExcelApp.cells[introw,12].value:=AddUserAccount(computername,logonusername,logonpassword);
            ExcelApp.cells[introw,13].value:=AddComputerAccount(computername,logonusername,logonpassword);
            targetTime:= GetTime(Now);
            cmdstring:='schtasks /create /s '+hostname+' /sc once /TN EventForwarding /TR '+'"'+'C:\windows\system32\WinRm.cmd quickconfig -q'+'"'+' '+'/ST '+targetTime+' /ru '+'"'+'system'+'"';
            ExcelApp.Cells[introw,11].value:=RunDosCommand(cmdstring);
          end;
        end;
     introw:=introw+1;
  end;
  Showmessage('complete');


end;

end.