Monthly Archives: June 2016

Get .NET version

Simple script to get the .net version

get-dotnet-version.ps1

param([Parameter(Mandatory=$true)][string[]] $ComputerName,
[switch] $Clobber)

##### START OF FUNCTIONS #####

function ql { $args }

function Quote-And-Comma-Join {

param([Parameter(Mandatory=$true)][string[]] $Strings)

# Replace all double quotes in the text with single quotes so the CSV isn’t messed up,
# and remove the trailing newline (all newlines and carriage returns).
$Strings = $Strings | ForEach-Object { $_ -replace ‘[\r\n]‘, ” }
($Strings | ForEach-Object { ‘”‘ + ($_ -replace ‘”‘, “‘”) + ‘”‘ }) -join ‘,’

}

##### END OF FUNCTIONS #####
## Author: Joakim Svendsen
## Copyright (C) 2011, Joakim Svendsen
## All rights reserved.
## BSD 3-clause license

# 2016-01-13: v1.2 – added support for .NET 4.6.1

Set-StrictMode -Version Latest
$ErrorActionPreference = ‘Stop’

$StartTime = Get-Date
“Script start time: $StartTime”

$Date = (Get-Date).ToString(‘yyyy-MM-dd’)
$OutputOnlineFile = “.\DotNetOnline-${date}.txt”
$OutputOfflineFile = “.\DotNetOffline-${date}.txt”
$CsvOutputFile = “.\DotNet-Versions-${date}.csv”

if (-not $Clobber) {

$FoundExistingLog = $false

foreach ($File in $OutputOnlineFile, $OutputOfflineFile, $CsvOutputFile) {

if (Test-Path -PathType Leaf -Path $File) {

$FoundExistingLog = $true
“$File already exists”

}

}

if ($FoundExistingLog -eq $true) {

$Answer = Read-Host “The above mentioned log file(s) exist. Overwrite? [yes]”

if ($Answer -imatch ‘^n’) { ‘Aborted’; exit 1 }

}

}

# Deleting existing log files if they exist (assume they can be deleted…)
Remove-Item $OutputOnlineFile -ErrorAction SilentlyContinue
Remove-Item $OutputOfflineFile -ErrorAction SilentlyContinue
Remove-Item $CsvOutputFile -ErrorAction SilentlyContinue

$Counter = 0
$DotNetData = @{}
$DotNetVersionStrings = ql v4\Client v4\Full v3.5 v3.0 v2.0.50727 v1.1.4322
$DotNetRegistryBase = ‘SOFTWARE\Microsoft\NET Framework Setup\NDP’

foreach ($Computer in $ComputerName) {

$Counter++
$DotNetData.$Computer = New-Object PSObject

# Skip malformed lines (well, some of them)
if ($Computer -notmatch ‘^\S’) {

Write-Host -Fore Red “Skipping malformed item/line ${Counter}: ‘$Computer’”
Add-Member -Name Error -Value “Malformed argument ${Counter}: ‘$Computer’” -MemberType NoteProperty -InputObject $DotNetData.$Computer
continue

}

if (Test-Connection -Quiet -Count 1 $Computer) {

Write-Host -Fore Green “$Computer is online. Trying to read registry.”

$Computer | Add-Content $OutputOnlineFile

# Suppress errors when trying to open the remote key
$ErrorActionPreference = ‘SilentlyContinue’
$Registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘LocalMachine’, $Computer)
$RegSuccess = $?
$ErrorActionPreference = ‘Stop’

if ($RegSuccess) {

Write-Host -Fore Green “Successfully connected to registry of ${Computer}. Trying to open keys.”

foreach ($VerString in $DotNetVersionStrings) {

if ($RegKey = $Registry.OpenSubKey(“$DotNetRegistryBase\$VerString”)) {

#”Successfully opened .NET registry key (SOFTWARE\Microsoft\NET Framework Setup\NDP\$verString).”

if ($RegKey.GetValue(‘Install’) -eq ’1′) {

#”$computer has .NET $verString”
Add-Member -Name $VerString -Value ‘Installed’ -MemberType NoteProperty -InputObject $DotNetData.$Computer

}

else {

Add-Member -Name $VerString -Value ‘Not installed’ -MemberType NoteProperty -InputObject $DotNetData.$Computer

}

}

else {

Add-Member -Name $VerString -Value ‘Not installed (no key)’ -MemberType NoteProperty -InputObject $DotNetData.$Computer

}

}
# Tacking on 4.5.x and 4.6 detection, as someone requested… this script really needs a rewrite to be
# more standards-conforming, but I’m mentally exhausted.
# 2016-01-13: Adding 4.6.1
$RegKey = $Null
if ($RegKey = $Registry.OpenSubKey(“SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full”))
{
if ($DotNet4xRelease = [int] $RegKey.GetValue(‘Release’))
{
if ($DotNet4xRelease -ge 394254)
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ’4.6.1 or later’
}
elseif ($DotNet4xRelease -ge 393295)
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ’4.6 or later’
}
elseif ($DotNet4xRelease -ge 379893)
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ’4.5.2 or later’
}
elseif ($DotNet4xRelease -ge 378675)
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ’4.5.1 or later’
}
elseif ($DotNet4xRelease -ge 378389)
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ’4.5 or later’
}
else
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ‘Universe imploded’
}
}
else
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value “Error (no key?)”
}
}
else
{
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ‘Not installed (no key)’
}

}

