从 Powershell 启动 Elevated CMD.exe [英] Launch Elevated CMD.exe from Powershell

查看:58
本文介绍了从 Powershell 启动 Elevated CMD.exe的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 PowerShell 启动提升的 CMD 窗口,但我遇到了一些问题.以下是我现在拥有的代码.机器上有一个管理员帐户,用户名是test",密码是test"

$username = "test"$password = ConvertTo-SecureString "test" -AsPlainText -Force$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password启动进程cmd.exe"-Credential $cred

这对于从没有管理员权限的用户配置文件中运行应用程序来说一切正常,但是在调用 cmd.exe 时,它​​会以提升的权限按预期启动,但随后立即关闭.

我也尝试使用以下方法调用它:

Start-Process "cmd.exe" -Credential $cred -ArgumentList '/k'

这也不起作用.
我通过传递如下参数来测试提升的权限,这工作正常.

Start-Process "cmd.exe" -Credential $cred -ArgumentList 'dir >目录.txt'

这会将 dir.txt 文件写入 C:\Windows\System32\WindowsPowerShell\v1.0 目录,该目录在用户帐户上被阻止,但对于管理员帐户测试没有.

任何有关显示持久 cmd 窗口的帮助将不胜感激.

谢谢

解决方案

注意:SomeShinyObject 在 他的答案,但他的参数传递技术并不健壮(更新:因为已更正) - 不要使用脚本块代替字符串 - 请参阅底部.

  • -Verb RunAs 使 Start-Process 启动进程提升.>

  • 但是,-Verb RunAs 不能与 -Credential 参数结合使用,所以你不能直接控制提升发生在哪个用户帐户 - 但这通常没有必要:

    • 如果当前用户是管理员,提升总是发生在该用户的上下文中,GUI 提示只是要求确认.
    • 否则,会显示一个 GUI 对话框,要求输入管理员的用户名和密码(用户名字段为空).

安全警告:

  • 以纯文本形式存储密码通常存在安全风险.
  • 此外,如果您让非管理员用户使用存储的管理员凭据执行以下代码,您实际上是在授予他们管理员权限.

如果您仍想按照指定的方式实现脚本,解决方法需要嵌套 2次Start-Process调用:

  • 第一个在指定用户的上下文中隐形运行(总是)非提升命令 - 假设是管理用户 - 使用 -Credential.

    • 由于指定的用户是管理员,这里不是问题,但是如果-Credential针对的是非管理员用户,建议也指定一个-WorkingDir 参数表明指定用户具有访问权限 - 否则,调用可能会失败(保留当前位置,并且可能不允许目标用户访问).
  • 第二个,嵌入在第一个中,然后使用 -Verb RunAs 运行目标命令 elevated,然后在上下文中发生指定用户的.

    • 注意:即使使用包含密码的凭据对象,您仍会收到是/否 UAC 提示以确认提升的意图 - 除非 UAC 已关闭(即不可取).

    • 工作目录总是$env:SYSTEMROOT\Windows32-Verb RunAs 甚至忽略 -WorkingDirectory 值;如果要切换到特定目录,请在传递给 cmd.exe 的命令中嵌入 cd 命令.

此命令完全符合您的要求 - 请注意安全警告:

# 构造凭证对象$username = "jdoe"# CAVEAT:以纯文本形式存储密码通常存在安全风险.# 另外,如果你让非管理用户执行这个# 带有存储密码的代码,您实际上是在给他们# 管理权限.$password = ConvertTo-SecureString "test" -AsPlainText -Force$cred = 新对象 PSCredential -Args $username, $password# 以 $username 用户身份启动提升的命令提示符 (cmd).启动进程 powershell.exe -Credential $cred -WindowStyle Hidden `'-noprofile -command 启动进程 cmd.exe -Verb RunAs"'

请注意,嵌入的第二个命令作为单个字符串传递给(隐含的)-ArgumentList(又名 -Args)参数.

在这个简单的例子中,只有 1 级嵌入引用 - '...' 字符串中的 " 实例 - 并且不需要扩展(字符串插值),传递单个字符串是一个可行的选择,但使用更复杂的命令引用变得棘手.

