用代码操控另一台电脑
2015-03-11
做测试时,往往要配置测试机器,如果能用代码自动化实现,那是最好不过的。
据我所知,有三种方法[1]:
- socket通讯即可完成
- 用psexec,(psexec是pstools中的一个程序)
- 用ManagementClass类
第1.2.中方法,都需要在被操控的机器上安装接受信息的程序。所以我采用第3.种方法,只需在一台机器上操控即可。
设计
使用ManagementClass类,只需知道被操控机器的用户名、密码即可,可对不在同一域中的机器进行操控
源代码:
设计思路:
- step 1: create sub direcotry on remtoeMachine
- step 2: create a share folder on remoteMachine
- step 3: get full control of share folder
- step 4: copy tool to share folder
- step 5: start tool with argument to do special operation on remote machine
实现
Class Library 'MachineControl.dll'
'MachineControl.dll':(引用到了System.Management.dll)是负责对被操控的机器进行控制的类,主要就两个类'WindowsShare', 'ExecuteCommand':
Class 'WindowsShare':该类负责在被操控的机器上创建share folder,设置权限
1 using System.Management; 2 using System.Security.Principal; 3 using System.Collections.Generic; 4 using System; 5 6 namespace MachineControl 7 { 8 public class WindowsShare 9 { 10 public enum MethodStatus : uint 11 { 12 Success = 0, //Success 13 AccessDenied = 2, //Access denied 14 UnknownFailure = 8, //Unknown failure 15 InvalidName = 9, //Invalid name 16 InvalidLevel = 10, //Invalid level 17 InvalidParameter = 21, //Invalid parameter 18 DuplicateShare = 22, //Duplicate share 19 RedirectedPath = 23, //Redirected path 20 UnknownDevice = 24, //Unknown device or directory 21 NetNameNotFound = 25 //Net name not found 22 } 23 public enum ShareType : uint 24 { 25 DiskDrive = 0x0, //Disk Drive 26 PrintQueue = 0x1, //Print Queue 27 Device = 0x2, //Device 28 IPC = 0x3, //IPC 29 DiskDriveAdmin = 0x80000000, //Disk Drive Admin 30 PrintQueueAdmin = 0x80000001, //Print Queue Admin 31 DeviceAdmin = 0x80000002, //Device Admin 32 IpcAdmin = 0x80000003 //IPC Admin 33 } 34 public enum AccessMaskTypes 35 { 36 FullControl = 2032127, Change = 1245631, 37 ReadOnly = 1179817 38 } 39 #region field and property 40 private ManagementObject _winShareObject; 41 private WindowsShare(ManagementObject obj) { _winShareObject = obj; } 42 public ManagementObject ManagementObject { get { return _winShareObject; } } 43 public uint AccessMask { get { return Convert.ToUInt32(_winShareObject["AccessMask"]); } } 44 public bool AllowMaximum { get { return Convert.ToBoolean(_winShareObject["AllowMaximum"]); } } 45 public string Caption{ get { return Convert.ToString(_winShareObject["Caption"]); } } 46 public string Description { get { return Convert.ToString(_winShareObject["Description"]); } } 47 public DateTime InstallDate { get { return Convert.ToDateTime(_winShareObject["InstallDate"]); } } 48 public uint MaximumAllowed 49 { 50 get { return Convert.ToUInt32(_winShareObject["MaximumAllowed"]); } 51 } public string Name { get { return Convert.ToString(_winShareObject["Name"]); } } public string Path { get { return Convert.ToString(_winShareObject["Path"]); } } public string Status { get { return Convert.ToString(_winShareObject["Status"]); } } public ShareType Type { get { return (ShareType)Convert.ToUInt32(_winShareObject["Type"]); } } public MethodStatus Delete() { object result = _winShareObject.InvokeMethod("Delete", new object[] { }); uint r = Convert.ToUInt32(result); return (MethodStatus)r; } 52 #endregion 53 #region static method 54 public static MethodStatus Create(string path, string name, ShareType type, uint? maximumAllowed, string description, string password) 55 { 56 ManagementClass mc = new ManagementClass("Win32_Share"); 57 ManagementBaseObject shareParams = mc.GetMethodParameters("Create"); 58 shareParams["Path"] = path; 59 shareParams["Name"] = name; 60 shareParams["Type"] = (uint)type; 61 shareParams["Description"] = description; 62 if (maximumAllowed != null) 63 shareParams["MaximumAllowed"] = maximumAllowed; 64 if (!String.IsNullOrEmpty(password)) 65 shareParams["Password"] = password; 66 ManagementBaseObject result = mc.InvokeMethod("Create", shareParams, null); 67 return (MethodStatus)(result.Properties["ReturnValue"].Value); 68 } 69 70 public static MethodStatus CreateShareFolder(string FolderPath, string ShareName, ShareType type, string Description, string remoteMachine, string userName, string passWord) 71 { 72 73 ManagementClass mc = new ManagementClass(string.Format(@"\\{0}\root\cimv2:Win32_Share", remoteMachine)); 74 mc.Scope.Options.Username = userName; 75 mc.Scope.Options.Password = passWord; 76 77 // Get the parameter for the Create Method for the folder 78 ManagementBaseObject shareParams = mc.GetMethodParameters("Create"); 79 // Assigning the values to the parameters 80 shareParams["Description"] = Description; 81 shareParams["Name"] = ShareName; 82 shareParams["Path"] = FolderPath; 83 shareParams["Type"] = (int)type; 84 // Finally Invoke the Create Method to do the process 85 ManagementBaseObject result = mc.InvokeMethod("Create", shareParams, null); 86 return (MethodStatus)(result.Properties["ReturnValue"].Value); 87 88 } 89 90 public static IListGetAllShareFolders(string remoteMachine, string userName, string passWord) 91 { 92 IList result = new List (); 93 ManagementClass mc = new ManagementClass(string.Format(@"\\{0}\root\cimv2:Win32_Share", remoteMachine)); 94 mc.Scope.Options.Username = userName; 95 mc.Scope.Options.Password = passWord; 96 97 ManagementObjectCollection moc = mc.GetInstances(); 98 99 foreach (ManagementObject mo in moc)100 {101 WindowsShare share = new WindowsShare(mo);102 result.Add(share);103 }104 return result;105 }106 107 public static IList GetAllShares()108 {109 IList result = new List ();110 ManagementClass mc = new ManagementClass("Win32_Share"); 111 ManagementObjectCollection moc = mc.GetInstances(); 112 foreach (ManagementObject mo in moc)113 {114 WindowsShare share = new WindowsShare(mo);115 result.Add(share);116 } 117 return result;118 }119 public static WindowsShare GetShareByName(string name)120 {121 name = name.ToUpper();122 IList shares = GetAllShares();123 foreach (WindowsShare s in shares)124 if (s.Name.ToUpper() == name)125 return s; return null;126 }127 public static WindowsShare GetShareByName(string remoteMachine, string userName, string passWord,string name)128 {129 name = name.ToUpper();130 IList shares = GetAllShareFolders(remoteMachine, userName, passWord);131 foreach (WindowsShare s in shares)132 if (s.Name.ToUpper() == name)133 return s; return null;134 }135 public static WindowsShare GetShareByPath(string path)136 {137 path = path.ToUpper();138 IList shares = GetAllShares();139 foreach (WindowsShare s in shares)140 if (s.Path.ToUpper() == path)141 return s; return null;142 }143 #endregion144 #region method145 public MethodStatus SetPermission(string domain, string userName, AccessMaskTypes amtype)146 {147 NTAccount account = new NTAccount(domain, userName); 148 SecurityIdentifier sid = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));149 byte[] sidArray = new byte[sid.BinaryLength]; sid.GetBinaryForm(sidArray, 0);150 ManagementObject trustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);151 trustee["Domain"] = domain; 152 trustee["Name"] = userName; 153 trustee["SID"] = sidArray; 154 ManagementObject adminACE = new ManagementClass(new ManagementPath("Win32_Ace"), null); 155 adminACE["AccessMask"] = (int)amtype; adminACE["AceFlags"] = 3;156 adminACE["AceType"] = 0; 157 adminACE["Trustee"] = trustee; 158 ManagementObject secDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);159 secDescriptor["ControlFlags"] = 4; //SE_DACL_PRESENT 160 secDescriptor["DACL"] = new object[] { adminACE };161 object result = _winShareObject.InvokeMethod("SetShareInfo", new object[] 162 { Int32.MaxValue, this.Description, secDescriptor }); 163 uint r = Convert.ToUInt32(result); return (MethodStatus)r;164 }165 #endregion166 }167 }
Class 'ExecuteCommand' :该类负责在被操控的机器上执行cmd命令
1 using System.Management; 2 using System.Security.Principal; 3 using System.Collections.Generic; 4 using System; 5 6 namespace MachineControl 7 { 8 public class ExecuteCommand 9 {10 public static void Execute(string remoteMachine, string username, string password, string cmd)11 {12 ConnectionOptions connOptions = new ConnectionOptions13 {14 Impersonation = ImpersonationLevel.Impersonate,15 EnablePrivileges = true,16 Username = username,17 Password = password18 };19 20 ManagementScope scope = new ManagementScope(@"\\" + remoteMachine + @"\root\cimv2", connOptions);21 scope.Connect();22 23 ObjectGetOptions options = new ObjectGetOptions();24 25 // Getting the process class and the process startup class26 ManagementPath processClassPath = new ManagementPath("Win32_Process");27 28 ManagementClass processClass = new ManagementClass(scope, processClassPath, options);29 30 // Settings the parameters for the Create method in the process class31 ManagementBaseObject inArgs = processClass.GetMethodParameters("Create");32 inArgs["CommandLine"] = cmd;33 34 // Invoking the method35 ManagementBaseObject returnValue = processClass.InvokeMethod("Create", inArgs, null);36 if ((uint)(returnValue.Properties["ReturnValue"].Value) != 0)37 throw new Exception("Folder might be already in share or unable to share the directory");38 }39 }40 }
Tool 'Tool.exe'
'Tool.exe':是要拷贝到被操控的机器上的工具,它带有参数,可根据不同参数的命令行进行操控
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Tool 7 { 8 class Program 9 {10 static void Main(string[] args)11 {12 if (args.Length == 1)13 {14 if (args[0] == @"/?")15 Console.WriteLine("if arg = 'Creat', Create a txt file; if arg ='Delete', Delete the txt file.");16 else if (args[0].ToUpper() == "CREATE")17 System.IO.File.Create(@"c:\qm\CreateWithTool.txt");18 else if (args[0].ToUpper() == "DELETE")19 System.IO.File.Delete(@"c:\qm\CreateWithTool.txt");20 }21 }22 }23 }
Client 'Client.exe'
'Client.exe':是操控端代码
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Net; 6 using System.Net.Sockets; 7 using System.Threading; 8 using System.Management; 9 10 using MachineControl;11 12 namespace Client13 {14 class Program15 {16 static bool isConnected = false;17 static void Main(string[] args)18 {19 string shareFolderDirectory = @"c:\qm";20 string shareFolderName = "qm";21 string remoteMachine = "machineName";22 string remoteMachineUserName = @"yonghuming(inclue domain)";23 string remoteMachinePassWord = "password";24 25 string myMachineDomain = "yuming";26 string myMachineUserName = "yonghuming";27 string toolName = "Tool.exe";28 string cmdCreateFolder = string.Format(@"cmd /c md {0}", shareFolderDirectory);29 string cmdExecuteTool = string.Format(@"{0}\{1} {2}", shareFolderDirectory, toolName, "create");30 31 //step 1: create sub direcotry on remtoeMachine 32 ExecuteCommand.Execute(remoteMachine, remoteMachineUserName, remoteMachinePassWord, cmdCreateFolder);33 34 //step 2: create a share folder on remoteMachine35 WindowsShare.MethodStatus status = WindowsShare.CreateShareFolder(shareFolderDirectory, shareFolderName, WindowsShare.ShareType.DiskDrive, "ShareFolder", remoteMachine, remoteMachineUserName, remoteMachinePassWord);36 if (WindowsShare.MethodStatus.Success != status)37 {38 Console.WriteLine(string.Format("Can't create shareFolder, the status is'{0}'.", status.ToString()));39 }40 41 WindowsShare ws = WindowsShare.GetShareByName(remoteMachine, remoteMachineUserName, remoteMachinePassWord, shareFolderName);42 //step 3: get full control of share folder43 ws.SetPermission(myMachineDomain, myMachineUserName, WindowsShare.AccessMaskTypes.FullControl);44 45 //step 4: copy tool to share folder46 System.IO.File.Copy(Environment.CurrentDirectory + @"\" + toolName, @"\\" + remoteMachine + @"\" + shareFolderName + @"\" + toolName);47 48 //step 5: start tool with argument to do special operation on remote machine49 ExecuteCommand.Execute(remoteMachine, remoteMachineUserName, remoteMachinePassWord, cmdExecuteTool);50 }51 52 }53 }
结果
执行到step 3: get full control of share folder时,
执行到step 5: start tool with argument to do special operation on remote machine时,'Tool.exe'会根据命令"c:\qm\Tool.exe create",创建‘CreateWithTool.txt’
参考:
[1]