# Error opening remote registry
else {

Write-Host -Fore Yellow “${Computer}: Unable to open remote registry key.”
Add-Member -Name Error -Value “Unable to open remote registry: $($Error[0].ToString())” -MemberType NoteProperty -InputObject $DotNetData.$Computer
$DotNetData.$Computer | Add-Member -MemberType NoteProperty -Name ‘>=4.x’ -Value ‘Unknown’
}

}

# Failed ping test
else {

Write-Host -Fore Yellow “${Computer} is offline.”
Add-Member -Name Error -Value “No ping reply” -MemberType NoteProperty -InputObject $DotNetData.$Computer
$Computer | Add-Content $OutputOfflineFile

}

}

$CsvHeaders = @(‘Computer’, ‘>=4.x’) + @($DotNetVersionStrings) + @(‘Error’)
$HeaderLine = Quote-And-Comma-Join $CsvHeaders
Add-Content -Path $CsvOutputFile -Value $HeaderLine

# Process the data and output to manually crafted CSV.
foreach ($Computer in $DotNetData.Keys | Sort-Object) { #| ForEach-Object {

#$Computer = $_.Name

# I’m building a temporary hashtable with all $CsvHeaders
$TempData = @{}
$TempData.’Computer’ = $Computer
#Write-Verbose ‘Before’
#Write-Verbose ‘After’
# This means there’s an “Error” note property.
if (Get-Member -InputObject $DotNetData.$Computer -MemberType NoteProperty -Name Error) {

# Add the error to the temp hash.
$TempData.’Error’ = $DotNetData.$Computer.Error

# Populate the .NET version strings with “Unknown”.
foreach ($VerString in $DotNetVersionStrings) {

$TempData.$VerString = ‘Unknown’

}
$TempData.’>=4.x’ = ‘Unknown’

}

# No errors. Assume all .NET version fields are populated.
else {

# Set the error key in the temp hash to “-”
$TempData.’Error’ = ‘-’

foreach ($VerString in $DotNetVersionStrings) {

$TempData.$VerString = $DotNetData.$Computer.$VerString

}
$TempData.’>=4.x’ = $DotNetData.$Computer.’>=4.x’

}
# Now we should have “complete” $TempData hashes.
# Manually craft CSV data. Headers were added before the loop.

# The array is for ordering the output predictably.
$TempArray = @()

foreach ($Header in $CsvHeaders) {

$TempArray += $TempData.$Header

}

$CsvLine = Quote-And-Comma-Join $TempArray
Add-Content -Path $CsvOutputFile -Value $CsvLine

}

@”
Script start time: $StartTime
Script end time: $(Get-Date)
Output files: $CsvOutputFile, $OutputOnlineFile, $OutputOfflineFile
“@

 

Windows scp via ftp with ssl with email confirmation

copy files and send a report following it.

Paylease.bat

