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

  由于最近做的一个任务需要用到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版本执行交互命令的时候会出现无法执行的情况,原因是版本低的问题

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值