Como obter a robocópia em execução no PowerShell?

24

Estou tentando usar a robocopy dentro do powershell para espelhar alguns diretórios em minhas máquinas domésticas. Aqui está o meu 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"
}

O script utiliza um arquivo csv com uma lista de diretórios de origem e destino. Quando executo o script, recebo estes erros:

-------------------------------------------------------------------------------
   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 !

Alguma idéia do que eu preciso fazer para corrigir?

Obrigado, Mark.

Mark Allison
fonte

Respostas:

10

Se as variáveis ​​para $whate $optionsnão mudam, por que são variáveis?

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

Este trabalho é bom para mim:

robocopy   $source $dest /COPYALL /B /SEC /MIR /R:0 /W:0 /NFL /NDL
Tatiana Racheva
fonte
Bom ponto - mantenha-o simples. :)
Helvick
3
Também / não seg / seg / é crítica aqui
1
Então você acabou de pular o / Log e funcionou :-) Entendi, você recebe Erros estranhos chamando Robocopy com PS quando o Logfile não existe anteriormente.
precisa saber é o seguinte
6
Sei que este é um post antigo, mas acho que vale a pena dizer que tê-los como variáveis ​​é um sinal para os futuros leitores do script de que eles deveriam ser partes configuráveis ​​do script. A razão pela qual isso funciona é que isso corrige o erro de digitação no $ what original.
Oct
2
Mesmo que algo não esteja mudando, o encapsulamento variável pode ajudar a tornar um script menos complicado. E se eu precisar referenciar essa variável novamente mais tarde, isso tornará o script mais dinâmico #
Kolob Canyon
20

Preencher cadeias de caracteres em parâmetros para comandos externos de dentro do Powershell exige alguns saltos de argola se você quiser usar expansão variável e também fazer com que a linha de comando resultante entenda corretamente quais parâmetros você deseja separar e quais não devem. No seu exemplo, você está enviando a cadeia inteira como o primeiro parâmetro e o Robocopy está dizendo que não pode encontrar essa cadeia longa como um diretório de origem. Você deseja que toda a cadeia de origem seja tratada como um parâmetro (incluindo espaços que possam estar lá), da mesma forma que para Destino, mas suas opções $ what e $ falharão porque ambas serão entregues ao Robocopy como um único parâmetro que não pode ser analisado.

Existem algumas maneiras de fazer isso da maneira certa, mas o seguinte trecho é baseado na maneira como você parece querer quebrar seus parâmetros e funciona no exemplo de diretório único que eu usei.

$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
Helvick
fonte
Obrigado pela resposta. Eu tentei o seu código, mas eu ainda obter o seguinte erro: Erro: Parâmetro inválido # 3: "/ COPYALL / B / SEC / MIR"
Mark Allison
Quando executo o código stub acima (copiado de cima), ele funciona exatamente como o esperado - especificamente todas as opções \ quais itens são reconhecidos como parâmetros separados. Se você executar apenas o esboço acima (com uma pasta de origem que existe), ele funciona? Nesse caso, verifique as aspas \ escapando em seu próprio código modificado. O parâmetro inválido nº 3 indica que sua versão de $ what ainda é uma única string, não uma matriz de parâmetros separados no código que você está executando.
Helvick
2
+1. Esse é definitivamente o problema aqui. Acho engraçado como as pessoas constantemente tentar usar o PowerShell como se fosse um velho shell baseado em texto somente ;-)
Joey
@ Joey Você achou que o modelo de objetos do PowerShell funcionou melhor na prática do que os baseados em texto?
Didier A.
1
@DidierA .: Definitivamente. Especialmente onde existem objetos para descrever as coisas que interagem com, por exemplo, arquivos, processos, serviços, etc. Mas mesmo quando você só tem aplicações nativas e saídas de cordas você pode apenas usar os operadores de string habituais, por exemplo, -matche -replace, assim como a filtragem / cmdlets de projeção trabalhar com isso. Geralmente, é bem projetado nesse sentido (a maioria dos *-Objectcomandos é ortogonal e todos podem ser aplicados a qualquer objeto).
Joey
3

Remover as aspas da linha de robocópia?

ie

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
}
Bryan
fonte
Não, tentei primeiro e não funcionou (erros semelhantes), então mudei para o que é mostrado acima. Alguma outra ideia?
Mark Allison
Qual é o resultado quando você o executa sem aspas? Sua saída original mostrando a origem como "P: \ C: \ Backup \ Photos \ COPYALL \ B \ SEC \ \ MIR \ R: 0 \ W: 0 \ NFL \ NDL \ LOG: MyLogfile.txt \" foi o que chamou minha atenção às citações.
Bryan3 /
3