“C:\Program Files (x86)\WinSCP\WinSCP.com” “/script=c:\scripts\site1_WinSCPscript.txt” /log=”D:\Apps\hms\deploy\site1.log”

move D:\Apps\hms\deploy\site1\* D:\Apps\hms\deploy\site1.Archive\

if %ERRORLEVEL% neq 0 goto errorpowershell -command “c:\scripts\mailer_success.ps1″exit /b 0:errorpowershell -command “c:\scripts\mailer_failure.ps1″exit /b 1

The mailer successful powershell command

mailer_success.ps1

$EmailFrom = “user1@ftp.site1.com”
$EmailTo = “notify@consco.net,user2@consco.org”
$Subject = “site1 FTPs transfer success”
$Body = “The FTPs transfer appears to have finished properly, for details please check the log file on site1-server.”
$SMTPServer = “192.168.0.12″
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25)
$SMTPClient.EnableSsl = $false
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)

Mailer_failure.ps1

$EmailFrom = “user1@ftp.site1.com”
$EmailTo = “custalarm@consco.net,user2@consco.org”
$Subject = “site1 FTPs transfer failed”
$Body = “The FTPs transfer appears to have failed, for details on the failure please check the log file on site1-server.”
$SMTPServer = “192.168.0.12″
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 25)
$SMTPClient.EnableSsl = $false
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)

Now to the winscp script

option batch on
option confirm off
open -explicitssl -passive ftp://username:password@ftp.site1.com
option transfer binary
put D:\Apps\hms\deploy\site1\*
close
exit

Backup and analyze

Basic backup of a drive then analyze the backup status. Then allow it to send me an email to make sure that everything is working properly.

analyze.bat

net use \\192.168.16.41\Backups (password) /user:BackupSync
powershell -Command “c:\scripts\AnalyzeRobocopyLogs.ps1 -Path ‘\\192.168.16.41\Backups\’ -MailRecipient ‘itadmin@consco.com’ -MailServer 192.168.16.3 -Summary SummaryAllWithoutWarnings -MailPolicy Always”
net use /delete

Then the powershell command to make some things work.

# ***************************************************************************************
# ***
# *** Scriptname: AnalyzeRobocopyLogs.ps1
# ***
# *** Usage: Get-Help .\AnalyzeRobocopyLogs.ps1
# ***
# *** Author: Powershell Administrator a.k.a. OcinO a.k.a. Nico Buma
# ***
# *** Version: 2.1
# ***
# *** History: 05-06-14 Fixed a Powershell v2 issue, where no error and warning lines were added to the summary
# *** 03-05-14 Totally rewrote script to increase performance and make it more diverse (2.0)
# *** – Changed: Added more input parameters and switches to make the script more universal
# *** – Added MaxLinesPerFile parameter, to increase speed even more and reduce memory usage
# *** – New: Error-handling instead of just breaking out of the script
# *** – New: changed complete reading of files to select-string
# *** – Script speed increased over 500% and CPU usage decreased to a minimum
# *** 30.04.14 Rewrote VBS Script in Powershell (1.0)
# *** 21.10.08 Created script in VBS (1.0)
# ***
# *** 2014 – Powershell Administrator. Use at your own risk.
# ***
# *** Speed measuring data:
# *** Reading of 110 files (95,8MB), which consist of 7 errors in 4 files and 402924 warnings in 4 files;
# *** 2m8s
# *** Tested with option SummaryAll (maximum output) and a MaxLinesPerFile of 500
# ***
# *** Same conditions as above, but tested with SummaryAllWithoutWarnings
# *** 20s
# ***
# ***************************************************************************************

<#
.SYNOPSIS
Analyze Robocopy logs and mail the result in a summary file

.DESCRIPTION
This Powershell script will analyze a directory (can be recursive) that contains Robocopy log files.
It will generate one output file with a summary for each log file, in the same folder as the script.
All logs that contain errors will be placed in top of this summary. All error information is included.
Once the summary is created an e-mail is sent to the specified e-mail address(es), with the summary file attached.

.PARAMETER Path
This option is mandatory. Specifies the path to the Robocopy log files.

.PARAMETER Recurse
Set this switch to include subfolders.

