PowerShell ScriptBlock and multiple functions
Solution 1
I know this is an old thread, but I hope it helps someone.
[CmdletBinding()]
param()
$barScriptBlock = {
function GetBar() {
$bar = "bar"
$bar
}
}
$fooScriptBlock = {
function GetFoo() {
$foo = "foo"
$bar = GetBar
$foo
$bar
}
}
# Concatenate all functions into a script block; add a parameter for extra credit.
$scriptBlockString = @"
param(`$hello)
$($barScriptBlock.ToString())
$($fooScriptBlock.ToString())
`$hello
GetFoo
"@
Write-Verbose $scriptBlockString
# Convert combined string to script block.
$finalScriptBlock = [ScriptBlock]::Create($scriptBlockString)
# Run synchronously, passing runtime parameter.
$result = & $finalScriptBlock "Hola"
# (Async results would not be reiably accessed here yet.)
Write-Host $result[0]
Write-Host $result[1]
Write-Host $result[2]
Solution 2
The problem is that Invoke-Command
can only see what's inside ScriptBlock
, it can't see functions definded outside. If you really want to - you can run everything in one line, like this:
$result = Invoke-Command -ComputerName localhost -ScriptBlock { function GetBar() { $bar = "bar"; $bar }; function GetFoo() { $foo = "foo"; $bar = GetBar; $foo; $bar }; GetFoo }
But I personally would advise you to save functions in script and call Invoke-Command
with -FilePath
parameter, like this:
$result = Invoke-Command -ComputerName localhost -FilePath "\1.ps1"
Solution 3
I recently got this working:
function GetBar() {
$bar = "bar"
$bar
}
function GetFoo() {
$foo = "foo"
$bar = GetBar
$foo
$bar
}
$NewScriptBlock = [scriptblock]::Create("function GetBar() { ${function:GetBar} } function GetFoo() { ${function:GetFoo} } GetFoo")
Invoke-Command -ComputerName localhost -ScriptBlock $NewScriptBlock
Alternatively you can spare a line using:
Invoke-Command -ComputerName localhost -ScriptBlock ([scriptblock]::Create("function GetBar() { ${function:GetBar} } function GetFoo() { ${function:GetFoo} } GetFoo"))
The trick is that the Create method of the ScriptBlock class adds the code inside the functions, but not the header and final bracket. You need to add that yourself, plus the final invoke.
Knows Not Much
Updated on June 04, 2022Comments
-
Knows Not Much almost 2 years
I have written the following code:
cls function GetFoo() { function GetBar() { $bar = "bar" $bar } $foo = "foo" $bar = GetBar $foo $bar } $cred = Get-Credential "firmwide\srabhi_adm" $result = Invoke-Command -Credential $cred -ComputerName localhost -ScriptBlock ${function:GetFoo} Write-Host $result[0] Write-Host $result[1]
It works but I don't want to define
GetBar
inside ofGetFoo
.Can I do something like this?
cls function GetBar() { $bar = "bar" $bar } function GetFoo() { $foo = "foo" $bar = GetBar $foo $bar } $cred = Get-Credential "firmwide\srabhi_adm" $result = Invoke-Command -Credential $cred -ComputerName localhost -ScriptBlock ${function:GetFoo; function:GetBar; call GetFoo} Write-Host $result[0] Write-Host $result[1]
Basically I am selectively putting the functions which I want in the ScriptBlock and then calling one of them. This way I don't have to define function inside of function and I can construct the ScriptBlock by injecting the functions which I want to be a part of that ScriptBlock.