英文:
C# Process start powershell and execute command, doesn't have admin permission
问题
首先,我想执行的命令是get-vm
和start-vm
,这些命令需要管理员权限。
在我的应用程序中,我将检查Hyper-V虚拟机的状态,看它是Running还是Off。因此,我需要调用get-vm {vmName}
来获取状态。在获取到虚拟机状态之后,如果状态是Off,那么我将调用start-vm {vmName}
来启动虚拟机。
其次,我使用Process来使用用户名和密码启动PowerShell。
代码如下:
var tmp = CShortPath.GetShortPath(System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()));
var processInfo = new ProcessStartInfo
{
Verb = "runas",
LoadUserProfile = true,
CreateNoWindow = true,
FileName = "powershell.exe",
//Arguments = "Start-VM -name 'win11-Lite'",
Arguments = $"get-VM 'win11-Lite' >{tmp}",
RedirectStandardOutput = false,
UseShellExecute = false,
UserName = "{AdminUserName}",
Password = MakePwd("AdminPwd")
};
Process.Start(processInfo);
如你所见,当执行时,输出文件**{tmp}**为空,并且不会显示UAC权限对话框。
应该怎么办?
英文:
First of all, the commands that i want to execute are get-vm
and start-vm
, which are need admin permission.
In my app , i will check the hyper-v vm state to see it Running or Off. thus , i need to invoke get-vm {vmName}
the get the state. after got the vm state , if the state is Off, then i will invoke start-vm {vmName}
to start the vm.
secondly, i use Process to start PowerShell with UserName and Password.
the code is below:
var tmp = CShortPath.GetShortPath(System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()));
var processInfo = new ProcessStartInfo
{
Verb = "runas",
LoadUserProfile = true,
CreateNoWindow = true,
FileName = "powershell.exe",
//Arguments = "Start-VM -name 'win11-Lite'",
Arguments = $"get-VM 'win11-Lite' >{tmp}",
RedirectStandardOutput = false,
UseShellExecute = false,
UserName = "{AdminUserName}",
Password = MakePwd("AdminPwd")
};
Process.Start(processInfo);
as you see, when executed , the output file {tmp} is empty, and there will not display UAC Permission dialog.
what should do ?
答案1
得分: 2
首先,你需要先检查PowerShell命令/脚本。
然后你需要知道,管理员权限并不是必需的来控制虚拟机。你可以授予任何用户或组所需的权限来控制虚拟机。
接下来,你可以重定向标准输出,而不是使用一个中间文件(以下是Microsoft的示例代码):
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// 为避免死锁,始终先读取输出流,然后再等待进程退出。
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
参考链接:允许非管理员控制Hyper-V
英文:
First of all, you need to check the powershell commands/scripts first.
Then you need to know that the admin permissions are not mandatory to control vms. You can grant any user or group the required rights to control vms.
Then you can redirect the standard output instead of using an intermediate file (Microsoft sample below):
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// To avoid deadlocks, always read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
答案2
得分: 2
注意:
- 如果通过
.UserName
和.Password
以及创建一个提升的进程(.Verb = "RunAs"
)的方式来以编程方式提供凭据的目的是为了绕过UAC(用户账户控制),即避免交互式确认/授权提示,出于安全原因,这基本上是行不通的。1 - 如果您有权限修改权限以允许非管理员控制Hyper-V虚拟机的选项,那么启动一个提升的进程可能并不是必要的-请参阅rotabor的答案。[2]
当使用ProcessStartInfo
实例启动进程时:
.Verb = "RunAs"
(使用提升权限(管理员权限)启动进程)需要.UseShellExecute = true
。- 然而,
.UseShellExecute = true
不能与.UserName
和.Password
组合使用。
这意味着:
- 您只能以当前用户的身份启动一个提升的进程(
.Verb = "RunAs"
,结合.UseShellExecute = true
)。- 要以不同用户的身份启动提升的进程,您需要使用嵌套进程:
- 一个非提升的辅助进程,您可以使用所需的凭据启动该进程。也就是说,省略
.Verb = "RunAs"
。 - 在非提升进程的用户身份上下文中创建的嵌套提升进程。由于您正在调用PowerShell,您可以在PowerShell CLI调用中使用
Start-Process -Verb RunAs
。[2]
- 一个非提升的辅助进程,您可以使用所需的凭据启动该进程。也就是说,省略
- 要以不同用户的身份启动提升的进程,您需要使用嵌套进程:
- 然而,您最终将无法避免UAC对话框。
- 也就是说,按设计,您无法以编程方式绕过UAC,即使提供了管理员的凭据。
- 鉴于必须使用
SecureString
实例来以编程方式提供密码(.Password
),并且考虑到此类型提供的安全性有限,并且不建议在新代码中使用它,最好避免以基于密码的凭据进行编程。
- 鉴于必须使用
- 如果您仍然决定以编程方式指定管理员凭据,您唯一获得的好处是不可避免的UAC提示变成了仅仅是一个确认提示,而不需要在提示时提供管理员的(用户名和)密码。
- 也就是说,按设计,您无法以编程方式绕过UAC,即使提供了管理员的凭据。
1 技术上可以禁用UAC,但强烈建议不要这样做,因为这会使您的系统极易受到攻击。1
[2] Start-Process
基于.NET的ProcessStartInfo
类,因此它受到相同的基本限制:-Verb RunAs
不能与-Credential
组合使用。[2]
英文:
Note:
-
If the intent behind the unsupported attempt to supply credentials programmatically via
.UserName
and.Password
in combination with creating an elevated process (.Verb = "RunAs"
) is to bypass UAC, i.e. to avoid an interactive confirmation/authorization prompt, this fundamentally won't work, for security reasons.<sup>1</sup> -
Launching an elevated process may not even be necessary if you have the option to modify permissions to also allow non-administrators to control Hyper-V VMs - see rotabor's answer.
When using a ProcessStartInfo
instance to launch a process:
.Verb = "RunAs"
(starting a process with elevation (elevated privileges, as administrator) requires.UseShellExecute = true
- However,
.UseShellExecute = true
cannot be combined with.UserName
and.Password
This means:
-
You can only launch an elevated process (
.Verb = "RunAs"
, combined with.UseShellExecute = true
) as the current user.-
To launch an elevated process as a different user, you need nested processes:
-
A non-elevated helper process that you launch with the desired credentials. That is, omit
.Verb = "RunAs"
. -
A nested, elevated process created in the context of the non-elevated process' user identity. Since you're calling PowerShell, you can use
Start-Process
-Verb RunAs
in your PowerShell CLI call.<sup>[2]</sup>
-
-
-
However, you will ultimately invariably get a UAC dialog.
-
That is, by design you can never bypass UAC programmatically, even if you supply an administrator's credentials.
- Given that a
SecureString
instance must be used to supply the password (.Password
) programmatically and given the limited security this type provides and that its use is not recommended in new code, using password-based credentials programmatically is best avoided.
- Given that a
-
If you still decide to specify administrator credentials programmatically, the only thing you gain is that the unavoidable UAC prompt becomes a mere confirmation prompt rather than having to provide an administrator's (username and) password when prompted.
-
<sup>1 It is technically possible to disable UAC, but doing is strongly advised against, as it would leave your system highly vulnerable.</sup>
<sup>[2] Start-Process
builds on the .NET ProcessStartInfo
class, so it is subject to the same fundamental limitation: -Verb RunAs
cannot be combined with -Credential
.</sup>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论