Powershell with Robocopy and Arguments Passing

34,549

Solution 1

Use the arrays, Luke. If you specify an array of values, PowerShell will automatically expand them into separate parameters. In my experience, this is the most reliable method. And it doesn't require you to mess with the Start-Process cmdlet, which is in my opinion is overkill for such tasks.

This trick is from the best article I've seen on the PowerShell behavior towards external executables: PowerShell and external commands done right.

Example:

$source = 'C:\hold\first test'
$destination = 'C:\hold\second test'
$robocopyOptions = @('/NJH', '/NJS')
$fileList = 'test.txt'

$CmdLine = @($source, $destination, $fileList) + $robocopyOptions
& 'robocopy.exe' $CmdLine

Solution 2

Start robocopy -args "$source $destination $fileLIst $robocopyOptions"
or
robocopy $source $destination $fileLIst $robocopyOptions.split(' ')

Solution 3

You can't use a string to pass options in that way because when you write

robocopy $source $destination $fileList $robocopyOptions

PowerShell will evaluate the last variable ($robocopyOptions) as a single string and it will quote it. This means robocopy will get "/NJH /NHS" (single string, quoted) on its command line. (Obviously not the intent.)

For details on how to work around these kinds of issues, see here:

http://windowsitpro.com/powershell/running-executables-powershell

The article includes the following function:

function Start-Executable {
  param(
    [String] $FilePath,
    [String[]] $ArgumentList
  )
  $OFS = " "
  $process = New-Object System.Diagnostics.Process
  $process.StartInfo.FileName = $FilePath
  $process.StartInfo.Arguments = $ArgumentList
  $process.StartInfo.UseShellExecute = $false
  $process.StartInfo.RedirectStandardOutput = $true
  if ( $process.Start() ) {
    $output = $process.StandardOutput.ReadToEnd() `
      -replace "\r\n$",""
    if ( $output ) {
      if ( $output.Contains("`r`n") ) {
        $output -split "`r`n"
      }
      elseif ( $output.Contains("`n") ) {
        $output -split "`n"
      }
      else {
        $output
      }
    }
    $process.WaitForExit()
    & "$Env:SystemRoot\system32\cmd.exe" `
      /c exit $process.ExitCode
  }
}

This function will let you run an executable in the current console window and also let you build an array of string parameters to pass to it.

So in your case you could use this function something like this:

Start-Executable robocopy.exe $source,$destination,$fileList,$robocopyOptions

Solution 4

Putting the options in separate arguments worked for me. Using Robocopy for copying excluding any CSV files.

$roboCopyPath = $env:ROBOCOPY_PATH
$otherLogsPath = [System.IO.Path]::Combine($basePath, "Logs-Other")
$atrTestResults = [System.IO.Path]::Combine($Release, $BuildNumber)
$ResultsSummary = [System.IO.Path]::Combine($basePath, "Result")

$robocopyOptions = @("/log:$otherLogsPath\robocopy.log", '/xf', '*.csv')
$CmdLine = @($atrTestResults, $ResultsSummary) + $robocopyOptions 
&$roboCopyPath $CmdLine
Share:
34,549

Related videos on Youtube

Baluta Eugen
Author by

Baluta Eugen

I've been developing for windows since about 1993, everything from VB to MFC to Managed code. I worked at Microsoft from 1998-2012, since then I spend a lot more time coding and a lot less time presenting.

Updated on November 25, 2020

Comments

  • Baluta Eugen
    Baluta Eugen over 3 years

    I'm trying to write a script that uses robocopy. If I were just doing this manually, my command would be:

    robocopy c:\hold\test1 c:\hold\test2 test.txt /NJH /NJS
    

    BUT, when I do this from powershell, like:

    $source = "C:\hold\first test"
    $destination = "C:\hold\second test"
    $robocopyOptions = " /NJH /NJS "
    $fileList = "test.txt"
    
    robocopy $source $destination $fileLIst $robocopyOptions
    

    I get:

    -------------------------------------------------------------------------------
       ROBOCOPY     ::     Robust File Copy for Windows
    -------------------------------------------------------------------------------
    
      Started : Fri Apr 10 09:20:03 2015
    
       Source - C:\hold\first test\
         Dest - C:\hold\second test\
    
        Files : test.txt
    
      Options : /COPY:DAT /R:1000000 /W:30
    
    ------------------------------------------------------------------------------
    
    ERROR : Invalid Parameter #4 : " /NJH /NJS "
    

    However, if I change the robocopy command to

    robocopy $source $destination $fileLIst  /NJH /NJS 
    

    everything runs successfully.

    So, my question is, how can I pass a string as my robocopy command options (and, in a larger sense, do the same for any given external command)

  • Bill_Stewart
    Bill_Stewart about 9 years
    Start-Process is OK if you don't mind the separate console window.
  • Anton Z
    Anton Z about 9 years
    use -NoNewWindow -PassThru -Wait arguments to avoid separate console window
  • Bill_Stewart
    Bill_Stewart about 9 years
    IIRC, Start-Process doesn't update $LASTEXITCODE. That may be important in some cases.
  • Sharpenologist
    Sharpenologist about 5 years
    Original link in answer is dead ... Here is the updated link: PowerShell and external commands done right
  • beatcracker
    beatcracker about 5 years
    @Sharpenologist Thanks, fixed!