Eu tive o mesmo problema. Toda a linha de comando foi interpretada como o primeiro argumento.

Nada mencionado acima funcionou, incluindo:

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

Deixar as aspas não funciona quando há um espaço no caminho:

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

Depois de tentar os truques em http://edgylogic.com/blog/powershell-and-external-commands-done-right/ , finalmente entendi.

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

Talvez eu devesse ter ficado com os arquivos bat. :)

Justin
fonte
O seu link para edgylogic mudou para slai.github.io/posts/… ?
Henrik Staun Poulsen 22/11
1

Eu descobri que a melhor maneira de executar um comando nativo é usar o comando & para executar uma lista de strings. Além disso, se você deseja que a saída do console seja incluída em uma transcrição do PowerShell, será necessário canalizar a saída para o host externo. Aqui está um exemplo de chamada ao 7Zip com vários parâmetros extraídos de um 7-Zip para o Amazon S3 Powershell Script que eu escrevi:

$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
}

Basicamente, para o seu caso, eu tentaria algo assim (talvez seja necessário quebrar os parâmetros de opções $ what e $ individualmente):

$robocopypath = "c:\pathtofolder\robocopy.exe"
& $robocopypath "$source" "$dest" "$what" "$options" "/LOG:MyLogfile.txt"
Greg Bray
fonte
O problema é que, como você diz "$ what" e "$ options", eles são enviados para a robocópia como parâmetros únicos, em vez de uma lista de parâmetros separados. isto.
Helvick
Você pode usar o operador de splat @se você estiver usando powershell v3 para dividir uma lista separada por vírgula em uma pilha de argumento
Zasz
0
invoke-expression "robocopy $source $dest $what $options /LOG:MyLogfile.txt"

Isso interpolará todas as variáveis ​​e chamará a sequência resultante. Do jeito que você tem agora, parece que a robocópia está sendo chamada com aspas em todas as opções, ou seja, robocopy "c: \ src c: \ dst blah meh". Isso é interpretado como um único parâmetro.

M Aguilar
fonte
0

Isso funcionou para mim e permite uma entrada dinâmica do local do arquivo de log. o símbolo & diz ao PowerShell que o texto é uma linha de código que eu quero executar.

    $source = "E:\BackupToRestore\"
    $destination = "E:\RestoreMe\"
    $logfile = "E:\robocopyLogFile.txt"    
    $switches = ("/B", "/MIR", "/XJ", "/FFT", "/R:0", "/LOG:$logfile")
    & robocopy $source $destination $roboCopyString $switches
BriGuy
fonte
0

Adicionando meus 2 centavos a isso, pois isso pode ajudar alguém ... O código abaixo está faltando a parte "loop" onde eu li um csv para obter os arquivos para copiar

# first we setup an array of possible robocopy status
$RobocopyErrors="NO ERRORS",
            "OKCOPY",
            "XTRA",
            "OKCOPY + XTRA",
            "MISMATCHES",
            "OKCOPY + MISMATCHES",
            "MISMATCHES + XTRA",
            "OKCOPY + MISMATCHES + XTRA",
            "FAIL",
            "OKCOPY + FAIL",
            "FAIL + XTRA",
            "OKCOPY + FAIL + XTRA",
            "FAIL + MISMATCHES& goto end",
            "OKCOPY + FAIL + MISMATCHES",
            "FAIL + MISMATCHES + XTRA",
            "OKCOPY + FAIL + MISMATCHES + XTRA",
            "***FATAL ERROR***"
#setting some variables with the date
$DateLogFile=get-date -format "yyyyddMMhh"

#this commands below one usually goes into a loop
$DateLog=get-date -format "yyyyddMMhhmmss"

#adding options and command arg as described in previous post
$options = @("/R:0","/W:0")
$cmdArgs = @("$Source","$Destination",$File,$options)

#executing Robocopy command
robocopy @cmdArgs

# We capture the lastexitcode of the command and use to confirm if all was good or not

$errorlevel=$LASTEXITCODE
# I output the status to a log file
"$DateLog`t::$($RobocopyErrors[$errorlevel])::`"$file`"`t`"$Source`" -> `"$Destination`"" | out-file "$scriptPath\Logs\$DateLogFile.log" -append
 if ($errorlevel -lt 8) {
    #error below 8 = all is good

}
else {
    # something bad happened ..  

}
galadriann
fonte