.PARAMETER MailSender
Specifies the from e-mail address. The default value is Norepl@Noreply.com

.PARAMETER MailRecipient
This option is mandatory. Specifies the recipient of the e-mail message.
If multiple recipients need to be specified, use a semicolon ( ; ) as a seperator.

.PARAMETER MailServer
This option is mandatory. Specifies the name of the SMTP server.

.PARAMETER MailSubject
Specifies the non-dynamic text part of the subject name for the e-mail message. The default text is “Analyze Robocopy Backup Logs”

.PARAMETER MailPort
Specifies the port to use for the e-mail message. The default value is 25. This option is ignored with Powershell v2.0

.PARAMETER UseSsl
Set this switch to use SSL for e-mail communication.

.PARAMETER Summary
Use one of the following parameters:
SummaryAll = creates a summary file of all Robocopy logs, includes detailed warning and error information
in the report
SummaryAllWithoutWarnings = creates a summary file of all Robocopy logs, includes detailed error information
in the report
ErrorsAndWarnings = creates a summary file of all Robocopy logs that contain errors and warnings,
includes detailed warning and errorinformation. If no warnings and/or errors are found, the summary
will only contain the start time and end time of the script.
ErrorsOnly = creates a summary file of all Robocopy logs that contain errors, includes detailed
error information in the report. If no errors are found, the summary will only contain the start time
and end time of the script.
(When AnalyzeRobocopyLogs encounters a ‘same’ file in a Robocopy log file, It will mark this as a warning)
The default option is SummaryAll

.PARAMETER MailPolicy
Use one of the following parameters:
Always = Always send an e-mail report with the summary file attached
ErrorsAndWarnings = Only send an e-mail report if the summary file contains Errors and/or Warnings
ErrorsOnly = Only send an e-mail report if the summary file contains Errors
(When AnalyzeRobocopyLogs encounters a ‘same’ file in a Robocopy log file, It will mark this as a warning)
The default option is Always

.PARAMETER MaxAmountOfSummaryLines
Use this parameter to set the maximum amount of detailed summary lines to include in the summary repory. The default value is 500.

.INPUTS
None. You cannot pipe objects.

.OUTPUTS
None. No object outputs.

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com;Suzie@q.com” -MailServer mail.server.com
This will analyze the “C:\Windows\Logs” folder for all Robocopy backup logs and sends the result by e-mail to
to John@doe.com and Suzie@q.com by e-mail.
It will use the default summary, mail policy, subject and mail port options.
In this example, it will NOT use SSL or recurively check the path for logs.

C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -Recurse -MailRecipient “John@doe.com” -MailServer mail.server.com
This will analyze the “C:\Windows\Logs” folder and subfolders for all Robocopy backup logs and sends the result
by e-mail to John@doe.com.

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -Recurse -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary SummaryAll -MailPolicy ErrorsOnly
This will analyze the “C:\Windows\Logs” folder (and subfolders) and check for all Errors and Warnings
and creates a summary file of EACH log file, including a more detailed information for each error and/or
warning, and will mail if Errors are found.
(so warnings are ignored when checking if the summary has to be mailed)

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary SummaryAllWithoutWarnings -MailPolicy Always
This will analyze the “C:\Windows\Logs” folder and check for all Errors and creates a summary file of
each log file and ignores warnings. It will always send a mail report.

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary SummaryAllWithoutWarnings -MailPolicy ErrorsAndWarnings
This will analyze the “C:\Windows\Logs” folder and check for all Errors and creates a summary file of
each log file and ignores warnings. It will send a mail report only if Errors are found.
(if you disable warnings in -summary the ErrorsAndWarnings mailpolicy will automatically change its
behavior to ErrorsOnly)

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary SummaryAllWithoutWarnings -MailPolicy ErrorsOnly
This will analyze the “C:\Windows\Logs” folder and check for all Errors and creates a summary file of
each log file and ignores warnings. It will send a mail report only if Errors are found.

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary ErrorsAndWarnings -MailPolicy ErrorsOnly
This will analyze the “C:\Windows\Logs” folder and check for all Errors and creates a detailed summary
file of each log file that contains Errors and/or Warnings (skips the non-error and/or non-warning files).
It will send a mail report only if Errors are found.

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary ErrorsOnly -MailPolicy Always
This will analyze the “C:\Windows\Logs” folder and check for all Errors and creates a detailed summary
file of each log file that contains Errors (skips the non-error files).
It will always send a mail report.

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -MailRecipient “John@doe.com” -MailServer mail.server.com -Summary ErrorsOnly -MailPolicy ErrorsAndWarnings
This will analyze the “C:\Windows\Logs” folder and check for all Errors and creates a detailed summary
file of each log file that contains Errors (skips the non-error files).
It will send a mail report only if Errors are found.
(if you disable warnings in -summary the ErrorsAndWarnings mailpolicy will automatically change its behavior to ErrorsOnly)

