将 robocopy 日志转换为 csv 文件 [英] Convert a robocopy log into a csv file

查看:64
本文介绍了将 robocopy 日志转换为 csv 文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法把robocopy的输出日志转成csv文件?复制大小、日期、来源和目的地的列?如果我运行多个 robocopy,每个副本都有自己的行.谢谢

Is there a way to get the output logs of robocopy into a csv file? A column for size copied, date, source and destination? and if I run multiple robocopys have each copy have its own line. Thanks

$Logfile = "C:\Powershell\robocopy.txt"
Clear-Content "C:\Powershell\robocopy.txt" -Force
$EmailFrom = "testing@test.com"
$EmailTo = "test@testing.com"
$EmailBody = "completed successfully. See attached log file"
$EmailSubject = "Summary"

$files = @("SCRIPT")

for($i = 0; $i -lt $files.Count; $i++){
    robocopy "C:\$($files[$i])" "C:\NEW TEST\folder\folder\$($files[$i])" /Z /e /xx /W:5 /NFL /NDL /NJH /nc /np /unilog+:$Logfile
}

Send-MailMessage -To $EmailTo -from $EmailFrom -Subject $EmailSubject -Body $EmailBody -attachment $Logfile -smtpserver 192.168.243.22 -Port 25

输出日志:

------------------------------------------------------------------------------
               Total    Copied   Skipped  Mismatch    FAILED    Extras
    Dirs :         4         0         4         0         0         0
   Files :        17         0        17         0         0         0
   Bytes :    27.0 k         0    27.0 k         0         0         0
   Times :   0:00:00   0:00:00                       0:00:00   0:00:00
   Ended : Thursday, April 29, 2021 11:55:52 AM

推荐答案

这里还有很多事情要解决.请参阅这个问题和我的回答.

There's a lot more going on here that what's in the question. See this question, and my answer.

总而言之,OP 希望将每个 RoboCopy 作业的自定义摘要行添加到电子邮件中.

In summary the OP wanted to add a custom summary line from each RoboCopy job to an email message.

示例:

Bytes Copied: 27.0 k on Thursday, April 29, 2021 6:15:20 PM

一些事情变得明显:

  1. 基于他有多个 RoboCopy 作业在循环中运行的事实,并且他正在使用 RoboCopy 的 /unilog+:$LogFile,很明显需要制作一行并将其添加到每个 RoboCopy 作业的电子邮件正文.
  2. 根据评论,我们将查看复制的字节数.注意:这与Doug 的巧妙方法/答案中提到的印象不同.
  3. OP 还通过评论扩展了问题以导出 CSV 数据和电子邮件正文.
  1. Based on the fact that he had multiple RoboCopy jobs running in a loop, and that he was using RoboCopy's /unilog+:$LogFile, it was clear that a line needed to be crafted and added to an email body per RoboCopy Job.
  2. From the comments we're to look at Bytes copied. Note: that differs from the impression noted in Doug's clever approach/answer.
  3. Also via the comments the OP expanded the question to export the CSV data as well as the email body.

不用说,但随着范围的扩大,答案变得更加混乱.让他就 CSV 内容提出一个新问题确实让我想到了.具有讽刺意味的是,我不知道另一个问题.但是,我想确保这两个任务得到最佳组合.也就是说,请考虑以下结合其他案例的建议和实现的提炼示例:

Needless to say, but the answer got messier as the scope expanded. It did cross my mind to have him ask a new question for the CSV stuff. Ironically I didn't know about this other question. However, I wanted to make sure the 2 tasks were optimally combined. That said, please consider the below distilled examples combining suggestions and realizations from the other case:

Clear-Content "C:\Powershell\robocopy.txt" -Force
$Logfile      = "C:\PowerShell\robocopy.txt"
$CsvFile      = "C:\PowerShell\RoboCsv.txt"
$EmailFrom    = "testing@test.com"
$EmailTo      = "test@test.com"
$EmailBody    = [Collections.ArrayList]@("completed successfully. See attached log file & below summary","")
$EmailSubject = "Summary"
$CsvData      = [Collections.ArrayList]@()

$Files = @("SCRIPT")

ForEach( $File in $Files )
{
    $Source = "C:\$File"
    $Dest   =  "C:\NEW TEST\folder\folder\$File"

    $Log = robocopy $Source $Dest /Z /e /xx /W:5 /MAXAGE:2 /NFL /NDL /NJH /nc /np /unilog+:$Logfile /tee

    $Date = ( ( $log -match "^\s+Ended.+" ) -split ":", 2 )[1].Trim()
    $Line = ( $Log -match "^\s+Bytes.+" ) -split "\s+"
        
    $Copy = $Line[5]
    $Mult = $Line[4]

    $Line = "Bytes Copied: $Copy $Mult on $Date"

    [Void]$EmailBody.Add($Line)

    # For Csv output:
    [Void]$CsvData.Add(
        [PSCustomObject]@{
            SizeCopied  = $Copy
            Date        = $Date
            Source      = $Source
            Destination = $Dest
        } )    
}    

