Make a Powershell function/task run in the background

13,530

Solution 1

In the new scope you create for the background job, your parameters defined for you WriteAllPaths function are not defined. Try this and you'll see they aren't:

Function writeAllPaths([string]$fromFolder,[string]$filter,[string]$printfile) 
{    
    Start-Job { "$fromFolder, $filter, $printFile" }
}

$job = WriteAllPaths .\Downloads *.zip zips.txt
Wait-Job $job
Receive-Job $job

, ,

Try this instead:

Function writeAllPaths([string]$fromFolder, [string]$filter, [string]$printfile) 
{    
    Start-Job {param($fromFolder,$filter,$printfile) 
               "$fromFolder, $filter, $printfile" } `
               -ArgumentList $fromFolder,$filter,$printfile
}

$job = WriteAllPaths .\Downloads *.zip z.txt
Wait-Job $job
Receive-Job $job

.\Downloads, *.zip, z.txt

Now you see your output because we passed the parameters through to the scriptblock via -ArgumentList. What I would recommend is a function that can optionally use a background job. Just stick this function definition in your profile and you're set:

function WriteAllPaths([string]$FromFolder, [string]$Filter, 
                       [string]$Printfile, [switch]$AsJob) 
{
    if (![IO.Path]::IsPathRooted($FromFolder)) {
        $FromFolder = Join-Path $Pwd $FromFolder
    }
    if (![IO.Path]::IsPathRooted($PrintFile)) {
        $PrintFile = Join-Path $Pwd $PrintFile
    }

    $sb = {
        param($FromFolder, $Filter, $Printfile)
        Get-ChildItem $FromFolder -r $filter | Select FullName > $PrintFile
    }

    if ($AsJob) {
        Start-Job $sb -ArgumentList $FromFolder,$Filter,$PrintFile
    }
    else {
        & $sb $FromFolder $Filter $PrintFile        
    }
}

Test the function (synchronously) like so:

$job = WriteAllPaths Downloads *.zip z.txt -AsJob
Wait-Job $job
Receive-Job $job

Note that I'm testing if the path is root and if not I'm prepending the current dir. I do this because the background job's starting dir is not always the same as where you executed Start-Job from.

Solution 2

Which version of powershell? In Powershell 2.0 I think you can use background jobs for this Start-Job.

Starts a Windows PowerShell background job.

Share:
13,530
KdgDev
Author by

KdgDev

Updated on June 04, 2022

Comments

  • KdgDev
    KdgDev almost 2 years

    I have a function that lets me write the file-path of files to a text file, depending on your input. That sounds confusing, but I don't know of a better way to put it, so here's the function:

    Function writeAllPaths([string]$fromFolder,[string]$filter,[string]$printfile) {
        Get-ChildItem -Path $fromFolder -Recurse $filter | Select-Object -Property FullName > $printfile
    }
    

    First argument being the folder you start your search from.
    Second argument, the filter. *.zip for instance, will list all zip files. Third argument, you have to provide where the text file will end up.

    Sample usage: writeAllPaths c:\ *.zip c:\allZips.txt

    The thing is, when I do this, Powershell won't accept commands until it's done. Which isn't very productive. Is there a way to have this run in the background when started. And preferably, give a little message when it's done. I could be opening any file that's being created in the middle of the process...

    Also, I'm on Windows 7, so I'm guessing that I have Powershell 2.0

    Yeah, I'm not sure about it :p

    EDIT:

    I used Start-Job, as suggested, as follows:

    Function writeAllPaths([string]$fromFolder,[string]$filter,[string]$printfile) {
      Start-Job -ScriptBlock {Get-ChildItem -Path $fromFolder -Recurse $filter | Select-Object -Property FullName > $printfile}
    }
    

    However, the file isn't created. The old function does create a file.

    EDIT2: it would be preferable to have this function in my Powershell profile. This way, I can execute it whenever I want, instead of having to load in the specific ps1 file every time I boot Powershell.

    More info on the Powershell profile can be found here You can summon your own profile by typing: notepad $profile

  • KdgDev
    KdgDev over 14 years
    I'm on Windows 7 Ultimate, so I'm guessing 2.0
  • cal meacham
    cal meacham over 14 years
    Well then read up on PsJob, Start/Stop/Wait/Get/Remove/Receive-Job
  • KdgDev
    KdgDev over 14 years
    And suppose I wanted to have this function in my Powershell Profile?
  • Keith Hill
    Keith Hill over 14 years
    I updated the post for this. Note the addition of the -AsJob param.
  • KdgDev
    KdgDev over 14 years
    I should "Just stick this function definition in your profile and you're set". But what about the 3rd last-line. There is a reference to WriteAllPaths.ps1, which does not exist. Also, if I just paste this code into my profile, what will the effect of those last 3 lines be. They're not included in a function but exist directly in the profile. So everytime Powershell starts, it will try to execute them.
  • Keith Hill
    Keith Hill over 14 years
    Just paste the function. Those three lines just show how to execute in a synchronous manner. You wouldn't normally execute Wait-Job since you would want to do other work - rather than wait for the job to finish.