在C#中以管理员权限运行进程时,如何使用RedirectStandardInput



我正试图使用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:WindowsSystem32diskpart.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:WindowsSystem32diskpart.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:WindowsSystem32cmd.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:WindowsSystem32cmd.exe";
p.StartInfo.Verb = "runas";
p.StartInfo.Arguments = "/c diskpart";
p.StartInfo.RedirectStandardInput = true;
p.Start();
p.StandardInput.WriteLine("select vdisk 1");

有什么想法吗?谢谢

以下显示如何创建磁盘部件脚本,然后使用System.Diagnostics.Process执行该脚本。

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

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

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

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

应用程序清单中,替换

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

带有

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

添加以下使用语句

  • 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

资源

  • 磁盘部件
  • System.Diagnostics.Process
  • 如何读取嵌入的资源文本文件

我遵循了本文中的一条建议UseShellExecute=false和Raising Elevation

当我用下面的代码创建一个命令行exe并以管理员身份运行时,我会得到预期的结果。可能为你工作,也可能不为你工作。(您的示例中SELECT VDISK 1语法不正确,所以我即兴创作(。这可能有助于

using (Process p = new())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = @"C:WindowsSystem32diskpart.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();
}

相关内容

最新更新