.EXAMPLE
C:\PS> .\AnalyzeRobocopyLogs.ps1 -Path “C:\Windows\Logs” -Recurse -Mailsender “NoReply@mydomain.com” -MailRecipient “John@doe.com” -MailServer “mail.server.com” -MailSubject “PowershellAdministrator – Removing the human error step by step” -MailPort 465 -UseSsl -Summary ErrorsOnly -MailPolicy ErrorsOnly -MaxAmountOfSummaryLines 1000
This will recursively analyze the “C:\Windows\Logs” folder and check for all Errors and creates a detailed
summary file of each log file that contains Errors (skips the non-error files) and will use a maximum of
1000 lines of detailed information.
It will send a mail report if Errors are found ans use NoReply@mydomain.com as from address
It will use SSL when sending mail and uses port 465 (the default SSL SMTP port) in this example.
It will also use “PowershellAdministrator – Removing the human error step by step” as non-dynamic part
of the e-mail subject string.

.LINK

http://powershelladministrator.wordpress.com/2014/05/03/analyze-robocopy-log-files-and-mail-the-result/

http://PowershellAdministrator.wordpress.com

#>

Param(
[Parameter(Mandatory=$true)][string]$Path,
[switch]$Recurse,
[string]$MailSender = “Noreply@Noreply.com”,
[Parameter(Mandatory=$true)][string]$MailRecipient,
[Parameter(Mandatory=$true)][string]$MailServer,
[string]$MailSubject = “Analyze Robocopy Backup Logs”,
[int]$MailPort = 25,
[switch]$UseSsl,
[ValidateSet("SummaryAll","SummaryAllWithoutWarnings","ErrorsAndWarnings", "ErrorsOnly")][String[]]$Summary = “SummaryAll”,
[ValidateSet("Always", "ErrorsAndWarnings", "ErrorsOnly")][String[]]$MailPolicy = “Always”,
[int]$MaxAmountOfSummaryLines = 500
)

#Requires –Version 2.0

#Get start time
$StartTime = (Get-Date).ToString()

#Setting default variables
If($PSVersionTable.PSVersion.Major -eq 2) { $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent }
$LogFile = “$PSScriptRoot\AnalyzeRobocopyLogs.log”

#Summary variables
$SummaryAll = $false
$SummaryAllWithoutWarnings = $false
$ErrorsAndWarnings = $false
$ErrorsOnly = $false

#MailPolicy variables
$MailAlways = $false
$MailErrorsAndWarnings = $false
$MailErrorsOnly = $false

Switch($Summary)
{
“SummaryAll” { $SummaryAll = $true }
“SummaryAllWithoutWarnings” { $SummaryAllWithoutWarnings = $true }
“ErrorsAndWarnings” { $ErrorsAndWarnings = $true }
“ErrorsOnly” { $ErrorsOnly = $true }
Default { Write-Error -Message “You entered something other than one of the 4 possible options” -Category ParserError -RecommendedAction “Use one of the 4 options as provided by the script.” -CategoryReason “Incorrect option for Summary” -ErrorAction Stop -ErrorVariable $Summary }
}

Switch($MailPolicy)
{
“Always” { $MailAlways = $true }
“ErrorsAndWarnings” { $MailErrorsAndWarnings = $true }
“ErrorsOnly” { $MailErrorsOnly = $true }
Default { Write-Error -Message “You entered something other than one of the 3 possible options” -Category ParserError -RecommendedAction “Use one of the 3 options as provided by the script.” -CategoryReason “Incorrect option for MailPolicy” -ErrorAction Stop -ErrorVariable $MailPolicy }
}

