3

I have a function that I should be able to call from any place in my powershell script.

The problem is that it doesn't identify the function in a script block.

In the following example I have the function getNumberFive which should return the number 5.
I want to be able to use this function inside a scriptblock when I start a new job and also in the end of the script.

Expected result:
Write the number 15 to the file "C:\tmp\result.txt"
Write to the console: "I like the number 5"

In reality:
Write the number 10 to the file "C:\tmp\result.txt"
Write to the console: "I like the number 5"

I can workaround this issue by defining the same function inside the scriptblock but then I will duplicate the function and this is not a good programming.

Another way is to define:

$func = {
    function getNumberFive(){
        return 5
    }
}
$scriptBlock = {

    Function printSum(){
        $number = getNumberFive
        $newNumber = 10 + $number  # => $newNumber should be 15
        $newNumber >> "C:\tmp\result.txt"
      }
}
Start-Job -ScriptBlock $scriptBlock -InitializationScript $func

But in this case I won't be able to call $five = getNumberFive.

I read number of methods but I didn't understand how exactly to use them:
CALLING A POWERSHELL FUNCTION IN A START-JOB SCRIPT BLOCK WHEN IT’S DEFINED IN THE SAME SCRIPT

How to pass a named function as a parameter (scriptblock)

https://social.technet.microsoft.com/Forums/ie/en-US/485df2df-1577-4770-9db9-a9c5627dd04a/how-to-pass-a-function-to-a-scriptblock?forum=winserverpowershell

PowerShell: Pass function as a parameter

Using Invoke-Command -ScriptBlock on a function with arguments

My script:

function getNumberFive(){
    return 5
}

$scriptBlock = {

    Function printSum(){
        # $number = getNumberFive => DOESN'T WORK
        # $number = Invoke-Expression ($(get-command getNumberFive) | Select -ExpandProperty Definition) => DOESN'T WORK AS EXPECTED
        # $number = &(${function:getNumberFive}) => DOESN'T WORK AS EXPECTED
        # $number = &(Get-Item function:getNumberFive) => DOESN'T WORK AS EXPECTED
        $newNumber = 10 + $number  # => $newNumber should be 15
        $newNumber >> "C:\tmp\result.txt"
    }

    printSum
}

Start-Job -ScriptBlock $scriptBlock 

$five = getNumberFive
Write-Host "I like the number"$five

Get-Job | Wait-Job
Get-Job | Stop-Job
Get-Job | Remove-Job
2
  • Try -InitializationScript $function:getNumberFive Commented Sep 18, 2017 at 13:46
  • @TheIncorrigible1 it doesn't work. I also tried it, see in my question by declaring the getNumberFive in separate script block but then the I like the number 5 doesn't work. Commented Sep 18, 2017 at 13:57

2 Answers 2

4

When you pass a scriptblock to start-job (or invoke-expression) the PowerShell instance that executes that scriptblock only has access to that scriptblock, anything that script block loads, and anything that already exists in the PowerShell instance.

Other parts of your script are not included. (For functions locally defined in your script to be available from other, possibly remote, instances of PowerShell the whole script – not just the scriptblock – and any dependencies would need to be accessible from the other instance.)

You could refactor the code you want in both places into a module which the script block loads as well as the job creating script.

When using jobs you are executing code in another process: like any remote operation the remote executing is a separate environment.

Sign up to request clarification or add additional context in comments.

Comments

1

You can do like this:

function getNumberFive(){
    return 5
}

$a={
Function printSum($number){
        $newNumber = 10 + $number  # => $newNumber should be 15
        $newNumber >> "D:\result.txt"
    }
}

$scriptBlock = {
param($number)
    printSum -number $number
}
$five = getNumberFive
Write-Host "I like the number"$five

Start-Job -InitializationScript $a -ScriptBlock $scriptBlock -ArgumentList $five

There is a switch name -InitializationScript in Start-job where you can keep your initialization code like a function. Wrap it in a scriptblock and simply call it from the main scriptblock.

Hope it helps.

8 Comments

I want something like this but then the row $five = getNumberFive won't work for me.
@E235: as per your comment. I have edited the answer. You have to compile that function also.
I ran it and it still doesn't work. It prints to the console I like the number 5 but it doesn't write to the file the sum 15. You also forgot to uncomment $number = getNumberFive in $initialization_block. I checked after I uncommented it.
This code is a very simple code I created in order to make thing simple enough for people to understsand me. The real code is more complexed. In the real code, I really need to use start-job. I mentioned in the question that the expected result is to write 15 to a file and "I like the number 5" to a console. It doesn't happen with your suggestion.
This works but I need to find a way to call the function from anywhere in the code. You are using the getNumberFive result because you know it is constant. In other situations it can be a function that checking something specific inside the script block. I don't have good example now because I wanted to make things simple. I will find and show you cases that it won't work.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.