0

我正在尝试使用 diskpart 运行进程,但要做到这一点,我需要管理员权限,因为我在工作中使用 PC。为了以管理员身份运行流程,我需要 Process.StartInfo.Verb = "runas" 并且还需要 Process.StartInfo.UseShellExecute = true。将 UseShellExecute 设置为 true,我无法将命令传递给标准输入,但如果我将其设置为 false,我会收到一条错误消息,提示“请求的操作需要提升”(也就是我需要管理员权限)。如果我尝试将脚本传递给 Process.StartInfo.Arguments 它似乎没有做任何事情。以下是我迄今为止尝试过的几个版本的代码(没有一个有效):

版本 1:

Process p = new Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.FileName = @"C:\Windows\System32\diskpart.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.Arguments = "vhdScript.txt";
p.Start();

版本 2:

Process p = new Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.FileName = @"C:\Windows\System32\diskpart.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.Arguments = "/s vhdScript.txt";
p.Start();

版本 3:

Process p = new Process();
p.StartInfo.UseShellExecute = true;
p.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.Arguments = "/c diskpart /s vhdScript.txt";
p.Start();

版本 4:

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.Arguments = "/c diskpart";
p.StartInfo.RedirectStandardInput = true;
p.Start();
p.StandardInput.WriteLine("select vdisk 1");

有什么想法吗?谢谢。

4

2 回答 2

0

我遵循了这篇文章UseShellExecute=false 和 Raising Elevation中的建议之一

当我使用以下代码创建命令行 exe 并以管理员身份运行时,我得到了我期望的结果。可能对你有用,也可能对你不起作用。(您的示例中的 SELECT VDISK 1 语法不正确,所以我即兴创作)。这可能会有所帮助

using (Process p = new())
{
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.FileName = @"C:\Windows\System32\diskpart.exe";
    p.StartInfo.Verb = "runas";
    //p.StartInfo.Arguments = "/c diskpart";
    p.StartInfo.RedirectStandardInput = true;

    p.Start();

    StreamWriter myStreamWriter = p.StandardInput;
    myStreamWriter.WriteLine("LIST DISK");
    myStreamWriter.Close();
    p.WaitForExitAsync();

}
于 2022-03-03T23:33:30.743 回答
0

下面展示了如何创建一个diskpart脚本,然后使用System.Diagnostics.Process来执行该脚本。

创建一个新Windows Forms App (.NET Framework)项目(名称:ProcessDiskPartTest)

将应用程序清单添加到您的项目

注意:这用于提示用户以管理员身份执行程序。

  • 在 VS 菜单中,单击项目
  • 选择添加新项目...
  • 选择应用程序清单文件(仅限 Windows)(名称:app.manifest)
  • 单击添加

app.manifest中,替换

<requestedExecutionLevel level="asInvoker" uiAccess="false" />

<requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />

添加以下 using 语句

  • using System.IO;
  • using System.Diagnostics;

以下代码将使用Process来执行diskpart脚本。

private void RunDiskPart(string arguments)
{
    string diskpartPath = Path.Combine(Environment.GetEnvironmentVariable("windir"), "System32", "diskpart.exe");

    if (!System.IO.File.Exists(diskpartPath))
        throw new Exception(String.Format("'{0}' doesn't exist.", diskpartPath));

    Debug.WriteLine("diskpartPath: " + diskpartPath);

    ProcessStartInfo psInfo = new ProcessStartInfo(diskpartPath);
    psInfo.Arguments = arguments;
    
    psInfo.CreateNoWindow = true;
    psInfo.RedirectStandardError = true; //redirect standard Error
    psInfo.RedirectStandardOutput = true; //redirect standard output
    psInfo.RedirectStandardInput = false;
    psInfo.UseShellExecute = false; //if True, uses 'ShellExecute'; if false, uses 'CreateProcess'
    psInfo.Verb = "runas"; //use elevated permissions
    psInfo.WindowStyle = ProcessWindowStyle.Hidden;
    
    //create new instance and set properties
    using (Process p = new Process() { EnableRaisingEvents = true, StartInfo = psInfo })
    {
        //subscribe to event and add event handler code
        p.ErrorDataReceived += (sender, e) =>
        {
            if (!String.IsNullOrEmpty(e.Data))
            {
                //ToDo: add desired code 
                Debug.WriteLine("Error: " + e.Data);
            }
        };

        //subscribe to event and add event handler code
        p.OutputDataReceived += (sender, e) =>
        {
            if (!String.IsNullOrEmpty(e.Data))
            {
                //ToDo: add desired code
                Debug.WriteLine("Output: " + e.Data);
            }
        };

        p.Start(); //start

        p.BeginErrorReadLine(); //begin async reading for standard error
        p.BeginOutputReadLine(); //begin async reading for standard output

        //waits until the process is finished before continuing
        p.WaitForExit();
    }
}

