none
Powershell: Add progress bar to my flatten-directory function RRS feed

  • Question

  • Hey guys,

    I've been trying figure out how to add a progress bar to my script all day with no success.  I wrote the following script so that I could pull all files from their subdirectories and consolidate them into a single folder. Now I just need to get some feedback in the terminal to know when the copy job is done.  Any suggestions?

    Here's my function:

    function Flatten-Directory {
    $source = "C:\source"
    $dest = "C:\destination"
    if ( -Not (Test-Path $dest))
    {
    New-Item $dest -type directory}
    Get-ChildItem $source -Recurse | `
        Where-Object { $_.PSIsContainer -eq $False } | `
        ForEach-Object {Copy-Item -Path $_.Fullname -Destination $dest -Force} 
    }


    Wednesday, May 13, 2015 10:13 PM

Answers

  • To prove my point about the pipeline just run this and watch it count up files.

    $files=Get-ChildItem c:\scripts -Recurse  -file 
    $k=$files.Count
    $j
    $files |
         ForEach-Object {
              #Copy-Item -Path $_.Fullname -Destination c:\temp3 -Force -Whatif
              sleep -mil 50
              $j++
              write-progress -id  1 -activity Updating -status 'Progress' -percentcomplete ($j/$k * 100) -currentOperation 'Copy Progress'
              
        } 
    
    Too many people have this idea that the pipeline does not step.  If so then why call it a stoppable pipeline.  no - the whole point of the pipeline is to pas each object down the pipe one at a time.


    \_(ツ)_/

    • Marked as answer by loranbruce Thursday, May 14, 2015 9:28 PM
    Thursday, May 14, 2015 1:34 AM

All replies

  • The "Get-ChildItem $source -Recurse " statement does it all in one go. Can not monitor the progress.

    This is a sample that will recursively step through a folder structure (can be customized to suit your needs). At each level the progress can be shown. The drawback is knowing at the beginning what the total is as the progress is shown / calculated as a percent. A benefit could be the current folder being processed can be shown in the progress. 

    function Recurse-Folders([string]$path) {
    
      Set-Location -Path $Path
      
      #  $L = Get-Location
      #  Do something at this location
        
      [String[]]$Folders  = Get-ChildItem "." -Directory
      ForEach ($F in $Folders)
      {
        Recurse-Folders($F)
        Set-Location -Path ".."
      }
    }

    Thursday, May 14, 2015 12:15 AM
  • Brian - it is a stepable pipeline.  It was made for a progressbar.  Just place the write progress in the pipeline.

    #init progress
    Write-Progress ...
    
    
    Get-ChildItem $source -Recurse  -file | `
         ForEach-Object {
              Copy-Item -Path $_.Fullname -Destination $dest -Force
              Write-Progress ....
        } 
    
    In the middle is where it goes.


    \_(ツ)_/

    Thursday, May 14, 2015 12:24 AM
  • Each part in the pipeline is processed before being passed to the next part in the pipeline.  Showing progress for each part of the pipe does not accurately reflect the progress as does showing the progress of each folder or level processed, though it could be easier to implement.

    1..3 | % {Write-output "Part 1$_"} | % {Write-output Part 2$_}
    
    Part 2Part 11
    Part 2Part 12
    Part 2Part 13

    Thursday, May 14, 2015 1:09 AM
  • That is not really how it works.\

    \_(ツ)_/

    Thursday, May 14, 2015 1:15 AM
  • if you feel the pipeline has been stalled then use a for loop.


    \_(ツ)_/

    Thursday, May 14, 2015 1:16 AM
  • To prove my point about the pipeline just run this and watch it count up files.

    $files=Get-ChildItem c:\scripts -Recurse  -file 
    $k=$files.Count
    $j
    $files |
         ForEach-Object {
              #Copy-Item -Path $_.Fullname -Destination c:\temp3 -Force -Whatif
              sleep -mil 50
              $j++
              write-progress -id  1 -activity Updating -status 'Progress' -percentcomplete ($j/$k * 100) -currentOperation 'Copy Progress'
              
        } 
    
    Too many people have this idea that the pipeline does not step.  If so then why call it a stoppable pipeline.  no - the whole point of the pipeline is to pas each object down the pipe one at a time.


    \_(ツ)_/

    • Marked as answer by loranbruce Thursday, May 14, 2015 9:28 PM
    Thursday, May 14, 2015 1:34 AM
  • This version displays the names of the files being copied.

    $files=Get-ChildItem c:\scripts -Recurse  -file 
    $k=$files.Count
    $j=0
    $files |
         ForEach-Object {
              #Copy-Item -Path $_.Fullname -Destination c:\temp3 -Force -Whatif
              sleep -mil 50
              $j++
              write-progress -id  1 -activity Updating -status $_.Name -percentcomplete ($j/$k * 100) -currentOperation 'Copy Progress'
              
        } 
    


    \_(ツ)_/

    Thursday, May 14, 2015 1:41 AM
  • if you feel the pipeline has been stalled then use a for loop.


    \_(ツ)_/

    The only way to use a for-loop in a tree structure is to use it recursively.

    Depending on the target environment, the first part "Get-ChildItem -recurse" could take a lot of time and use a lot of resources, during which feedback is not existent. When progress is shown with each folder processed, feedback is immediate and constant. The amount of resources used is only as large as the largest folder, rather than all of them.

    Thursday, May 14, 2015 1:44 AM
  • Not my point and your code does nothing to answer rhe question of using a progress bar.  The progress bar works just fine in a pipeline.  The issue with yours is the same.  You cannot get a count until you have walked the whole structure.

    With this kind of issue there is no solution.


    \_(ツ)_/

    Thursday, May 14, 2015 2:13 AM
  • Worked like a charm!  Thank you so much.  I had already discovered the write-progress command, but was having a hard time understanding it using the examples in get-help and on the web.  Seeing it used with ForEach-Object helped a lot.  Also, it makes way more sense after reading your comments about the pipeline.
    Thursday, May 14, 2015 9:31 PM
  • You are welcome.  As Brian notes it may not work as well on very large and complex folder structures but on smaller structures where the MS indexer is running the "Get-ChildItem" Cmdlet will run very fast and the copy will be much, much slower.  This can make the progress bar very useful for feedback.

    \_(ツ)_/

    Thursday, May 14, 2015 10:36 PM