C#调用PowShell执行命令的两种方式

    xiaoxiao2021-04-18  64

      由于最近做的一个任务需要用到C#代码调用PowerShell远程执行代码,所以在参考了一些资料和自己实验整理出两种可行的方式。

      分别为两种方式,一种是发送远程指令操作,一种是执行本地powershell脚本文件。

      在进行操作之前,要先以管理员权限启动powershell软件,先将powershell执行权限调至最高,因为window默认不允许执行任何脚本文件。

      所以我们要在powershell页面执行一条命令来改变powershell环境。

       Set-ExecutionPolicy Unrestricted //最高级的权限,让powershell运行在无限制的环境下

       在VS开始编写代码之前,我们还要先引入一个powershell本身自带的DLL文件,System.Management.Automation.dll,由于win7是默认内置的powershell2.0,所以这个dll一般存在C盘:

       C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0

       文件夹之中,添加引用后,using两个命名空间

      

         原因是在C#和powershell之间建立交流需要用到其中的Runspace类,建立执行powershell命令的独立通信通道,而其中的pipeline.类可以为我们提供执行powershell指令后提供的返回值。

      做的任务是C#通过Powshell远程操作网络服务器,首先是执行脚本的方法。

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Management.Automation.Runspaces; using System.Management.Automation; using System.Management; using System.Collections.ObjectModel; using System.IO; namespace DHCP.Test {     class Class2     {         private static string RunPowershell(string filePath, string parameters)         {             RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();             Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);             runspace.Open();             RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);             Pipeline pipeline = runspace.CreatePipeline();             Command scriptCommand = new Command(filePath);             Collection<CommandParameter> commandParameters = new Collection<CommandParameter>();             string[] tempParas = parameters.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);             for (int i = 0; i < tempParas.Length; i += 2)             {                 CommandParameter commandParm = new CommandParameter(tempParas[i], tempParas[i + 1]);                 commandParameters.Add(commandParm);                 scriptCommand.Parameters.Add(commandParm);             }             pipeline.Commands.Add(scriptCommand);             var re = pipeline.Invoke();//在pipeline管道类线程上执行委托,并且获取到执行命令后的返回值             string kk = "";             foreach (var a in re)             {                 kk = a.ToString() + kk;//打印返回信息             }             if (pipeline.Error.Count > 0)             {                 throw new Exception("脚本执行失败");             }             runspace.Close();//关闭通信通道             return kk;         }         static void Main(string[] args)         {             string re = RunPowershell(@".\test2.ps1", "");//执行项目中的脚本,注意,脚本ps1文件需要放在源代码DHCP.Test\bin\Debug 文件下             Console.WriteLine(re);             Console.ReadLine();         }     } }

      再接下来是直接执行远程指令的方法,通过Runspace类直接传输字符串型的powershell指令

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Management.Automation.Runspaces; using System.Management.Automation; using System.Management; using System.Collections.ObjectModel; namespace DHCP.Test {     class Class1     {         static int ipnum = 0;         static string[] ip1 = new string[100];         //添加方法,需传入各项指定好的参数,MAC地址有点问题,         //各项参数 1.DHCP服务器的总IP   2.作用域的IP  3.保留地址的IP(即电脑的IP)4. 与保留地址对应的MAC地址  5.名称  6.备注         static void AddVlan(string DHCPip, string Vlanip, string ip, string mac, string ComputerName, string Remark)

    //旧式执行代码,使用dos端的执行命令,不严谨,有点小瑕疵,无法对流动的保留地址进行更新,也就是活动标识为active的ip地址         {             string KK = "netsh Dhcp Server " + DHCPip + " Scope " + Vlanip + " Add reservedip " + ip + " " + mac + " \"" + ComputerName + "\" \"" + Remark + "\" \"BOTH\"";             string cmd = "$uname=\"123\\123\"\n$pwd = ConvertTo-SecureString -AsPlainText \"123\" -Force\n$cred =    New-Object System.Management.Automation.PSCredential($uname,$pwd)\n" + "$a = {" + KK + "}\n" + "Invoke-Command -Credential $cred -command $a -ComputerName 10.10.11.111\n" + "$?";             if (CheckPSVlan(ip) == "False")             {                 Console.WriteLine("ip:" + ip + "没有重复,正在添加");                 InvokeSystemPS(cmd);                 if (CheckPSVlan(ip) == "False")                 {                     Console.WriteLine("添加失败,mac地址" + mac + "有问题,请重新输入");                 }                 else                 {                     Console.WriteLine("已经成功添加ip:" + ip + "到域:" + Vlanip + "下");                 }             }             else             {                 Console.WriteLine("输入IP:" + ip + "有重复,请重新输入IP");             }         }         static void AddVlan1(string DHCPip, string Vlanip, string ip, string mac, string ComputerName, string Remark)         {             string KK = "netsh Dhcp Server " + DHCPip + " Scope " + Vlanip + " Add reservedip " + ip + " " + mac + " \"" + ComputerName + "\" \"" + Remark + "\" \"BOTH\"";             string cmd = "$uname=\"123\\123\"\n$pwd = ConvertTo-SecureString -AsPlainText \"123\" -Force\n$cred =    New-Object System.Management.Automation.PSCredential($uname,$pwd)\n" + "$a = {" + KK + "}\n" + "Invoke-Command -Credential $cred -command $a -ComputerName 10.10.11.111\n" + "$?";             InvokeSystemPS(cmd);         }         static void AddVlanNew(string DHCPip, string Vlanip, string ip, string mac, string ComputerName, string Remark)

    //新式的执行代码,使用powershell端的指令,Add方式         {             string str = "add-DhcpServerv4Reservation –ComputerName " + DHCPip + " -ScopeId " + Vlanip + " -IPAddress " + ip + " -ClientId " + mac + " -Name " + ComputerName + " -Description " + "\"" + Remark + "\"";             string cmd = "$uname=\"123\\123\"\n$pwd = ConvertTo-SecureString -AsPlainText \"123\" -Force\n$cred =   New-Object System.Management.Automation.PSCredential($uname,$pwd)\n" + "$a = {" + str + "}\n" + "Invoke-Command -Credential $cred -command $a -ComputerName " + DHCPip + "\n" + "$?";             InvokeSystemPS(cmd);         }         static void DeleteVlan(string ip, string mac)//删除方法,IP为保留地址,mac为对应的mac地址,但是随意输入的mac地址也能删除,所以猜测IP才是最主要的         {             string KK1 = "netsh dhcp server 10.10.11.111 scope 10.10.22.0 delete reservedip " + ip + " " + mac;             string cmd1 = "$uname=\"123\\123\"\n$pwd = ConvertTo-SecureString -AsPlainText \"123\" -Force\n$cred =    New-Object System.Management.Automation.PSCredential($uname,$pwd)\n" + "$a = {" + KK1 + "}\n" + "Invoke-Command -Credential $cred -command $a -ComputerName 10.10.11.111\n" + "$?";             if (CheckPSVlan(ip) != "False")             {                 InvokeSystemPS(cmd1);                 Console.WriteLine("IP:" + ip + "已经成功删除");             }             else             {                 Console.WriteLine("目标IP:" + ip + "不存在");             }         }         //不仅仅10.10.1.133一个基地         // static string CheckPSVlan(string DHCPIP,string ip)         //正式使用时候备用,传入查询ip的地址和DHCP服务器的IP         static string CheckPSVlan(string ip)//通过GET方法检查有没有重复的IP,如果没有则返回False(注意是字符串,F为大写),即域下面没有存在保留地址

    //查询指定IP信息,不过只返回该IP下的IPAddress信息         {             string KK1 = "Get-DhcpServerv4Lease -IPAddress " + ip + " | fl IPAddress";             string cmd1 = "$uname=\"123\\123\"\n$pwd = ConvertTo-SecureString -AsPlainText \"123\" -Force\n$cred =    New-Object System.Management.Automation.PSCredential($uname,$pwd)\n" + "$a = {" + KK1 + "}\n" + "Invoke-Command -Credential $cred -command $a -ComputerName 10.10.11.111\n" + "$?";             //如果返回值为False时,则没有对应IP,如果返回其他值则是已经存在重复IP             return InvokeSystemPS(cmd1);         }         public static string InvokeSystemPS(string cmd)//提交方法,将命令传入,打开与powershell交互的工作流,提交命令,并获得返回值         {             string kk = "";             try             {                 List<string> ps = new List<string>();                 //开启计算机的安全设置,允许执行可能会用到                 //开启最高的执行权限                 //Unrestricted——允许所有的script运行                 ps.Add("Set-ExecutionPolicy RemoteSigned");                 ps.Add("Set-ExecutionPolicy -ExecutionPolicy Unrestricted");                 ps.Add(cmd);                 Runspace runspace = RunspaceFactory.CreateRunspace();                 runspace.Open();                 Pipeline pipeline = runspace.CreatePipeline();                 foreach (var scr in ps)                 {                     pipeline.Commands.AddScript(scr);                 }                 var test = pipeline.Invoke();//Execute the ps script                 foreach (var item in test)                 {                     //Type typename = item.ImmediateBaseObject.GetType();//获得通道中返回的最原始基类对象                     string member = test[0].Members.ElementAt(3).Value.ToString();//返回对象中的第四个属性,保留活动标识,AddressState                     string a = member.Substring(0, member.Length);//分隔保留活动标识字符串                     //var A = Convert.ChangeType(item.ImmediateBaseObject, typename);//返回指定类型的对象                                          Console.WriteLine(typename);//打印返回基类对象信息                     Console.WriteLine(a);//打印保留活动标识字符串                     //Console.WriteLine(item.ToString());//打印从通道流中的返回值信息                 //}                 foreach (var a in test)                 {                     kk = a.ToString() + kk;                     Console.WriteLine(kk);//打印返回信息                 }                 runspace.Close();             }             catch (Exception ex)             {                 throw ex;             }             return kk;         }         static string CheckPSVlan1(string ip)

    //查询指定IP信息,并返回此IP下的所有信息         {             string KK1 = "Get-DhcpServerv4Lease -IPAddress " + ip;             string cmd1 = "$uname=\"123\\123\"\n$pwd = ConvertTo-SecureString -AsPlainText \"123\" -Force\n$cred =    New-Object System.Management.Automation.PSCredential($uname,$pwd)\n" + "$a = {" + KK1 + "}\n" + "Invoke-Command -Credential $cred -command $a -ComputerName 10.10.11.111\n" + "$?";             //如果返回值为False时,则没有对应IP,如果返回其他值则是已经存在重复IP

    //get 命令,获取服务器中是否存在指定IP,查询语句             return InvokeSystemPS(cmd1);         }         static void Main(string[] args)         {             List<string[]> ip = new List<string[]>();             string[] es = { "10.10.11.111", "10.10.22.0", "10.10.22.127", "4B-99-B6-D4-AE-8D", "测试电脑", "这是一个备注" };             ip.Add(es);                //AddVlanNew(es[0],es[1],es[2],es[3],es[4],es[5]);                 CheckPSVlan1("10.10.22.127");                 //CheckPSVlan("10.10.22.127");                 //AddVlan1(ip[0][0], ip[0][1], ip[0][2], ip[0][3], ip[0][4], ip[0][5]);                 //DeleteVlan(ip[0][2],ip[0][3]);             Console.ReadLine();         }     } }

    这两种方法,耗时基本上一致,远程执行指令稍微比脚本执行快上0.6S左右(插入5条数据)

    基本耗时都在35-40S之间波动,原因是查询IP信息所花费时间较长,一次查询信息需要大概15S左右的时间,插入仅需要5s左右

    还有个需要注意的问题,使用前最好将powershell升级到3.0版本,win7一般自带版本为2.0,2.0版本执行交互命令的时候会出现无法执行的情况,原因是版本低的问题

    转载请注明原文地址: https://ju.6miu.com/read-674840.html

    最新回复(0)