Powershell with Robocopy and Arguments Passing
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
Related videos on Youtube
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, 2020Comments
-
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 about 9 years
Start-Process
is OK if you don't mind the separate console window. -
Anton Z about 9 yearsuse
-NoNewWindow -PassThru -Wait
arguments to avoid separate console window -
Bill_Stewart about 9 yearsIIRC,
Start-Process
doesn't update$LASTEXITCODE
. That may be important in some cases. -
Sharpenologist about 5 yearsOriginal link in answer is dead ... Here is the updated link: PowerShell and external commands done right
-
beatcracker about 5 years@Sharpenologist Thanks, fixed!