Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'm trying to use robocopy inside powershell to mirror some directories on my home machines. Here's my script:

param ($configFile)

$config = Import-Csv $configFile
$what = "/COPYALL /B /SEC/ /MIR"
$options = "/R:0 /W:0 /NFL /NDL"
$logDir = "C:\Backup\"

foreach ($line in $config)
{
 $source = $($line.SourceFolder)
 $dest = $($line.DestFolder)
 $logfile =  $logDIr 
 $logfile += Split-Path $dest -Leaf
 $logfile += ".log"

 robocopy "$source $dest $what $options /LOG:MyLogfile.txt"
}

The script takes in a csv file with a list of source and destination directories. When I run the script I get these errors:

-------------------------------------------------------------------------------
   ROBOCOPY     ::     Robust File Copy for Windows                              
-------------------------------------------------------------------------------

  Started : Sat Apr 03 21:26:57 2010

   Source : P:\ C:\Backup\Photos \COPYALL \B \SEC\ \MIR \R:0 \W:0 \NFL \NDL \LOG:MyLogfile.txt\
     Dest - 

    Files : *.*

  Options : *.* /COPY:DAT /R:1000000 /W:30 

------------------------------------------------------------------------------

ERROR : No Destination Directory Specified.

       Simple Usage :: ROBOCOPY source destination /MIR

             source :: Source Directory (drive:\path or \\server\share\path).
        destination :: Destination Dir  (drive:\path or \\server\share\path).
               /MIR :: Mirror a complete directory tree.

    For more usage information run ROBOCOPY /?


****  /MIR can DELETE files as well as copy them !

Any idea what I need to do to fix?

Thanks, Mark.

share|improve this question

6 Answers 6

up vote 4 down vote accepted

If the variables for $what and $options don't change, why are they variables?

$what = "/COPYALL /B /SEC /MIR" 
$options = "/R:0 /W:0 /NFL /NDL" 

This works fine for me:

robocopy   $source $dest /COPYALL /B /SEC /MIR /R:0 /W:0 /NFL /NDL
share|improve this answer
    
Good point - keep it simple. :) –  Helvick Apr 4 '10 at 1:31
    
also /sec not /sec/ is critical here –  tony roth Apr 4 '10 at 1:40
    
So you just skipped the /Log and it worked :-) Gotcha is that you get strange Errors calling Robocopy with PS when the Logfile does not exist beforehand. –  icnivad Apr 26 '13 at 5:32
    
This does not work when $dest is an array (e.g. robocopy $source $dest[$I] /MIR /Z) will fail. –  Zian Choy Apr 29 at 22:54

Populating strings into parameters for external commands from within Powershell requires some hoop jumping if you want to be able to use variable expansion and also have the resulting command line properly understand which parameters you want to be separated and which should not. In your example you are sending the entire string as the first parameter and Robocopy is telling you that it can't find that long string as a source directory. You do want the entire Source string to be treated as one param (including spaces that may be in there), likewise for Destination but your $what and $options will fail because they will both be delivered to Robocopy as a single parameter which cannot be parsed.

There are a few ways to do this right but the following snippet is based on the way you seem to want to break out your parameters and does work for the single directory example I've used.

$source="C:\temp\source"
$dest="C:\temp\dest"

$what = @("/COPYALL","/B","/SEC","/MIR")
$options = @("/R:0","/W:0","/NFL","/NDL")

$cmdArgs = @("$source","$dest",$what,$options)
robocopy @cmdArgs
share|improve this answer
    
Thanks for the reply. I've tried your code but I still get the following error: ERROR : Invalid Parameter #3 : "/COPYALL /B /SEC /MIR" –  Mark Allison Apr 3 '10 at 22:18
    
When I run the above stub code (copied from above) it works exactly as expected - specifically all the options\what items are recognised as separate parameters. If you run just the above stub (with a source folder that exists) does it work? If so then double check the Quotes\escaping in your own modified code. The invalid parameter #3 indicates that your version of $what is still a single string not an array of separate parameters in the code you are running. –  Helvick Apr 3 '10 at 22:56
2  
+1. That's definitely the issue here. I find it funny how people constantly try to use PowerShell as if it were an old text-only-based shell ;-) –  Joey Nov 24 '10 at 13:33

