Make a Powershell function/task run in the backgro

2019-07-20 06:59发布

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

2条回答
淡お忘
2楼-- · 2019-07-20 07:28

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.

查看更多
男人必须洒脱
3楼-- · 2019-07-20 07:36

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.

查看更多
登录 后发表回答