miocaro507 发表于 2022-12-13 13:41

C# 执行PowerShell脚本的问题

本帖最后由 miocaro507 于 2022-12-13 13:46 编辑

以下是一段C#执行PowerShell脚本的代码,其作用是结束远程计算机上的某个进程。但是这样运行之后,最后会输出以下错误:

Errors - Get-WmiObject : Invalid query "select * from Win32_Process where name = LabelPrinting.exe"
At line:1 char:14
+ ... Processes = Get-WmiObject -Class Win32_Process -ComputerName DSK0550...
+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) , ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

如果把变量script的值拷贝出来,贴到PowerShell的窗口去执行,则可以正常执行。请教是不是因为双引号造成的?怎么解决?谢谢


            StringBuilder script = new StringBuilder();
            script.AppendLine(string.Format("$Processes = Get-WmiObject -Class Win32_Process -ComputerName {0} -Filter 'name = \"{1}\"';", "DSK0550", "LabelPrinting.exe"));
            script.AppendLine("foreach ($process in $processes) {");
            script.AppendLine("$returnval = $process.terminate()");
            script.AppendLine("if($returnval.returnvalue -eq 0) {");
            script.AppendLine("write-host \"Closed\"");
            script.AppendLine("} else {");
            script.AppendLine("write-host \"Failed\"");
            script.AppendLine("}");
            script.AppendLine("}");

            ProcessStartInfo processInfo = new ProcessStartInfo();
            processInfo.FileName = @"powershell.exe";
            processInfo.Arguments = script.ToString();
            processInfo.RedirectStandardError = true;
            processInfo.RedirectStandardOutput = true;
            processInfo.UseShellExecute = false;
            processInfo.CreateNoWindow = true;

            //start powershell process using process start info
            Process process = new Process();
            process.StartInfo = processInfo;
            process.Start();
            process.WaitForExit();
            Console.WriteLine("Errors - {0}", process.StandardError.ReadToEnd());

MIAIONE 发表于 2022-12-13 13:56

本帖最后由 MIAIONE 于 2022-12-13 13:58 编辑

可不可以考虑用内部WMI实现? 毕竟底层都是WMI服务
https://learn.microsoft.com/zh-cn/windows/win32/wmisdk/connecting-to-wmi-remotely-with-c-

jackyyue_cn 发表于 2022-12-13 14:05

进程名称用单引号试试?

miocaro507 发表于 2022-12-13 15:07

jackyyue_cn 发表于 2022-12-13 14:05
进程名称用单引号试试?

试了,不行,因为name前边已经有单引号了

coolcalf 发表于 2022-12-13 16:09

using System;
using System.Collections.Generic;
using System.Text;

using System.Diagnostics;
namespace Subversion.GUI
{
    class DosCommandOutput
    {
      /// <summary>
      /// 执行DOS命令,返回DOS命令的输出
      /// </summary>
      /// <param name="dosCommand">dos命令</param>
      /// <returns>返回输出,如果发生异常,返回空字符串</returns>
      public static string Execute(string dosCommand)
      {
            return Execute(dosCommand, 60 * 10000);
      }
      /// <summary>
      /// 执行DOS命令,返回DOS命令的输出
      /// </summary>
      /// <param name="dosCommand">dos命令</param>
      /// <param name="milliseconds">等待命令执行的时间(单位:毫秒),如果设定为0,则无限等待</param>
      /// <returns>返回输出,如果发生异常,返回空字符串</returns>
      public static string Execute(string dosCommand, int milliseconds)
      {
            string output = "";   //输出字符串
            if (!string.IsNullOrEmpty(dosCommand))
            {
                Process process = new Process();   //创建进程对象
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = "cmd.exe";      //设定需要执行的命令
                startInfo.Arguments = "/C " + dosCommand;   //设定参数,其中的“/C”表示执行完命令后马上退出
                startInfo.UseShellExecute = false;   //不使用系统外壳程序启动
                startInfo.RedirectStandardInput = false;   //不重定向输入
                startInfo.RedirectStandardOutput = true;   //重定向输出
                startInfo.CreateNoWindow = true;   //不创建窗口
                process.StartInfo = startInfo;
                try
                {
                  if (process.Start())       //开始进程
                  {
                        if (milliseconds == 0)
                            process.WaitForExit();   //这里无限等待进程结束
                        else
                            process.WaitForExit(milliseconds);//这里等待进程结束,等待时间为指定的毫秒
                        output = process.StandardOutput.ReadToEnd();//读取进程的输出
                  }
                }
                catch
                {
                }
                finally
                {
                  if (process != null)
                        process.Close();
                }
            }
            return output;
      }