# Flip the $EmailBody array back to being a regular string.
$EmailBody = $EmailBody -join "`r`n"

Send-MailMessage -To $EmailTo -From $EmailFrom -Subject $EmailSubject -Body $EmailBody -Attachment $Logfile -SMTPserver 192.168.243.22

# Output to CSVFile
$CsvData | Export-Csv -Path $CsvFile -NoTypeInformation

说明:

  1. ForEach(...) 替换传统的 For 循环结构.没有明显的理由使用更神秘的传统循环.
  2. 此处的关键部分是将 /TEE 参数添加到 RoboCopy 命令中.这会将输出发送到控制台的成功流,我们将在 $Log 变量中捕获它.
  3. 由于选择了日志记录选项,$Log 将永远只有来自给定 RoboCopy 作业的小摘要数据.因此,没有内存问题...
  4. $Log 应该是一个典型的 [Object[]] 数组,所以 -match 将返回匹配的元素.因此,假设一个完整的保真日志段(稍后会详细介绍),$Line$Date 应该没有问题.$Date 被分割成只保存日期字符串.而且,$Line 将是一个数组,我们可以从中轻松地将数据点与索引相关联.
  5. $Line 转换为电子邮件正文所需的字符串,然后将其添加到 $EmailBody 数组列表中.
  6. 创建具有所需属性的 [PSCustomObject],将其添加到 $CSVData 数组列表以供以后导出.
  7. 最后,当我们退出循环时,我们可以将 $EmailBody 转换为一个整体字符串,用于 Send-EmailMessage-Body 参数.我们还会将 $CSVData 导出到 CSV 文件.
  1. Replaces traditional For loop Construct with a ForEach(...). There was no discernable reason to use the more cryptic traditional loop.
  2. The key piece here is to add the /TEE parameter to the RoboCopy command. That will, send output to the console's success stream where we'll capture it in the $Log variable.
  3. Because of the logging options chosen $Log will only ever have the small summary data from a given RoboCopy job. Therefore, there's no memory concern...
  4. $Log should be a typical [Object[]] array, so -match will return the matching elements. So, Assuming a full fidelity log segment (more on that later), both $Line & $Date should populate no problem. $Date is split such that it will only hold the date string. And, $Line will be an array from which we can easily relate the data points to the indices.
  5. Convert $Line to the desired string for the email body then add it to the $EmailBody array list.
  6. Create a [PSCustomObject] with the desired properties, adding it to the $CSVData array list for later export.
  7. Finally when we're out of the loop, we can convert $EmailBody to a monolithic string for use in Send-EmailMessage's -Body argument. And we'll also Export $CSVData to a CSV file.

正如在其他讨论中提到的,我并不特别喜欢以这种方式累积数组.另一种方法可能是将循环输出分配给 $CSVData,而不必费心收集电子邮件正文行.然后当该循环完成时,我可以在 $CSVData 上运行第二个后处理循环来编译电子邮件正文.然而,乘数在这里发挥了作用.它不是 CSV 数据规范的一部分.可以说,它应该考虑到您不知道您是在查看 KB 还是 MB.也就是说,除了执行更多的逻辑来通用字节或为乘法器添加另一列之外,我只是认为这已经足够了.

As mentioned in the other discussion I don't particularly like accumulating arrays in this way. The alternate approach might have been to assign the loop output to $CSVData not bothering to collect the email body lines. Then when that loop is complete I could run a second post-process loop on $CSVData to compile the email body. However, the multiplier plays a role here. It was not part of the specification for the CSV data. Arguably it should be considering you wouldn't know if you were looking at KB or MB. That said, short of executing a lot more logic to common-denominate on bytes or adding another column for the multiplier, I just thought this was good enough.

另外,我没有费心去转换数字和日期.目前,电子邮件正文行和 CSV 数据的所有计算数据都将转换为字符串.同样,如果我们的任务是计算一个共同的乘数,或者可能想要一个不同的日期字符串,故事可能会有所不同.

Also, I didn't bother casting numeric and dates. As it currently stands all calculated data would be converted to string for both the email body line and the CSV data. Again if we were tasked with calculating a common multiplier or perhaps wanted a different date string the story might be different.

注意

如果 RoboCopy 产生意外输出,则此逻辑中的某些部分将失败.特别是比赛可能不退还!特别是,如果 RoboCopy 作业由于初始命令的问题而无法运行,则可能会发生这种情况,例如:

