winformspowershellloggingrobocopy

write robocopy output to console and log file


I have an interactive PowerShell using windows forms, meaning a PowerShell script displays some controls on a form asking for input and finally runs robocopy, when the user clicks the button.

This is a simple script displaying the problem. You can copy the code, save it to a Power Sell script and run. It needs a:\tmp\tmp folder to successfully run, see the CopyFolder function.

function createdMainForm {
    $mainForm = New-Object System.Windows.Forms.Form

    $btn = New-Object System.Windows.Forms.Button

    $btn.Text = "RoboCopy"

    #register click event   
    $btn.add_click({Add_click})

    $mainForm.Controls.Add($btn)

    $mainForm.ShowDialog()
}

#click event
function Add_click() {
    CopyFolder
}

function CopyFolder() {
    $sourseFolder = "C:\tmp\tmp"
    $targetFolder = "C:\tmp\tmp2"

    $Logfile = "c:\tmp\a.log"

    robocopy $sourseFolder $targetFolder /tee /log:$Logfile
}

function ReadMode() {
    Write-Host Mode [1 for GUI mode]

    $mode = Read-Host

    if ($mode -eq 1) {
        createdMainForm
    } else {
        CopyFolder
    }
}

ReadMode

I want to capture the robocopy progress in a log file as well as in the console.

However only the log file capture the output, while the console "hangs" until end.

I found that is works smoothly when PowerShell does not display form, but simply runs the command. The script works in two modes. enter 1 for "form mode" anything else for console mode, where the log actually written to console and file.

How can I use the form, and display the progress in the console?


Solution

  • Use the proper robocopy parameters:

    /log:<LogFile> Writes the status output to the log file (overwrites the existing log file). /unilog:<LogFile> can be used instead if your logfile is going to contain non-ascii characters.

    /tee Writes the status output to the console window, as well as to the log file.

    robocopy $s $t /tee /log:C:\path\to\your.log
    

    As for updating the output of your embedded control, you probably need to refresh your form on a timer:

    $timer = New-Object Windows.Forms.Timer
    $timer.Interval = 1000
    $timer.add_tick({$form.Refresh()})
    

    Start the timer when calling robocopy and stop it after the command completes. Details will vary depending on your actual code (which you chose to omit).


    Edit: I think I finally understood what you're trying to achieve and what problem you have getting there.

    You're running robocopy from a scriptblock that is associated with a form element. Because of that STDOUT output doesn't go to the console. You need to take the robocopy output (the success output stream) and write it to the host console yourself:

    function CopyFolder() {
        ...
        robocopy $sourseFolder $targetFolder /tee /log:$Logfile | Write-Host
    }