在新窗口中运行 PowerShell 自定义函数

Nat*_*ate 2 powershell

Function Check-PC
{
$PC = Read-Host "PC Name"
If($PC -eq "exit"){EXIT}
Else{
Write-Host "Pinging $PC to confirm status..."
PING -n 1 $PC
}
Run Code Online (Sandbox Code Playgroud)

这是我写到 PowerShell 脚本中的一个函数片段。我希望该函数在 PowerShell 的新实例中运行,而不是在主窗口中运行。

是否可以在 PowerShell 的单独进程中运行它而不将其编写为单独的脚本并调用脚本?像这样的东西:

$x= Start-Process powershell | Check-PC
Run Code Online (Sandbox Code Playgroud)

如果可能,我需要将所有内容都保存在一个脚本中。

mkl*_*nt0 7

注意:正是参与Start-Process使解决方案显着复杂化 - 见下文。我˚Fpowershell被调用直接从PowerShell中,你可以放心地通过一个脚本块,如下所示:

powershell ${function:Check-PC}  # !! Does NOT work with Start-Process
Run Code Online (Sandbox Code Playgroud)

${function:Check-PC}变量命名空间符号的实例:它以脚本块(实例)的形式返回函数;它是更简洁、更快速的.[scriptblock]
Get-Content Function:Check-PC

如果您需要将(仅位置)参数传递给脚本块,则必须附加-Args,然后将参数作为数组,-separated )。


Start-Process 带有辅助自删除临时文件的解决方案:

请参阅相关问题的答案的下半部分。


Start-Process使用-EncodedCommandBase64 编码的解决方案:

Start-Process powershell -args '-noprofile', '-noexit', '-EncodedCommand', `
  ([Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes(
    (Get-Command -Type Function Check-PC).Definition)))
Run Code Online (Sandbox Code Playgroud)

powershell实例不会看到您当前会话的定义(除非它们在您的配置文件中定义),因此您必须将函数体传递给它(要执行的源代码)。

(Get-Command -Type Function Check-PC).Definition将函数定义的主体作为string 返回

但是,该字符串需要转义,以便在未修改的情况下传递给新的 Powershell 进程。
"嵌入在字符串中的实例将被剥离,除非它们被表示为\"或三倍 ( """)。
(在这种情况下,\"通常`"需要转义双引号,因为 PowerShell\"在将命令传递给powershell.exe可执行文件时需要。)

类似地,如果整个字符串或函数体内的双引号字符串以 (a non-empty run of) 结尾\\则将被解释为转义字符,因此\必须加倍谢谢,PetSerAl

绕过这些引用(转义)问题-EncodedCommand的最可靠方法是将 Base64 编码的字符串与参数结合使用

  • [Convert]::ToBase64String()[byte[]]数组创建一个 Base64 编码的字符串。

  • [Text.Encoding]::Unicode.GetBytes()将(内部 UTF-16 - " Unicode")字符串转换为[byte[]]数组。


如果您想传递完整的函数,因此可以通过名称调用它以传递参数,则需要做更多的工作。

# Simply wrapping the body in `function <name> { ... }` is enough.
$func = (Get-Command -Type Function Check-PC)
$wholeFuncDef = 'Function ' + $func.Name + " {`n" + $func.Definition + "`n}"

Start-Process powershell -args '-noprofile', '-noexit', '-EncodedCommand', `
  ([Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes("$wholeFuncDef; Check-PC")))
Run Code Online (Sandbox Code Playgroud)

Start-Process 使用基于正则表达式的源代码转义的解决方案:

PetSerAl建议使用以下替代方案,它使用正则表达式来执行转义。解决方案更简洁,但有点令人费解:

Start-Process powershell -args '-noprofile', '-noexit', '-Command', `
  ('"' + 
   ((Get-Command -Type Function Check-PC).Definition -replace '"|\\(?=\\*("|$))', '\$&') +
   '"')
Run Code Online (Sandbox Code Playgroud)
  • "|\\(?=\\*("|$))匹配每个"实例和每个非空\字符运行。- 逐个字符 - 直接在"字符之前。或字符串的最末端。

    • \\需要在正则表达式的上下文中转义单个文字\.
    • (?=\\*("|$))是一个肯定的前瞻断言,它\仅在后跟"字符串 ( $)或结尾时匹配,或者直接匹配,或者\在 ( \\*)之间有更多实例。请注意,由于断言对匹配没有贡献\,因此如果有多个字符,仍然会一一匹配。
  • \$&用 a\后跟字符本身 ( $&)替换每个匹配的字符- 请参阅此答案以了解您可以在-replace表达式的替换字符串中使用的构造。

  • 需要将结果括在"..."( '"' + ... + '"') 中以防止空格规范化;没有它,任何超过一个空格字符的运行。和/或制表符。将被规范化为单个空格,因为整个字符串不会被识别为单个参数。

    • 请注意,如果您要powershell 直接调用,PowerShell 通常会在幕后自动将字符串括起来"...",因为它会在调用外部实用程序(本机命令行应用程序)时对包含空格的参数这样做,这powershell.exe与 - 不同该Start-Process cmdlet的
    • PetSerAl 指出,自动双引号机制并不是那么简单(字符串的具体内容与是否应用自动双引号有关),并且具体行为在 v5 中发生了变化,再次(稍微) 在 v6 中。


归档时间:

查看次数:

2686 次

最近记录:

4 年,2 月 前