# How to run the whole script (.PS1) which has multiple functions in it as a single job and view the output

1 vote
5.7k views
5.7k views

I have a script which include two functions and I did put this two functions into a single function so that it would work parallelly when I'm running it. Now I want to run the whole script as one job so that I can run the script on multiple folders and see the output without confusion.

[CmdletBinding()]
param (
[Parameter(Mandatory = $true)] [String]$currentPath
)
Function tfinit { Do something }
function changes { Do something}
function runjobs {
Param ($path) set-location$path
#remove blank workspace and space from the list
$workspace = terraform workspace list$workspaces = @()
$workspace | ForEach-Object {$a = $_ -replace "\*", ""$a = $a -replace ' ', ''$workspaces += $a } ### Do init tfinit -path$path
##### Do plan job
foreach ($workspace in$workspaces) {
if ($workspace -ne "") { changes -workspace$workspace -path $path } } ### Get folder inside the folder to run$list = Get-ChildItem -Directory
foreach ($folder in$list) {
set-location $folder.fullname runjobs -path "$folder.fullname"
}
}
runjobs -path $currentPath  I do want the function runJob to run as a Start-Job. Start-Job -ScriptBlock { runJobs -path$args[0]
} -InitializationScript $allJobs -ArgumentList "$currentPath" | Wait-Job | Receive-Job


When I tried to execute this it's running on a totally different folder. I want the Start-Job for the runJob function to work on the path that I'm giving to $currentPath. edited edit history It's not quite clear to me what you mean by "run as one job." Do you want to run the script as a background job (via Start-Job)? Can you give an example of the output you expect compared to the output you currently get? Also, the recursive runjobs call in your script won't work the way you expect. PowerShell only does simple variable expansion in strings, so "$folder.fullname" does the same as $folder + ".fullname" (expand the variable$folder and append the string ".fullname").

Yes I do want the function runJob to run as a start-job.

'Start-Job -ScriptBlock { runJobs -path $args[0] } -InitializationScript$allJobs  -ArgumentList "$currentPath" | Wait-Job | Receive-Job' when i tried to execute this its running on a totally different folder. I want the start-job for the runJob function to work on the path that I'm giving to the currentPath. ## Please log in or register to answer this question. ## 2 Answers 0 votes To invoke a function in a scriptblock run as a job you need to define the function (all functions invoked in the scriptblock) inside the context of the job. Otherwise you'll get an error like this: ObjectNotFound: The term 'runjobs' is not recognized as a name of a cmdlet, function, script file, or executable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. To include the function definitions in the code run by the job you can either put them inside the invoked scriptblock or pass them as a separate scriptblock (parameter -InitializationScript). The latter runs the given initialization code once before the actual job starts, similar to how a BEGIN {} block in a function works. So, if you want to invoke Start-Job from within the script the code in your script would have to look somewhat like this: [CmdletBinding()] Param( [Parameter(Mandatory =$true)]
[String]$currentPath ) Start-Job -ScriptBlock { function tfinit { #... } function changes { #... } function runjobs { Param($path)
#...
}

runJobs -path $args[0] } -ArgumentList "$currentPath" | Wait-Job | Receive-Job


or like this:

[CmdletBinding()]
Param(
[Parameter(Mandatory = $true)] [String]$currentPath
)

$jobFunctions = { function tfinit { #... } function changes { #... } function runjobs { Param($path)
#...
}
}

Start-Job -InitializationScript $jobFunctions -ScriptBlock { runJobs -path$args[0]
} -ArgumentList "$currentPath" | Wait-Job | Receive-Job  However, Start-Job is not limited to running scriptblocks. It can also invoke scripts, so you could leave your script as it is, and run it as a job like this: Start-Job -FilePath C:\path\to\your.ps1 -ArgumentList "some_path" | Wait-Job | Receive-Job  For example in a runner script like this (e.g. run_job.ps1): [CmdletBinding()] Param( [Parameter(Mandatory =$true)]
[String]$Script, [Parameter(Mandatory =$true)]
[String]$Path, [Parameter(Mandatory =$false)]
[ScriptBlock]$InitializationScript = {} ) Start-Job -FilePath$Script -InitializationScript $InitializationScript -ArgumentList$Path |
Wait-Job |


that you invoke with your script and the working directory:

.\run_job.ps1 -Script 'C:\path\to\foo.ps1' -Path 'D:\your\path'


As for "its running on a totally different folder," you're invoking Set-Location $path at the beginning of runjobs(), so the working directory should be fine unless you're passing a relative path (foo\bar) rather than an absolute path (D:\foo\bar). If it isn't: please provide evidence (edit your question to do so). edited by (100) 1 6 20 edit history 0 votes  [CmdletBinding()] Param( [Parameter(Mandatory =$true)]
[String]$currentPath )$allJobs = {
function tfinit {
#...
}
function changes {
#...
}
function runjobs {
Param($path) #... } } } Start-Job -Initializationscript$allJobs  -ScriptBlock { runJobs -path $args[0] } -ArgumentList "$currentPath"

by (5)
1 2
edit history

Is there a particular reason why you post and accept an answer of your own that basically copies my first suggestion (while adding a spurious trailing brace no less)? Whether the functions are defined via -InitializationScript or directly in the scriptblock makes no difference here.

I just wanted people to find the answer to this particular question easily and as you can see I altered the same code that i used for asking the question at the first place.  So i could say i basically copied my own code not yours. which is

'Start-Job -ScriptBlock {
runJobs -path $args[0] } -InitializationScript$allJobs  -ArgumentList "\$currentPath" | Wait-Job | Receive-Job'

The answer to your question is "make function definitions part of the code run by the job." Whether that's done in the invoked scriptblock or in an additional initialization scriptblock is an irrelevant implementation detail. A code-only answer without explanation but with an obvious syntax error will hardly be useful to anyone.