-ArgumentList 定义为 [string[]] 类型,即字符串参数的数组.如果您传递多个分隔的参数,则是PowerShell为您合成命令行,这通常会更容易获得引用正确,尤其是在涉及变量引用时:

以下命令演示了这种技术:它是一个变体,它传递一个命令供 cmd.exe 执行,并在该命令中使用变量引用:

$msg = '这是一个提升的命令提示符.'启动进程 powershell.exe -Credential $cred -WindowStyle Hidden -Args `'-noprofile', '-command', "Start-Process cmd.exe -Verb RunAs -Args/k, echo, '$msg'"

最终执行的cmd.exe命令(有提升)是:
cmd/k echo 这是一个提升的命令提示符.

<小时>

可选阅读:为什么使用脚本块代替字符串是不明智的

tl;dr

  • 不要养成在需要字符串的地方使用脚本块的习惯.虽然方便,但它并不健壮,记住它何时以及为什么会失败是很重要的.

乍一看,脚本块 ({ ... }) 似乎是一个方便的选项:

Start-Process cmd -ArgumentList {/k echo hi!}

上面按预期在新的控制台窗口中执行 cmd/k echo hi!.语法很方便,因为 { ... } 似乎提供了一个易于引用的上下文:您可以自由使用 embedded "' 实例来构建你的命令行.

然而,在幕后发生的是脚本块被转换为字符串,因为这是-ArgumentList期望的参数类型,并且当一个脚本块被转换为字符串时,它的文字内容 - {} 之间的所有内容 -使用.
这意味着不会发生字符串插值,因此您不能使用变量或子表达式.

尝试传递基于变量的命令:

 Start-Process cmd -ArgumentList {/k echo 亲爱的,我是 $HOME!}

这将执行的是:cmd/k echo 亲爱的,我是 $HOME! - $HOME 没有展开.

相比之下,单独传递内插字符串或参数可以按预期工作:

# 作为单个字符串(参数列表):Start-Process cmd -ArgumentList "/k echo 亲爱的,我是 $HOME!"# 作为参数数组:Start-Process cmd -ArgumentList/k, echo, "亲爱的,我是 $HOME!"

$HOME 在这两种情况下都被扩展(内插),类似于
cmd/k echo 亲爱的,我是 C:\Users\jdoe 被执行了.

I am trying to launch an elevated CMD window from PowerShell but I am running into some issues. Below is the Code I have now. There is an admin account on the machine that has the username of "test" and a Password of "test"

$username = "test"
$password = ConvertTo-SecureString "test" -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $password
Start-Process "cmd.exe" -Credential $cred

This is all working fine for running an application from the user profile with no administrator rights that this script sits in, but when calling the cmd.exe it launches as expected with elevated rights but then immediately closes.

I have also tried calling it with the following:

Start-Process "cmd.exe" -Credential $cred -ArgumentList '/k'

This also is not working.
I tested the elevated permissions by passing in an argument as follows and this works fine.

Start-Process "cmd.exe" -Credential $cred -ArgumentList 'dir > dir.txt'

This will write out a dir.txt file to the C:\Windows\System32\WindowsPowerShell\v1.0 directory which is blocked on the user account but not for the administrator account test.

Any help on getting a persistent cmd window to show would be greatly appreciated.

Thanks

解决方案

Note: SomeShinyObject came up with the fundamentals of the approach in his answer, but his parameter-passing technique is not robust (update: since corrected) - do not use script blocks in lieu of strings - see bottom.

  • -Verb RunAs is what makes Start-Process launch a process elevated.

  • However, -Verb RunAs cannot be combined with the -Credential parameter, so you cannot directly control under what user account the elevation happens - but that is generally not necessary:

    • If the current user is an administrator, elevation invariably happens in the context of that user, with the GUI prompt just asking for confirmation.
    • Otherwise, a GUI dialog is shown, asking for an administrator's username and password (with the username field blank).

Security caveats:

  • Storing a password as plain text is a security risk in general.
  • Additionally, if you let non-administrative users execute the code below with stored admin credentials, you're effectively giving them administrative rights.

If you still want to implement your script as specified, a workaround requires nesting 2 Start-Process calls:

  • The 1st one runs an (invariably) non-elevated command invisibly in the context of the specified user - assumed to be an administrative user - using -Credential.

    • Since the specified user is an administrator, it's not a concern here, but if -Credential targets a non-admin user, it is advisable to also specify a -WorkingDir argument that the specified user is known to have permissions to access - otherwise, the call may fail (the current location is retained, and the target user may not be allowed to access it).
  • The 2nd one, embedded in the 1st, then uses -Verb RunAs to run the target command elevated, which then happens in the context of the specified user.

    • Note: Even with a credentials object that includes the password, you will still get the yes/no UAC prompt to confirm the intent to elevate - unless UAC has been turned off (which is not advisable).

    • The working directory will invariably be $env:SYSTEMROOT\Windows32; -Verb RunAs ignores even a -WorkingDirectory value; if you want to change to a specific directory, embed a cd command in the command passed to cmd.exe.

This command does exactly what you asked for - please note the security caveat:

# Construct the credentials object
$username = "jdoe"
# CAVEAT: Storing a password as plain text is a security risk in general.
#         Additionally, if you let non-administrative users execute this 
#         code with a stored password, you're effectively giving them
#         administrative rights.
$password = ConvertTo-SecureString "test" -AsPlainText -Force    
$cred = New-Object PSCredential -Args $username, $password

# Start an elevated Command Prompt (cmd) as user $username.
Start-Process powershell.exe -Credential $cred -WindowStyle Hidden `
 '-noprofile -command "Start-Process cmd.exe -Verb RunAs"'

