Powershell Start-Process to start Powershell session and pass local variables
Asked Answered
F

5

7

Is there a way to use the Powershell Start-Process cmdlet to start a new Powershell session and pass a scriptblock with local variables (once of which will be an array)?

Example:

$Array = @(1,2,3,4)

$String = "This is string number"

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

Start-Process Powershell -ArgumentList "$Scriptblock"

Thanks.

Fonzie answered 21/7, 2013 at 20:9 Comment(4)
You can invoke an expression using the & operator. Like & $Scriptblock in your example.Seto
I would like to start a new powershell session and run a scriptblock in that session. The scriptblock will need to contain local variables from the initial session.Fonzie
@Fonzie why the need for the new session? are you trying to prevent unwanted output? Or do you want to send the output somewhere else?Seto
Well, I made a suggestion below that will work, but it's kind of a kludge, so unless you're really determined to pass variables to a new session with Start-Process, it wouldn't be a bad idea to take the advice here and re-examine what you're trying to accomplish with this and whether there's a more elegant way to do it.Abbotson
F
2

I was able to get this to work by joining the array with "/" to create a string and entering the scriptblock into another .ps1 script with appropriate parameters and splitting the joined string back to an array within the second script and using

Start-Process Powershell -ArgumentList "&C:\script.ps1 $JoinedArray $String"

Ugly, but it's the only way I could get it to work. Thanks for all the replies.

Fonzie answered 22/7, 2013 at 2:25 Comment(0)
A
3

I'm pretty sure there's no direct way to pass variables from one PowerShell session to another. The best you can do is some workaround, like declaring the variables in the code you pass in -ArgumentList, interpolating the values in the calling session. How you interpolate the variables into the declarations in -ArgumentList depends on what types of variables. For an array and a string you could do something like this:

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

Start-Process powershell -ArgumentList ("`$Array = echo $Array; `$String = '$String';" + $command)
Abbotson answered 21/7, 2013 at 21:38 Comment(0)
F
2

I was able to get this to work by joining the array with "/" to create a string and entering the scriptblock into another .ps1 script with appropriate parameters and splitting the joined string back to an array within the second script and using

Start-Process Powershell -ArgumentList "&C:\script.ps1 $JoinedArray $String"

Ugly, but it's the only way I could get it to work. Thanks for all the replies.

Fonzie answered 22/7, 2013 at 2:25 Comment(0)
V
2

You could wrap the contents of your script block in a function, and then call the function from the ArgumentList and pass in the variables as parameters to the function, as I do on this post.

$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')}"
Viyella answered 19/3, 2014 at 22:54 Comment(0)
X
2

The command line options for PowerShell.exe say that you should be able to pass arguments when using a script block by adding -args:

PowerShell.exe -Command { - | <script-block> [-args <arg-array>] | <string> [<CommandParameters>] }

However when I try to do that I get the following error:

-args : The term '-args' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

I added $MyInvocation | fl to the script block to see what was happening, and it looks like the -args is just appended to the deserialized commands in the script block (hence the error since -args is not a valid command). I also tried using GetNewClosure() and $Using:VariableName but those only appear to work when the script block is invoked (as opposed to this where we are using it to serialize/deserialize the commands).

The I was able to get it to work by wrapping it in a function like 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

Wrapping it in a script block and using $args[0] or $args[1] also works, just be aware that you many need to wrap the $var0 or $var1 in quotes if there are issues when it is deserialized and use `$ to prevent the $sb from being replaced with "" since that variable doesn't exist in the caller's scope:

$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"
Xavierxaviera answered 7/1, 2016 at 19:7 Comment(1)
you've probably figured this out by now, but -args isn't literally a parameter. It's designed to receive a set of parameters from a hashtable via splatting using the @ symbol.Carbo
H
0

If you want to pass objects that are serializable, but are not strings, I wrote up a solution: Is there a way to pass serializable objects to a PowerShell script with start-process?

Headstream answered 7/12, 2015 at 1:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.