使用Powershell Start-Process启动Powershell会话并传递本地变量

7
有没有一种方法可以使用Powershell Start-Process命令启动一个新的Powershell会话,并传递一个带有本地变量(其中一个是数组)的脚本块?
例如:
$Array = @(1,2,3,4)

$String = "This is string number"

$Scriptblock = {$Array | ForEach-Object {Write-Host $String $_}}

Start-Process Powershell -ArgumentList "$Scriptblock"

谢谢。


1
您可以使用&运算符调用表达式,如您示例中的& $Scriptblock - oɔɯǝɹ
我想要启动一个新的PowerShell会话,并在该会话中运行一个脚本块。该脚本块将需要包含来自初始会话的本地变量。 - atownson
@atownson 为什么需要新的会话?你是想防止不必要的输出吗?还是想将输出发送到其他地方? - oɔɯǝɹ
好的,我下面提出了一个可以工作的建议,但这有点笨拙,所以除非你真的决心要使用Start-Process将变量传递到新会话中,否则最好采纳这里的建议,重新审视你试图完成的任务,并考虑是否有更优雅的方法来实现它。 - Adi Inbar
5个回答

3

我很确定没有直接的方法可以将变量从一个PowerShell会话传递到另一个会话。你能做的最好办法是一些解决方法,例如在你通过-ArgumentList传递的代码中声明变量,并在调用会话中插值这些值。如何将变量插入到-ArgumentList中的声明中取决于变量的类型。对于数组和字符串,你可以像这样操作:

$command = '<contents of your scriptblock without the curly braces>'

Start-Process powershell -ArgumentList ("`$Array = echo $Array; `$String = '$String';" + $command)

2
PowerShell.exe的命令行选项”表明,使用脚本块时应该能够通过添加“-args:”来传递参数。
PowerShell.exe -Command { - | <script-block> [-args <arg-array>] | <string> [<CommandParameters>] }

然而,当我尝试这样做时,出现了以下错误:

-args:该术语“-args”不被识别为命令、函数、脚本文件或可操作程序的名称。请检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。

我在脚本块中添加了$MyInvocation | fl以查看发生了什么,看起来-args只是附加到脚本块中反序列化的命令(因此出现错误,因为-args不是有效的命令)。我还尝试使用GetNewClosure()和$Using:VariableName,但这些似乎只在调用脚本块时起作用(与我们在此处使用它进行序列化/反序列化命令的方式不同)。
然后,我通过像deadlydog's answer那样将其包装在一个函数中才能使其正常工作。
$var = "this is a test"

$scriptblock = {
    $MyInvocation | fl #Show deserialized commands
    function AdminTasks($message){
        write-host "hello world: $message"
    }
}

Start-Process powershell -ArgumentList '-noexit','-nologo','-noprofile','-NonInteractive','-Command',$scriptblock,"AdminTasks('$var')" -Verb runAs #-WindowStyle Hidden

#Output:
MyCommand             :
                         $MyInvocation | fl #Show deserialized commands
                         function AdminTasks($message){
                         write-host hello world: $message
                         }
                         AdminTasks('this is a test')
BoundParameters       : {}
UnboundArguments      : {}
ScriptLineNumber      : 0
OffsetInLine          : 0
HistoryId             : 1
ScriptName            :
Line                  :
PositionMessage       :
PSScriptRoot          :
PSCommandPath         :
InvocationName        :
PipelineLength        : 2
PipelinePosition      : 1
ExpectingInput        : False
CommandOrigin         : Runspace
DisplayScriptPosition :


hello world: this is a test

将其用脚本块包装并使用$args [0]$args [1]也可以,但请注意,如果在反序列化时出现问题,则可能需要将$var0或$var1用引号括起来,并使用`$来防止$sb被替换为"",因为该变量不存在于调用者的范围内:

$var0 = "hello"
$var1 = "world"

$scriptblock = {
    $MyInvocation | fl #Show deserialized commands
    $sb = {
        write-host $args[0] $args[1]
    }
}

Start-Process powershell -ArgumentList '-noexit','-nologo','-noprofile','-NonInteractive','-Command',$scriptblock,"& `$sb $var0 $var1"

你可能已经明白了,但是-args并不是字面上的参数。它旨在通过使用@符号从哈希表中接收一组参数,通过扩展来设计。 - Steve can help

2
你可以将脚本块的内容封装在一个函数中,然后从参数列表调用该函数,并将变量作为参数传递给函数,就像我在这篇文章中所做的那样。
$ScriptBlock = {
    function Test([string]$someParameter)
    {
        # Use $someParameter to do something...
    }
}

# Run the script block and pass in parameters.
$myString = "Hello"
Start-Process -FilePath PowerShell -ArgumentList "-Command & {$ScriptBlock Test('$myString')}"

2
我能通过将数组与斜杠"/"连接起来创建一个字符串,并将脚本块输入到另一个带有适当参数的.ps1脚本中,并在第二个脚本中将连接的字符串拆分回数组,然后使用该方法来使其工作。
Start-Process Powershell -ArgumentList "&C:\script.ps1 $JoinedArray $String"

虽然不美观,但这是我唯一能让它工作的方式。感谢所有的回复。


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接