views:

1030

answers:

2

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

+1  A: 

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.

jitter
I'm on Windows 7 Ultimate, so I'm guessing 2.0
WebDevHobo
Well then read up on PsJob, Start/Stop/Wait/Get/Remove/Receive-Job
jitter
+4  A: 

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.

Keith Hill
And suppose I wanted to have this function in my Powershell Profile?
WebDevHobo
I updated the post for this. Note the addition of the -AsJob param.
Keith Hill
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.
WebDevHobo
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.
Keith Hill