Remove the quotes from the robocopy line?

i.e.

param ($configFile)

$config = Import-Csv $configFile
$what = "/COPYALL /B /SEC/ /MIR"
$options = "/R:0 /W:0 /NFL /NDL"
$logDir = "C:\Backup\"

foreach ($line in $config)
{
 $source = $($line.SourceFolder)
 $dest = $($line.DestFolder)
 $logfile =  $logDIr 
 $logfile += Split-Path $dest -Leaf
 $logfile += ".log"

 robocopy $source $dest $what $options /LOG:MyLogfile.txt
}
share|improve this answer
    
No I tried that first and it didn't work (similar errors), so I changed it to what is shown above. Any other ideas? –  Mark Allison Apr 3 '10 at 20:02
    
What's the output when you run it without quotes? Your original output showing the Source as "P:\ C:\Backup\Photos \COPYALL \B \SEC\ \MIR \R:0 \W:0 \NFL \NDL \LOG:MyLogfile.txt\" was what drew my attention to the quotes. –  Bryan Apr 3 '10 at 20:34

I have found that the best way to execute a native command is to use the & command to execute a list of strings. Also if you want the console output to be included in a powershell transcript you will need to pipe the output to out-host. Here is an example of calling 7Zip with multiple parameters taken from a 7-Zip to Amazon S3 Powershell Script that I wrote:

$7ZipPath = "C:\Program Files\7-Zip\7z.exe" #Path to 7Zip executable
$FolderPath = "C:\Backup" #Folder to backup (no trailing slash!)
$FolderName = $FolderPath.Substring($FolderPath.LastIndexOf("\")+1) #grab the name of the backup folder
$TimeStamp = [datetime]::Now.ToString("yyyy-MM-dd_HHmm") #Create unique timestamp string
$strFile = [String]::Format("{0}\{1}_{2}.7z", "c:\",$FolderName,$TimeStamp) #Create filename for the zip
#7z options: add, type 7z, Archive filename, Files to add (with wildcard. Change \* to \prefix* or \*.txt to limit files), compression level 9, password, encrypt filenames, Send output to host so it can be logged.
& $7ZipPath "a" "-t7z" "$strFile" "$FolderPath\*" "-mx9" "-r" "-pPASSWORD" "-mhe" | out-host #create archive file
if($LASTEXITCODE -ne 0){ #Detect errors from 7Zip. Note: 7z will crash sometimes if file already exists
    Write-Error "ERROR: 7Zip terminated with exit code $LASTEXITCODE. Script halted."
    exit $LASTEXITCODE
}

Basically for your case I would try something like this (may need to break out the $what and $options parameters individually):

$robocopypath = "c:\pathtofolder\robocopy.exe"
& $robocopypath "$source" "$dest" "$what" "$options" "/LOG:MyLogfile.txt"
share|improve this answer
    
The problem with this is that as you say "$what" and "$options" will get sent to robocopy as single parameters rather than a list of separate ones and given his sample code they will have to be broken out, there's no may about it. –  Helvick Apr 4 '10 at 19:34
    
You can use the splat operator @ if you are using powershell v3 to split a comma separated list into an argument stack –  Zasz Sep 8 '12 at 4:21

I had the same problem. The whole command line was interpreted as the first argument.

Nothing mentioned above worked including:

invoke-expression "robocopy ""$sourceFolder"" ""$destinationFolder"" /MIR"  
invoke-expression "robocopy \`"$sourceFolder\`" \`"$destinationFolder\`" /MIR"  

Leaving out the quotes doesn't work when there's a space in the path:

invoke-expression "robocopy $sourceFolder $destinationFolder /MIR"  

After trying the tricks in http://edgylogic.com/blog/powershell-and-external-commands-done-right/, I finally got it.

robocopy "\`"$sourceFolder"\`" "\`"$destinationFolder"\`" /MIR

Maybe I should have stuck with bat files. :)

share|improve this answer
invoke-expression "robocopy $source $dest $what $options /LOG:MyLogfile.txt"

This will interpolate all of the variables, then call the resulting string. The way you have it now, it looks like robocopy is being invoked with the quotes around all of the options, i.e., robocopy "c:\src c:\dst blah meh". This is interpreted as a single parameter.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.