将 robocopy 日志转换为 csv 文件 [英] Convert a robocopy log into a csv file
问题描述
有没有办法把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
一些事情变得明显:
- 基于他有多个 RoboCopy 作业在循环中运行的事实,并且他正在使用 RoboCopy 的
/unilog+:$LogFile
,很明显需要制作一行并将其添加到每个 RoboCopy 作业的电子邮件正文. - 根据评论,我们将查看复制的字节数.注意:这与Doug 的巧妙方法/答案中提到的印象不同.
- OP 还通过评论扩展了问题以导出 CSV 数据和电子邮件正文.
- 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. - From the comments we're to look at Bytes copied. Note: that differs from the impression noted in Doug's clever approach/answer.
- 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
说明:
- 用
ForEach(...)
替换传统的 For 循环结构.没有明显的理由使用更神秘的传统循环. - 此处的关键部分是将
/TEE
参数添加到 RoboCopy 命令中.这会将输出发送到控制台的成功流,我们将在$Log
变量中捕获它. - 由于选择了日志记录选项,
$Log
将永远只有来自给定 RoboCopy 作业的小摘要数据.因此,没有内存问题... $Log
应该是一个典型的[Object[]]
数组,所以-match
将返回匹配的元素.因此,假设一个完整的保真日志段(稍后会详细介绍),$Line
和$Date
应该没有问题.$Date
被分割成只保存日期字符串.而且,$Line
将是一个数组,我们可以从中轻松地将数据点与索引相关联.- 将
$Line
转换为电子邮件正文所需的字符串,然后将其添加到$EmailBody
数组列表中. - 创建具有所需属性的
[PSCustomObject]
,将其添加到$CSVData
数组列表以供以后导出. - 最后,当我们退出循环时,我们可以将
$EmailBody
转换为一个整体字符串,用于Send-EmailMessage
的-Body
参数.我们还会将$CSVData
导出到 CSV 文件.
- Replaces traditional For loop Construct with a
ForEach(...)
. There was no discernable reason to use the more cryptic traditional loop. - 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. - 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... $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.- Convert
$Line
to the desired string for the email body then add it to the$EmailBody
array list. - Create a
[PSCustomObject]
with the desired properties, adding it to the$CSVData
array list for later export. - Finally when we're out of the loop, we can convert
$EmailBody
to a monolithic string for use inSend-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屋!