下面展示了如何将 diskpart 脚本添加为嵌入式资源。

为您的 DiskPart 脚本创建一个文件夹

  • 在 VS 菜单中,单击查看
  • 选择解决方案资源管理器
  • 在解决方案资源管理器中,右键单击 <项目名称>。选择添加。选择新文件夹(名称:DiskPartScripts)

将 DiskPart 脚本添加到项目

注意:下面的 diskpart 脚本仅用于测试目的。将其重命名为您想要的名称,并将这些命令替换为您想要的 diskpart 命令。

  • 在解决方案资源管理器中,右键单击DiskPartScripts文件夹。选择添加。选择新项目...。
  • 选择文本文件(名称:DiskPartListDisk.txt)

DiskPartListDisk.txt

list disk
list volume

使文本文件成为嵌入式资源

  • 在 VS 菜单中,单击查看
  • 选择属性窗口
  • 在解决方案资源管理器中,单击“DiskpartListDisk.txt”
  • 在属性窗口中,设置构建操作:嵌入式资源

以下用于读取嵌入的文本文件。

创建一个类(名称:HelperLoadResource.cs)

HelperLoadResource.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Diagnostics;

namespace ProcessDiskPartTest
{
    public static class HelperLoadResource
    {
        public static string ReadResource(string filename)
        {
            //use UTF8 encoding as the default encoding
            return ReadResource(filename, Encoding.UTF8);
        }

        public static string ReadResource(string filename, Encoding fileEncoding)
        {
            string fqResourceName = string.Empty;
            string result = string.Empty;

            //get executing assembly
            Assembly execAssembly = Assembly.GetExecutingAssembly();

            //get resource names
            string[] resourceNames = execAssembly.GetManifestResourceNames();

            if (resourceNames != null && resourceNames.Length > 0)
            {
                foreach (string rName in resourceNames)
                {
                    if (rName.EndsWith(filename))
                    {

                        //set value to 1st match
                        //if the same filename exists in different folders,
                        //the filename can be specified as <folder name>.<filename>
                        //or <namespace>.<folder name>.<filename>
                        fqResourceName = rName;

                        //exit loop
                        break;
                    }
                }

                //if not found, throw exception
                if (String.IsNullOrEmpty(fqResourceName))
                {
                    throw new Exception($"Resource '{filename}' not found.");
                }

                //get file text
                using (Stream s = execAssembly.GetManifestResourceStream(fqResourceName))
                {
                    using (StreamReader reader = new StreamReader(s, fileEncoding))
                    {
                        //get text
                        result = reader.ReadToEnd();
                    }
                }
            }

            return result;
        }
    }
}

注意:“ReadResource”的代码来自这里


用法

//temp filename that we'll use for diskpart
string diskpartScriptFilename = Path.Combine(Path.GetTempPath(), String.Format("diskpart_{0}.txt", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name));

//get embedded diskpart script
string diskpartScript = HelperLoadResource.ReadResource("DiskpartListDisk.txt");

//write script to file
File.WriteAllText(diskpartScriptFilename, diskpartScript);

//execute script
RunDiskPart("/s " + diskpartScriptFilename);

if (File.Exists(diskpartScriptFilename))
    File.Delete(diskpartScriptFilename); //delete file

资源

于 2022-03-03T23:23:02.743 回答