Note that the embedded, 2nd command is passed as a single string to the (implied) -ArgumentList (a.k.a. -Args) parameter.

In this simple case, with only 1 level of embedded quoting - the " instances inside the '...' string - and no need for expansions (string interpolation), passing a single string is a viable option, but with more sophisticated commands quoting gets tricky.

-ArgumentList is defined as type [string[]], i.e., an array of string arguments. If you pass multiple, ,-separated arguments, it is PowerShell that synthesizes the command line for you, which usually makes it easier to get the quoting right, especially when variable references are involved:

The following command demonstrates this technique: It is a variant that passes a command for cmd.exe to execute through, and uses a variable reference in that command:

$msg = 'This is an elevated Command Prompt.'

Start-Process powershell.exe -Credential $cred -WindowStyle Hidden -Args `
 '-noprofile', '-command', "Start-Process cmd.exe -Verb RunAs -Args /k, echo, '$msg'"

The cmd.exe command that is ultimately executed (with elevation) is:
cmd /k echo This is an elevated Command Prompt.


Optional Reading: Why using script blocks in lieu of strings is ill-advised

tl;dr

  • Do not get into the habit of using script blocks where strings are expected. While convenient, it is not robust, and remembering when and why it will fail is nontrivial.

At first glance, script blocks ({ ... }) seem like a convenient option:

Start-Process cmd -ArgumentList { /k echo hi! }

The above executes cmd /k echo hi! in a new console window, as expected. The syntax is convenient, because the { ... } seemingly provide a context in which quoting is easy: you're free to use embedded " and ' instances to construct your command line.

However, what happens behind the scenes is that a script block is converted to a string, because that's the type of argument(s) -ArgumentList expects, and when a script block is converted to a string, its literal contents - everything between { and } - is used.
This means that no string interpolation takes place, so you cannot use variables or subexpressions.

Take this attempt to pass a command based on a variable:

 Start-Process cmd -ArgumentList { /k echo Honey, I`'m $HOME! }

What this will execute is: cmd /k echo Honey, I'm $HOME! - $HOME was not expanded.

By contrast, passing either an interpolated string or the arguments individually works as intended:

# As a single string (argument list):
Start-Process cmd -ArgumentList "/k echo Honey, I'm $HOME!"

# As an array of arguments:
Start-Process cmd -ArgumentList /k, echo, "Honey, I'm $HOME!"

$HOME is expanded (interpolated) in both cases, and something like
cmd /k echo Honey, I'm C:\Users\jdoe is executed.

这篇关于从 Powershell 启动 Elevated CMD.exe的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