I can't get PowerShell start-job -scriptblock or sajb to work -- nothing happens

GraniteStateColin 211 Reputation points
2023-06-29T21:52:09.21+00:00

I have a command that works fine an old Command Prompt for loop that I'm trying to port to PowerShell. I can get all of it working fine, except when I try to get it to run all the cycles of the loop in parallel processes using start-job -scriptblock or sajb. No errors, just doesn't do anything.

I have tried examples I find online, and even the simplest don't work for me:User's image

An even simpler "Hello world" without a for loop doesn't do anything for me either (no other window opened either):

User's image

Should these work from the PS prompt, or do these only work by running a .PS script file?

Any idea what I may be doing wrong?

Here's a shortened version of the for loop from the command prompt that works perfectly for me, other than not being in PowerShell:

for %x in ("*.mp3") do (start "Convert %x" cmd /c "ffmpeg -i "%x" -f flac "int_%x.flac" & sox "int_%x.flac" -c 2 -C 192 -r 44100 "Ready\fixed-%x"")

Windows for business | Windows Server | User experience | PowerShell
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Rich Matheisen 48,026 Reputation points
    2023-06-30T02:34:11.7966667+00:00

    Once a job starts you have no control over the order in which the results will be returned. Also, if you're going to parameterize values in the scriptblock you have to pass the parameter value using the -ArgumentList parameter, or (more conveniently) the "$Using:" notation.

    Here's a simple example:

    'Colin', 'Joe' |
        ForEach-Object {
            $name = $_
            Start-Job -ScriptBlock { "Hello, $Using:name" } | Out-Null
        }
    While ($jobs = Get-Job) {
        foreach ($job in $jobs) {
            if ($job.State -eq 'Completed') {
                Receive-Job -Id $job.Id
                Remove-Job -Id $job.Id
            }
        }
    }
    
    0 comments No comments

  2. GraniteStateColin 211 Reputation points
    2023-06-30T02:37:32.11+00:00

    I now understand. This was because the Start-Job in version 5 of PowerShell (the one included with Windows 11) doesn't handle this very well (necessary to use $using: to pass parameters to the nested calls, as @Rich Matheisen also explained).

    For me, the best long-term solution was to just upgrade to PowerShell 7, which only takes a few seconds (via the Microsoft Store or PS command: winget install --id Microsoft.Powershell --source winget. After installing, you need to launch a new PowerShell window, then select to open a "PowerShell" tab, NOT a "Windows PowerShell" tab, which will still provide the old version 5 experience.

    From version 7, you can simply add the -parallel option to ForEach-Object, like in this, my final solution. With this, it works exactly the same, whether running in series or in parallel, exactly as you'd expect it should work and as it works with the old CMD for loops:

    md "Ready"; Get-ChildItem -Filter "*.mp3" | ForEach-Object -parallel { ffmpeg -i $_.name -f flac -af dynaudnorm -id3v2_version 3 ($_.name+".flac"); sox --norm=-3.25 ($_.fullname + ".flac") -c 2 -C 192 -r 44100 (".\Ready\Ready-" + $_.name) } | wjb; rm *.flac


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.