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

时间:2017-07-07 23:59:25

标签: 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
}

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

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

$x= Start-Process powershell | Check-PC

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

1 个答案:

答案 0 :(得分:2)

注意:Start-Process的参与使解决方案显着复杂化 - 见下文。我从PowerShell直接调用了 f powershell ,你可以安全地传递一个脚本块,如下所示:

powershell (Get-Command Check-PC).ScriptBlock  # !! Does NOT work with Start-Process
带有辅助自删除临时文件的

Start-Process解决方案:

请参阅我this answer的下半部分来查看相关问题。

带有Start-Process和Base64编码的

-EncodedCommand解决方案:

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

新的powershell实例将无法看到您当前会话的定义(除非它们已在您的个人资料中定义),因此您必须通过功能的主体到它(要执行的源代码)。

(Get-Command -Type Function Check-PC).Definition 将您的函数定义的 body 作为字符串返回。

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

同样,如果函数体内的字符串作为整体或双引号字符串以({1}}的非空运行结束,那么\将被解释为 escape 字符,因此\必须加倍谢谢,PetSerAl

绕过这些引用(转义)令人头疼的最强大的方法是将Base64编码的字符串与\参数结合使用

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

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

如果您想要传递完整功能,那么可以通过名称调用以传递参数 < / strong>,需要做更多的工作。

[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"))) 解决方案,使用基于正则表达式的源代码转义传递:

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

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

      在正则表达式的上下文中需要
    • "来逃避单个文字\\
    • \是一个积极的前瞻断言,仅当(?=\\*("|$))后跟\或字符串末尾(")时才匹配$中间的其他\个实例(\\*)。请注意,由于断言不会对匹配产生影响,因此\字符(如果存在多个字符)仍然是逐个匹配的。
  • \$&将每个匹配的字符替换为\后跟字符本身($&) - 请参阅我的this answer以了解您可以使用的结构-replace表达式的替换字符串。

  • 需要将结果包含在"..."'"' + ... + '"')中以防止空格正常化;没有它,任何超过一个空格char的运行。和/或tab char。将被标准化为单个空格,因为整个字符串不会被识别为单个参数。

    • 请注意,如果您直接调用powershell ,PowerShell通常会自动将字符串括在"..."幕后,因为它对于在调用外部实用程序(本机命令行应用程序)时包含空格的参数执行此操作,这是powershell.exe的原因 - 与Start-Process cmdlet <不同/ em>的
    • PetSerAl指出自动双引号机制并不那么简单(但字符串的具体内容与是否应用自动双引号有关),以及v5中特定行为的变化,以及再次(稍微)在v6。