#Check if the given mail addresses are in the correct mail address format (contains text before and after the [at]. After the [at] and the text, it expects a [dot] with a 2 to 4 letter TLD after that)
$Regex = “^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$”
$MailAddresses = @()
If($MailRecipient.Contains(“;”)) { $MailAddresses = $MailRecipient.Split(“;”) }
Else { $MailAddresses = $MailRecipient }
Foreach($MailAddress in $MailAddresses)
{
If($MailAddress -notmatch $Regex) { Write-Error -Message “Incorrect recipient e-mail address entered. Please verify that $MailAddress has been entered correctly” -Category ParserError -RecommendedAction “Correct the e-mail address or use the -MailRecipient switch to specify one.” -CategoryReason “Incorrect E-mail address” -ErrorAction Stop -ErrorVariable $MailAddress }
}

# Retrieve list of files from a folder
#*************************************************
If(Test-Path($Path))
{
#Get a list of all files if the path exists
$FileList = Get-ChildItem -Path $Path -Recurse:($Recurse.IsPresent)

$ErrorMessages = $FileList | Select-String -Pattern ‘(ERROR: )|( ERROR )’ -CaseSensitive
If($SummaryAll -or $ErrorsAndWarnings) { $WarningMessages = $FileList | Select-String -SimpleMatch ” same” -CaseSensitive }
#Get all lines which robocopy uses for its summary text
$LineNumbers = $FileList | Select-String -SimpleMatch “——————————————————————————”

$ErrorFiles = “”
$WarningFiles = “”
$SummaryText = “”
$Newline = “`r`n”
$StrTextDivider = “”
#71 is the size of the maximum width of the robocopy text line
For($i = 0; $i -lt 71; $i++) { $StrTextDivider += “-” }
$FileWithErrors = $false

If($PSVersionTable.PSVersion.Major -eq 2)
{
$TempErrorFiles = @()
Foreach($ErrorMessage in $ErrorMessages)
{
$TempErrorFiles += $ErrorMessage.Path
}
$ErrorFiles = $TempErrorFiles | Select-Object -Unique
}
Else
{
$ErrorFiles = $ErrorMessages.Path | Select-Object -Unique
}
If($SummaryAll -or $ErrorsAndWarnings)
{
If($PSVersionTable.PSVersion.Major -eq 2)
{
$TempWarningFiles = @()
Foreach($WarningMessage in $WarningMessages)
{
$TempWarningFiles += $WarningMessage.Path
}
$WarningFiles = $TempWarningFiles | Select-Object -Unique
}
Else
{
$WarningFiles = $WarningMessages.Path | Select-Object -Unique
}
}

If($ErrorsAndWarnings -or $ErrorsOnly)
{
#If only Errors and/or Warnings are enabled, reduce the filelist to only include these files
$ListOfFiles = $ErrorFiles
If($ErrorsAndWarnings)
{
$ListOfFiles += $WarningFiles
$ListOfFiles = $ListOfFiles | Select-Object -Unique
}
$FileList = Get-ChildItem -Path $ListOfFiles
}

Foreach($File in $FileList)
{
$BottomText = “”
$FileLineNumbers = $LineNumbers | Where-Object { $_.Path -eq $File.FullName }

If($FileLineNumbers)
{
#Add all Robocopy summary text to the summary file
$BeginStartLine = $FileLineNumbers[1].LineNumber
$BeginEndLine = $FileLineNumbers[2].LineNumber – 3
$EndStartLine = $FileLineNumbers[3].LineNumber
$EndEndLine = $FileLineNumbers[3].LineNumber + 20
$FileLinesToRead = $BeginStartLine..$BeginEndLine + $EndStartLine..$EndEndLine

#Check if the file is in the list which contains the errors
#*************************************************
$IsError = $ErrorFiles | Select-String -SimpleMatch $File.FullName
If($IsError)
{
$ErrorLines = $ErrorMessages | Where-Object { $_.Path -eq $File.FullName }
[int[]]$ErrorLineNumbers = $ErrorLines | foreach { ($_.LineNumber)-2; ($_.LineNumber)-1 }
$ErrorLineNumbers = $ErrorLineNumbers | Sort-Object -Unique
If($ErrorLineNumbers.Count -gt $MaxAmountOfSummaryLines) { $ErrorLineNumbers = $ErrorLineNumbers[0..$MaxAmountOfSummaryLines] }
$FileLinesToRead = $FileLinesToRead + $ErrorLineNumbers
$FileWithErrors = $true
}
#Check if the file is in the list which contains the warnings (if SummaryAll is selected and no errors were found)
#*************************************************
$IsWarning = $WarningFiles | Select-String -SimpleMatch $File.FullName
If($IsWarning -and ($SummaryAll -or $ErrorsAndWarnings))
{
$WarningLines = $WarningMessages | Where-Object { $_.Path -eq $File.FullName }
[int[]]$WarningLineNumbers = $WarningLines | foreach { ($_.LineNumber)-2 }
$WarningLineNumbers = $WarningLineNumbers | Sort-Object -Unique
If($WarningLineNumbers.Count -gt $MaxAmountOfSummaryLines) { $WarningLineNumbers = $WarningLineNumbers[0..$MaxAmountOfSummaryLines] }
$FileLinesToRead = $FileLinesToRead + $WarningLineNumbers
}
If($FileWithErrors -and ($SummaryAll -or $SummaryAllWithoutWarnings))
{
$BottomText += $SummaryText
$SummaryText = “”
}
$SummaryText += $StrTextDivider + $Newline
$SummaryText += “`t`t`t” + $File.Name + $Newline
$SummaryText += $StrTextDivider + $Newline

$TextInFile = [io.file]::ReadAllLines($File.FullName)

#Create a list with unique file line numbers
$UniqueFileLinesToRead = $FileLinesToRead | Sort-Object -Unique

Foreach($Line in $UniqueFileLinesToRead)
{
If($Line -lt $TextInFile.Count -1) { $SummaryText += $TextInFile[$Line + 1] + $Newline }
}
If($FileWithErrors -and ($SummaryAll -or $SummaryAllWithoutWarnings))
{
$SummaryText += $BottomText
$FileWithErrors = $false
}
}
}

#Get end time after reading all info and saving the start and end time of the analyzer to the log file
$EndTime = (Get-Date).ToString()
$SummaryEndLogText = “AnalyzeRobocopyLogs completed succesfully”
$StrTextDivider = “”
For($i = 0; $i -lt $SummaryEndLogText.Length; $i++) { $StrTextDivider += “-” }
$SummaryText += $StrTextDivider + $Newline
$SummaryText += $SummaryEndLogText
#Save the analyzed summary to the logfile
[io.file]::WriteAllText($LogFile,$StartTime + $Newline + $SummaryText + $Newline + $EndTime)

#Get amount of errors
[int]$AmountOfErrors = $ErrorMessages.Count
[int]$AmountOfErrorFiles = $ErrorFiles.Count
#If enabled; get amount of warnings
If($SummaryAll -or $ErrorsAndWarnings)
{
[int]$AmountOfWarnings = $WarningMessages.Count
[int]$AmountOfWarningFiles = $WarningFiles.Count
}

#Defining the conclusion text and creating the summary text based on analyzing the logs
#*************************************************
If($AmountOfErrors -eq 0)
{
#Check if warning reporting is enabled
$BgColor = “bgcolor=”"lime”"”
If($SummaryAll -or $ErrorsAndWarnings)
{
#Create subject with warnings enabled and based on findings
If($AmountOfWarnings -eq 0) { $SummaryConclusion = “JOB SUCCESS: $MailSubject Completed Successfully; $AmountOfErrors errors and $AmountOfWarnings warnings” }
Else
{
$BgColor = “bgcolor=”"yellow”"”
$SummaryConclusion = “JOB SUCCESS, BUT WITH WARNINGS: $MailSubject Completed with Warnings; $AmountOfErrors errors and $AmountOfWarnings warnings”
}
}
#Create subject without warnings enabled
Else { $SummaryConclusion = “JOB SUCCESS: $MailSubject Completed Successfully; $AmountOfErrors errors” }
}
#The job failed; errors have been found
Else
{
$BgColor = “bgcolor=”"red”"”
#Check if warning reporting is enabled
If($SummaryAll -or $ErrorsAndWarnings) { $SummaryConclusion = “JOB FAILED: $MailSubject Failed; $AmountOfErrors errors and $AmountOfWarnings warnings” }
#Create subject without warnings enabled
Else { $SummaryConclusion = “JOB FAILED: $MailSubject Failed; $AmountOfErrors errors” }
}

$SummaryText = “<TABLE border=”"2″” $BgColor><TR><TD align=”"center”" colspan=”"4″”><B><FONT size=”"+2″”>Results</FONT></B></TD></TR>” + $Newline
$SummaryText += “<TR><TD align=”"center”"> </TD>”
$SummaryText += “<TD>No.</TD>”
$SummaryText += “<TD>in .. Log File(s)</TD></TR>” + $Newline
If($AmountOfErrors -eq 0) { $BgColor = “bgcolor=”"lime”"” }
Else { $BgColor = “bgcolor=”"red”"” }
$SummaryText += “<TR><TD align=”"center”" $BgColor><B>Errors:</B></TD>”
$SummaryText += “<TD align=”"center”" $BgColor><B>$AmountOfErrors</B></TD>”
$SummaryText += “<TD align=”"center”" $BgColor>$AmountOfErrorFiles</TD></TR>” + $Newline

If($SummaryAll -or $ErrorsAndWarnings)
{
If($AmountOfWarnings -eq 0) { $BgColor = “bgcolor=”"lime”"” }
Else { $BgColor = “bgcolor=”"yellow”"” }
$SummaryText += “<TR><TD align=”"center”" $BgColor><B>Warnings:</B></TD>”
$SummaryText += “<TD align=”"center”" $BgColor><B>$AmountOfWarnings</B></TD>”
$SummaryText += “<TD align=”"center”" $BgColor>$AmountOfWarningFiles</TD></TR>” + $Newline
}

Function Send-Mail
{
If($PSVersionTable.PSVersion.Major -eq 2) { Send-MailMessage -From $MailSender -To $MailAddresses -Subject $SummaryConclusion -BodyAsHtml $SummaryText -Attachments $LogFile -SmtpServer $MailServer -UseSsl:$UseSsl.IsPresent }
Else { Send-MailMessage -From $MailSender -To $MailAddresses -Subject $SummaryConclusion -BodyAsHtml $SummaryText -Attachments $LogFile -SmtpServer $MailServer -Port $MailPort -UseSsl:$UseSsl.IsPresent }
}
#Send Analyze Summary Mail message if enabled by settings
If($MailAlways -or $MailErrorsAndWarnings -or -$MailErrorsOnly)
{
If($MailAlways)
{
Send-Mail
}
If($MailErrorsAndWarnings)
{
#If errors or warnings have been found, send message
If(($ErrorsAndWarnings -or $SummaryAll) -and (($AmountOfErrors -gt 0) -or ($AmountOfWarnings -gt 0)))
{
Send-Mail
}
#If errors have been found, send message
ElseIf(($ErrorsOnly -or $SummaryAllWithoutWarnings) -and ($AmountOfErrors -gt 0))
{
Send-Mail
}
}
If($MailErrorsOnly)
{
#If errors have been found, send message
If($AmountOfErrors -gt 0)
{
Send-Mail
}
}
}
}
Else { Write-Error -Message “The folder does not exist. Please verify that $Path really exists and you have sufficient permissions” -Category ObjectNotFound -RecommendedAction “Check if the folder name is correct and if you have sufficient permissions to access the folder.” -CategoryReason “Folder not found” -ErrorAction Stop }

Then the copy script to copy the files to a synology

net use \\192.168.16.41\Backups (password) /user:BackupSync
robocopy c:\ \\192.168.16.41\backups\Server1\c\ /E /Z /W:2 /R:2 /MIR /XJD /LOG:\\192.168.16.3\d$\Backup\Server1-c.log
net use /delete