If the RoboCopy produces unexpected output some of this logic will fail. Particularly matches may not be returned! In particular this can happen if the RoboCopy job doesn't run because of an issue with the initial command, for example:

Robocopy C:\DoesNotExist C:\temp\SomeOtherFolder

将返回:

    -------------------------------------------------------------------------------
       ROBOCOPY     ::     Robust File Copy for Windows
    -------------------------------------------------------------------------------
    
      Started : Friday, April 30, 2021 8:06:46 PM
       Source : c:\DoesNotExist\
         Dest : C:\temp\SomeOtherFolder\
    
        Files : *.*
    
      Options : *.* /DCOPY:DA /COPY:DAT /R:1000000 /W:30
    
    ------------------------------------------------------------------------------

显然,没有以Bytes"开头的行;或结束".

Obviously, there are no lines starting with "Bytes" or "Ended".

我感觉 RoboCopy 使用不当:

指定来源& 是一个常见的错误目标文件路径作为前 2 个位置参数.然而 RoboCopy 旨在复制文件夹结构,所以前 2 个参数应该是目录!

It is a common error to specify source & destination file paths as the first 2 positional arguments. However RoboCopy is designed to copy folder structures, so the first 2 arguments should be directories!

RoboCopy 帮助:

Usage :: ROBOCOPY source destination [file [file]...] [options]

我们从名为 $Files 的数组中绘制的事实表明存在问题.此外, $File 被连接到现有路径上.此外,附在 其他答案 上的讨论准确显示了您所期望的不匹配和空值问题的类型.

The fact that we're drawing from an array named $Files indicates a problem. Moreover, $File is being concatenated onto an existing path. Also, the discussion attached to the other answer shows exactly the kinds of no match and null value issues you'd expect.

假设我是对的,RoboCopy 命令应该看起来更像下面的例子:

Assuming I'm correct the RoboCopy Command should look more like the below example:

Clear-Content "C:\Powershell\robocopy.txt" -Force
$Logfile      = "C:\PowerShell\robocopy.txt"
$CsvFile      = "C:\PowerShell\RoboCsv.txt"
$EmailFrom    = "testing@test.com"
$EmailTo      = "test@test.com"
$EmailBody    = [Collections.ArrayList]@("completed successfully. See attached log file & below summary","")
$EmailSubject = "Summary"
$CsvData      = [Collections.ArrayList]@()

$Files = @("SCRIPT")

ForEach( $File in $Files )
{
    $Source  = "C:\"
    $Dest   =  "C:\NEW TEST\folder\folder\"

    $Log = robocopy $Source $Dest $File /Z /e /xx /W:5 /MAXAGE:2 /NFL /NDL /NJH /nc /np /unilog+:$Logfile /tee

    $Date = ( ( $log -match "^\s+Ended.+" ) -split ":", 2 )[1].Trim()
    $Line = ( $Log -match "^\s+Bytes.+" ) -split "\s+"
        
    $Copy = $Line[5]
    $Mult = $Line[4]

    $Line = "Bytes Copied: $Copy $Mult on $Date"

    [Void]$EmailBody.Add($Line)

    # For Csv output:
    [Void]$CsvData.Add(
        [PSCustomObject]@{
            SizeCopied  = $Copy
            Date        = $Date
            Source      = (Join-Path $Source $File)
            Destination = (Join-Path $Dest $File)
        } )
}

# Flip the $EmailBody array back to being a regular string.
$EmailBody = $EmailBody -join "`r`n"

Send-MailMessage -To $EmailTo -From $EmailFrom -Subject $EmailSubject -Body $EmailBody -Attachment $Logfile -SMTPserver 192.168.243.22

# Output to CSVFile
$CsvData | Export-Csv -Path $CsvFile -NoTypeInformation

注意:这需要一个完整的例子,因为 $Source &$Dest 发生了变化,因此 [PSCustomObject] 声明中的赋值也发生了变化.

Note: This required a complete example because $Source & $Dest changed therefore the assignments in the [PSCustomObject] declaration also changed.

如果我对 RoboCopy 语法不正确的说法是正确的,那就引出了另一个完全不同的问题;我们为什么要使用 RoboCopy.不要误会我的意思,我喜欢 RoboCopy,但是一次简单地复制 1 个文件是多余的.此外,我可以想到使用典型的 Copy-Item 以及类似的电子邮件和代码的更雄辩的代码模式.报告.

If I'm correct that the RoboCopy syntax is incorrect it begs another totally different question; Why are we using RoboCopy at all. Don't get me wrong I love RoboCopy, but it's overkill to simply copy 1 file at a time. Furthermore, I can think of more eloquent code patterns using typical Copy-Item complete with similar email & reporting.

这篇关于将 robocopy 日志转换为 csv 文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