我正在尝试从PowerShell启动一个提升的CMD窗口,但我遇到了一些问题。以下是我现在的代码。机器上有一个管理员帐户,其用户名为" 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
这一切都适用于从用户配置文件运行应用程序而没有此脚本所在的管理员权限,但在调用cmd.exe时,它会按预期启动并具有提升的权限,但会立即关闭。
我也试过用以下内容调用它:
Start-Process "cmd.exe" -Credential $cred -ArgumentList '/k'
这也不起作用。
我通过传递一个参数来测试提升的权限,如下所示,这很好。
Start-Process "cmd.exe" -Credential $cred -ArgumentList 'dir > dir.txt'
这会将dir.txt文件写入C:\ Windows \ System32 \ WindowsPowerShell \ v1.0目录,该目录在用户帐户中被阻止,但不会在管理员帐户测试中被阻止。
有关获取持久性cmd窗口以显示的任何帮助都将非常感激。
由于
答案 0 :(得分:4)
注意:SomeShinyObject在his answer中提出了该方法的基础知识,但他的参数传递技术并不健全( update :自更正后) - 不要使用脚本块代替字符串 - 见底部。
-Verb RunAs
是Start-Process
启动流程提升的原因。
但是, -Verb RunAs
无法与-Credential
参数结合使用,因此您无法直接控制高程发生的用户帐户 - 但是通常没有必要:
安全警告:
如果您仍想按指定实施脚本,解决方法需要 嵌套 2 Start-Process
次来电:
第一个使用-Credential
在指定用户(假定为管理用户)的上下文中运行(总是)非提升命令 。
-Credential
针对的是非管理员用户,建议您同时指定一个-WorkingDir
参数已知指定用户有权访问 - 否则,调用可能会失败(保留当前位置,并且可能不允许目标用户访问它)。嵌入在1st中的第二个,然后使用-Verb RunAs
运行目标命令提升,然后在指定用户的上下文中发生 < / em>的
注意:即使使用包含密码的凭据对象,您仍会收到是/否UAC提示以确认提升意图 - 除非UAC已关闭(不可取)。
工作目录总是$env:SYSTEMROOT\Windows32
; -Verb RunAs
甚至忽略-WorkingDirectory
值;如果要更改为特定目录,请在传递给cd
的命令中嵌入cmd.exe
命令。
此命令完全符合您的要求 - 请注意安全警告:
# 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"'
请注意,embedded,2nd命令作为单字符串传递给(隐含的)-ArgumentList
(a.k.a。-Args
)参数。
在这个简单的情况下,只有1级嵌入式引用 - "
字符串中的'...'
个实例 - 并且不需要扩展(字符串插值),传递单个字符串是可行的选择,但是使用更复杂的命令引用会变得棘手。
-ArgumentList
被定义为类型[string[]]
,即字符串参数的数组。 如果您传递多个,,
- 分隔的参数,那么PowerShell会为您合成命令行,这通常可以更容易地获得正确的引用,特别是涉及变量引用时:
以下命令演示了这种技术:它是一种变体,它传递cmd.exe
的命令来执行,并在该命令中使用变量引用:
$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'"
最终执行的cmd.exe
命令(带有提升)是:
cmd /k echo This is an elevated Command Prompt.
<强> TL;博士强>
乍一看,脚本块({ ... }
)似乎是一个方便的选择:
Start-Process cmd -ArgumentList { /k echo hi! }
上面按照预期在新控制台窗口中执行cmd /k echo hi!
。
语法很方便,因为{ ... }
似乎提供了一个简单引用的上下文:您可以自由使用嵌入式 "
和'
个实例构建命令行。
然而,幕后发生的事情是脚本块被转换为字符串,因为它是-ArgumentList
期望的参数类型,并且< strong>当脚本块转换为字符串时,其文字内容 - 使用{
和}
之间的所有内容 。
这意味着不会发生字符串插值,因此您无法使用变量或子表达式。
尝试根据变量传递命令:
Start-Process cmd -ArgumentList { /k echo Honey, I`'m $HOME! }
这将执行的是:cmd /k echo Honey, I'm $HOME!
- $HOME
未展开。
相比之下,传递插值字符串或参数分别按预期工作:
# 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
在两种情况下都被扩展(插值),类似于
cmd /k echo Honey, I'm C:\Users\jdoe
已执行。
答案 1 :(得分:2)
最好的方法是首先使用Start-Process
参数将您的-Credential
加倍,然后使用管理员凭据,然后在第二个-Verb runas
上加Start-Process
。之后,引用CMD.exe会有点复杂。
总的来说,它看起来应该是这样的。
Start-Process PowerShell -ArgumentList {-noexit -noprofile -Command "Start-Process powershell -argumentlist {-command cmd.exe -args \"/K #yourcommands# \"}" -verb runas} -Credential $Cred
所以抓住这个。阅读mklement0&#39>关于
总是有机会了解更多内容,而且我并不知道在ArgumentList
阻止变量扩展中包含ScriptBlock
。所以......不要这样做。
但该方法保持不变。您仍然需要两次Start-Process
来电,刚才您必须正确引用。
#Both of these work
Start-Process powershell -Credential $cred -ArgumentList "-noprofile", "-command", "Start-Process cmd.exe -Verb RunAs -ArgumentList /k, echo, 'something'"
# $Something will expand into it's value rather than literally
Start-Process powershell -Credential $cred -ArgumentList "-noprofile", "-command", "Start-Process cmd.exe -Verb RunAs -ArgumentList /k, echo, '$something'"