Итак, предполагая, что журнал — это просто сводные данные, вы можете довольно эффективно его анализировать:
$Log = Get-Content C:\temp\robocopy.txt
$Date = ($Log[-1] -split ":", 2)[1].Trim()
$Line = $log | Where-Object{$_ -match "^\s+Bytes.+"}
$Line = $Line -split "\s+"
$Line = "Bytes Copied: {0} {1} on {2}" -f $Line[3], $Line[4], $Date
$Line
Это должно вывести:
Bytes Copied: 27.0 k on Thursday, April 29, 2021 11:55:52 AM
Его можно вставить после запуска команды RoboCopy. Затем укажите $Line
в тексте или теме письма...
Я не проверял ваш журнал RoboCopy, чтобы убедиться, что формат соответствует продемонстрированному. Тем не менее концепции, изображенные здесь, должны хорошо служить цели.
Объяснение:
- Получение даты простым просмотром последней строки в массиве, возвращаемом
Get-Content
. Однако это можно сделать с помощью аналогичной стратегии сопоставления, если, например, подход [-1]
ненадежен.
- Чтобы определить количество байтов в нужной строке. сопоставьте строку, затем разделите ее и обратитесь к элементам, которые, как мы знаем, содержат данные.
- Наконец, используйте 2 извлеченные строки для форматирования нужной строки.
Примечание. Как объединение, так и расширение строк также являются вариантами окончательной сборки линии. Тем не менее, я думал, что подход -f
был более удобочитаемым для этой конкретной работы.
Примечание. При этом сохраняется любой используемый RoboCopy символ множителя, т. е. k, m или любой другой. Потребовалось бы больше работы и логики, чтобы вычислить и отобразить по-другому.
Примечание. Само собой разумеется, что существует миллион способов сделать это. Если я что-то улучшу, я постараюсь добавить больше примеров.
Другой подход:
Немного иначе, используйте оператор -match
как для даты, так и для количества данных:
$Log = Get-Content C:\temp\robocopy.txt
$Date = (($log -match "^\s+Ended.+") -split ":", 2)[1].Trim()
$Line = $Log -match "^\s+Bytes.+"
$Line = $Line -split "\s+"
$Line = "Bytes Copied: {0} {1} on {2}" -f $Line[3], $Line[4], $Date
$Line
Это будет работать до тех пор, пока $Log
является массивом, потому что -match
будет возвращать совпадения напрямую. Таким образом, нам не нужно предложение Where-Object
.
Обновление:
Мне приходит в голову, что, поскольку вы запускаете несколько заданий RoboCopy в цикле и используете параметр \Unilog+
, вы, вероятно, сталкиваетесь не только с анализом данных и количества данных, но и с несколькими запусками и/или с несколькими такими сегментами в файл журнала. Просто хочу решить эту проблему, поскольку у вас есть несколько вариантов.
- Поскольку вы выполняете RoboCopy в цикле, а число
$LogFile
известно и постоянно в этом цикле, вы можете добавить разделительную строку в конце каждого задания.
for($i = 0; $i -lt $files.Count; $i++){
$Log = robocopy "C:\$($files[$i])" "C:\NEW TEST\folder\folder\$($files[$i])" /Z /e /xx /W:5 /MAXAGE:2 /NFL /NDL /NJH /nc /np /unilog+:$Logfile /tee
"---Job Completed---" | Add-Content $Logfile
}
Я не собираюсь демонстрировать это, потому что есть более удобный способ, но это даст вам известную строку, на которую можно разделить, чтобы постобработать файл журнала до нужных вам строк.
- Добавьте параметр
/TEE
в свою команду RoboCopy и назначьте вывод непосредственно переменной. Это я продемонстрирую:
$Logfile = "C:\Powershell\robocopy.txt"
Clear-Content "C:\Powershell\robocopy.txt" -Force
$EmailFrom = "[email protected]"
$EmailTo = "[email protected]"
$EmailBody = [Collections.ArrayList]@("completed successfully. See attached log file & below summary","")
$EmailSubject = "Summary"
$files = @("SCRIPT")
for($i = 0; $i -lt $files.Count; $i++){
$Log = robocopy "C:\$($files[$i])" "C:\NEW TEST\folder\folder\$($files[$i])" /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.+"
$Line = $Line -split "\s+"
$Line = "Bytes Copied: {0} {1} on {2}" -f $Line[3], $Line[4], $Date
[Void]$EmailBody.Add($Line)
}
#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.24.55
Вы можете видеть, что $Log
теперь захватывает выходные данные RoboCopy напрямую, и вы можете выполнить оставшуюся часть кода, которая выглядит аналогично, что избавляет нас от необходимости пост-обработки журнала, как я упоминал в Вариантах 1. Переключение $EmailBody
на список массивов включено нам легко добавлять рассчитанные строки в массив. Преобразуйте массив обратно в строку, чтобы он подходил для параметра -EmailBody
в командлете Send-MailMessage
.
Обновление для комментария:
Вы можете изменить отображение скопированных данных, а не всего, просто переместив индекс массива, на который мы ссылаемся:
$Log = Get-Content C:\temp\robocopy.txt
$Date = (($log -match "^\s+Ended.+") -split ":", 2)[1].Trim()
$Line = $Log -match "^\s+Bytes.+"
$Line = $Line -split "\s+"
$Line = "Bytes Copied: {0} {1} on {2}" -f $Line[5], $Line[4], $Date
$Line
ОДНАКО обратите внимание, что я все еще ссылаюсь на $Line[4]
. Это потому, что RoboCopy не добавляет символ множителя, такой как k, когда есть 0 байтов, поэтому мы могли бы также взять символ, который соответствует сумме. Тем не менее, если сумма также равна 0, это может сбросить индексы массива, мы, конечно, можем приспособить это к дальнейшей работе, но вам придется решить вероятность этого сценария.
Примечание. Я еще не изменил более ранние примеры. Когда QA будет решен, я постараюсь перефразировать, чтобы он был последовательным. Учитывая, что было несколько обновлений.
Обновление для комментария, запрашивающего экспорт Csv
Командлеты *-Csv преобразуют объекты в значения, разделенные запятыми (строки), используя свойства объекта в качестве заголовков столбцов и записывая их в файл. Таким образом, последующий пример, который предусматривает требование предыдущего тела электронной почты и экспорт Csv, может выглядеть примерно так:
$Logfile = "C:\PowerShell\robocopy.txt"
$CsvFile = "C:\PowerShell\RoboCsv.txt"
Clear-Content "C:\Powershell\robocopy.txt" -Force
$EmailFrom = "[email protected]"
$EmailTo = "[email protected]"
$EmailBody = [Collections.ArrayList]@("completed successfully. See attached log file & below summary","")
$EmailSubject = "Summary"
$CsvData = [Collections.ArrayList]@()
$files = @("SCRIPT")
for($i = 0; $i -lt $files.Count; $i++){
$Source = "C:\$($files[$i])"
$Dest = "C:\NEW TEST\folder\folder\$($files[$i])"
$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.+"
$Line = $Line -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.24.55
#Output to CSVFile
$CsvData | Export-Csv -Path $CsvFile -NoTypeInformation
Что добавлено, так это массив пользовательских объектов, использующих значения, которые мы вычислили ранее. Очевидно, были определены некоторые новые переменные, потому что нам нужно повторно использовать/ссылаться, чтобы сделать 2 вещи вместо 1.
Обратите внимание, если я делал это с нуля и лучше разбирался в требованиях. Я мог бы структурировать это по-другому. Несколько вещей, которые приходят на ум:
- Используйте другую конструкцию цикла. Не похоже, что традиционный цикл технически необходим, и код может быть более читабельным с одной из конструкций ForEach.
- Заполнять только массив объектов в цикле. Затем выполните постобработку массива, чтобы извлечь необходимые данные тела электронной почты, а также команду
Export-Csv
. Это также может позволить вам полностью избежать проблемы с увеличением массива и, следовательно, не беспокоиться о [Collections.ArrayList]
.
Кроме того:
- Вам не нужно указывать
-Port 25
по умолчанию.
- Вам не хватает последнего октета IP-адреса вашего SMTP-сервера, для которого я только что добавил 55, но вы захотите это исправить.
person
Steven
schedule
30.04.2021
493g
? - person Mathias R. Jessen   schedule 30.04.2021