用代码操控另一台电脑
用代码操控另一台电脑
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,设置权限
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 IList<WindowsShare> GetAllShareFolders(string remoteMachine, string userName, string passWord) 91 { 92 IList<WindowsShare> result = new List<WindowsShare>(); 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<WindowsShare> GetAllShares() 108 { 109 IList<WindowsShare> result = new List<WindowsShare>(); 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<WindowsShare> 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<WindowsShare> 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<WindowsShare> shares = GetAllShares(); 139 foreach (WindowsShare s in shares) 140 if (s.Path.ToUpper() == path) 141 return s; return null; 142 } 143 #endregion 144 #region method 145 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 #endregion 166 } 167 }
Class 'ExecuteCommand' :该类负责在被操控的机器上执行cmd命令
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 ConnectionOptions 13 { 14 Impersonation = ImpersonationLevel.Impersonate, 15 EnablePrivileges = true, 16 Username = username, 17 Password = password 18 }; 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 class 26 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 class 31 ManagementBaseObject inArgs = processClass.GetMethodParameters("Create"); 32 inArgs["CommandLine"] = cmd; 33 34 // Invoking the method 35 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':是要拷贝到被操控的机器上的工具,它带有参数,可根据不同参数的命令行进行操控
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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':是操控端代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 Client 13 { 14 class Program 15 { 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 remoteMachine 35 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 folder 43 ws.SetPermission(myMachineDomain, myMachineUserName, WindowsShare.AccessMaskTypes.FullControl); 44 45 //step 4: copy tool to share folder 46 System.IO.File.Copy(Environment.CurrentDirectory + @"\" + toolName, @"\\" + remoteMachine + @"\" + shareFolderName + @"\" + toolName); 47 48 //step 5: start tool with argument to do special operation on remote machine 49 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’