如何在保持环境的同时在单独的 window 中启动另一个 PowerShell 会话?

How to start another PowerShell session in a separate window while keeping the environment?

在使用 PowerShell 时,我倾向于通过键入来快速切换到管理模式

Start-Process wt -Verb runas

当我这样做时,会出现一个新的 window(遗憾的是,Windows 中没有 sudo)。然而,在那个新的会话中,环境是全新的。是否可以在跳转到新的 window 时保留变量、别名、工作目录和所有其他类似内容?如果不是,那么好吧,这是一个有效的答案。


举个例子,我正在寻找这种行为:

第一个window

C:\test> $x = 123
C:\test> Start-Process wt

新建window

C:\test> $x
123

您不能保留变量,在创建新的 window 后您会立即丢失它们,最好的办法是创建一个包含所有活动的脚本,然后将其保存在同一工作目录中.

当您打开一个新的 window 时,只需调用您的脚本,它就能为您提供与另一个 window 中相同的信息。

根据 (security-minded) 设计,提升 会话 (-Verb RunAs) 继承调用者的 环境变量.

此外,无论您是否使用 -Verb RunAsPowerShell 会话的状态(别名、函数、当前位置...)都是 从不 在您启动另一个 PowerShell 进程时继承,例如使用 Start-Process.


您可以根据调用者状态的值,通过在提升的会话中执行的命令显式和选择性地重新定义感兴趣的状态来解决此问题,但这非常麻烦且有局限性,如以下示例所示:

# Define a few things to copy to the elevated session.
$x1 = 123
$x2 = '3" of snow' # !! See the caveat re regular variables below.
$env:foo = 1
$env:foo2 = 2
Set-Alias bar Get-Date
function baz { "hello, world" }

# Note: The following only copies the definitions above.
#       You could try to copy ALL such definitions, by omitting a target name / pattern:
#         Get-ChildItem env:
#         Get-ChildItem function:
#         Get-ChildItem alias:
#       CAVEAT: This will NOT generally work with *regular variables*.
Start-Process -Verb RunAs powershell @"
-NoExit -Command Set-Location -LiteralPath \"$((Get-Location -PSProvider FileSystem).ProviderPath)\"
$(Get-Variable x? | ForEach-Object { "`${$($_.Name)} = $(if ($_.Value -is [string]) { "'{0}'" -f ($_.Value -replace "'", "''" -replace '"', '\"')  } else { $_.Value }); " })
$(Get-ChildItem env:foo* | ForEach-Object { "Set-Item \`"env:$($_.Name)\`" \`"$($_.Value -replace '"', '\"\"')\`"; " })
$(Get-ChildItem function:bar | ForEach-Object { "`$function:$($_.Name) = \`"$($_.Definition -replace '"', '\"\"')\`"; " })
$(Get-ChildItem alias:baz | ForEach-Object { "`$alias:$($_.Name) = \`"$($_.Definition)\`"; " })
"@

重要:

  • 我省略了对 Windows 终端 (wt.exe) 的调用,因为那样会创建 另一个 PowerShell 会话,这意味着只为 that 会话保留以下定义:

    • 环境变量。
    • 当前位置(工作目录),IF其默认shell配置为使用父进程的工作目录。或者,更可预测的是,传递工作目录。明确地使用 -d 选项:
      wt.exe -d \"$((Get-Location -PSProvider FileSystem).ProviderPath)\"
    • 如果够了,您可以删除保留别名、函数和常规变量的命令,将-WindowStyle Hidden添加到Start-Process,删除-Command之前的-NoExit 在参数列表中,并在底部添加一个 wt.exe 调用。
  • 保留其他类型的定义需要直接在提升的 powershell 会话中工作,这将始终使用 常规 (conhost.exe) 控制台 window,但是。

一般来说,最好在 $PROFILE file.

中放置应该在常规会话和高级会话中都可用的定义

作为补充,请参阅 以了解便利功能 Enter-AdminPSSession,它允许您传递一个脚本块以在提升的会话中执行,您可以将调用者状态的值作为参数传递给该脚本块。

注:

  • 以上使用Windows PowerShell CLI,powershell.exe。要改用 PowerShell (Core) 7+,请替换为 pwsh.exe.

  • 上面涵盖了在 generic 时尚.

  • 警告:相比之下,保留常规变量仅限于字符串和数字 - 本质上,那些数据类型的实例,当解释为 source-code 文字时,其字符串化表示被识别为这样。

    • 通过不平凡的额外努力,通过使用 Base64 编码和 CLI 的 -EncodedCommand-EncodedArguments 参数,支持更多的数据类型是可能的,如 this answer, but the range of types that can be represented with type fidelity is fundamentally limited by PowerShell's XML-based serialization infrastructure - see .
    • 所示