      public static string ExecuteEx(string dosCommand)
      {
            return ExecuteEx(dosCommand, 60 * 10000);
      }

      public static string ExecuteEx(string dosCommand, int milliseconds)
      {
            string output = "";   //输出字符串
            if (!string.IsNullOrEmpty(dosCommand))
            {
                Process process = new Process();   //创建进程对象
                ProcessStartInfo startInfo = new ProcessStartInfo();
                startInfo.FileName = "cmd.exe";      //设定需要执行的命令
                startInfo.Arguments = "/C " + dosCommand;   //设定参数,其中的“/C”表示执行完命令后马上退出
                startInfo.UseShellExecute = false;   //不使用系统外壳程序启动
                startInfo.RedirectStandardInput = false;   //不重定向输入
                //startInfo.RedirectStandardOutput = true;   //重定向输出
                startInfo.CreateNoWindow = true;   //不创建窗口
                process.StartInfo = startInfo;
                try
                {
                  if (process.Start())       //开始进程
                  {
                        if (milliseconds == 0)
                            process.WaitForExit();   //这里无限等待进程结束
                        else
                            process.WaitForExit(milliseconds);//这里等待进程结束,等待时间为指定的毫秒
                        output = process.StandardOutput.ReadToEnd();//读取进程的输出
                  }
                }
                catch
                {
                }
                finally
                {
                  if (process != null)
                        process.Close();
                }
            }
            return output;
      }
    }

}

apull 发表于 2022-12-13 20:38

本帖最后由 apull 于 2022-12-13 20:42 编辑

可以把执行内容写到ps1文件里,用-Filet.ps1的参数执行。

      StringBuilder script = new StringBuilder();
      script.AppendLine(string.Format("$Processes = Get-WmiObject -Class Win32_Process -ComputerName {0} -Filter 'name = \"{1}\"';", "DSK0550", "LabelPrinting.exe"));
      script.AppendLine("foreach ($process in $Processes) {");
      script.AppendLine("$returnval = $process.terminate()");
      script.AppendLine("if($returnval.returnvalue -eq 0) {");
      script.AppendLine("write-host \"Closed\"");
      script.AppendLine("} else {");
      script.AppendLine("write-host \"Failed\"");
      script.AppendLine("}");
      script.AppendLine("}");

      string file = Path.GetTempPath() + "t.ps1";
      using (StreamWriter sw = new StreamWriter(file))
      {
            sw.Write(script.ToString());
      }

      ProcessStartInfo processInfo = new ProcessStartInfo();
      processInfo.FileName = @"powershell.exe";
      //processInfo.Arguments = script.ToString();
      processInfo.Arguments = string.Format("-File {0}", file);
      processInfo.RedirectStandardError = true;
      processInfo.RedirectStandardOutput = true;
      processInfo.UseShellExecute = false;
      processInfo.CreateNoWindow = true;

      //start powershell process using process start info
      Process process = new Process();
      process.StartInfo = processInfo;
      process.Start();
      process.WaitForExit();
      Console.WriteLine("Errors - {0}", process.StandardError.ReadToEnd());

      File.Delete(file);

miocaro507 发表于 2022-12-14 13:36

apull 发表于 2022-12-13 20:38
可以把执行内容写到ps1文件里,用-Filet.ps1的参数执行。

      StringBu ...

太感谢了,你的办法可行!但是需要以管理员打开PowerShell,执行以下脚本:

Set-ExecutionPolicy -scope CurrentUser Unrestricted

否则会报 t.ps1 cannot be loaded because running scripts is disabled on this system.
页: [1]
查看完整版本: C# 执行PowerShell脚本的问题