That Script was published in 2014, with minimal skills related to Powershell. You, the Community, loved it through.
Via Github, Mail, Facebook, and Twitter, I received a lot of feedback and Bug Reports 🙂
So today, I published a complete new Release, 2.0! With a lot of fixed Bugs, nearly all Functions the old one had and, in my opinion, better Code.
And of course, with a lot of help from the Community.
The Script
########################################################
# Name: BackupScript_v2.ps1
# Creator: Michael Seidl aka Techguy
# CreationDate: 05.08.2021
# LastModified: 05.08.2021
# Version: 2.0
# Doc: https://www.techguy.at/tag/backupscript/
# GitHub: https://github.com/Seidlm/PowerShell-Backup-Script
# PSVersion tested: 5
#
# PowerShell Self Service Web Portal at www.au2mator.com/PowerShell
#
#
# Description: Copies the Bakupdirs to the Destination
# You can configure more than one Backupdirs, every Dir
# wil be copied to the Destination.
# Only Change Variables in Variables Section
# Change LoggingLevel to 3 an get more output in Powershell Windows
#
#
########################################################
#
# www.techguy.at
# www.facebook.com/TechguyAT
# www.twitter.com/TechguyAT
# michael@techguy.at
#
#
########################################################
#Variables, only Change here
$Destination = "C:\temp\_Backup" #Copy the Files to this Location
$Versions = "3" #How many of the last Backups you want to keep
$Backupdirs = "C:\Users\seimi\Documents", "C:\Program Files (x86)\Common Files" #What Folders you want to backup
$ExcludeDirs = ($env:SystemDrive + "\Users\.*\AppData\Local"), "C:\Program Files (x86)\Common Files\Adobe" #This list of Directories will not be copied
$logPath = "C:\temp\_Backup"
$LogfileName = "Log" #Log Name
$LoggingLevel = "3" #LoggingLevel only for Output in Powershell Window, 1=smart, 3=Heavy
$Zip = $true #Zip the Backup Destination
$Use7ZIP = $true #7ZIP Module will be installed https://www.powershellgallery.com/packages/7Zip4Powershell/2.0.0
$UseStaging = $true #only if you use ZIP, than we copy file to Staging, zip it and copy the ZIP to destination, like Staging, and to save NetworkBandwith
$StagingPath = "C:\temp\_Staging"
$RemoveBackupDestination = $true #Remove copied files after Zip, only if $Zip is true
#region Functions
function Write-au2matorLog {
[CmdletBinding()]
param
(
[ValidateSet('DEBUG', 'INFO', 'WARNING', 'ERROR')]
[string]$Type,
[string]$Text
)
# Set logging path
if (!(Test-Path -Path $logPath)) {
try {
$null = New-Item -Path $logPath -ItemType Directory
Write-Verbose ("Path: ""{0}"" was created." -f $logPath)
}
catch {
Write-Verbose ("Path: ""{0}"" couldn't be created." -f $logPath)
}
}
else {
Write-Verbose ("Path: ""{0}"" already exists." -f $logPath)
}
[string]$logFile = '{0}\{1}_{2}.log' -f $logPath, $(Get-Date -Format 'yyyyMMdd'), $LogfileName
$logEntry = '{0}: <{1}> <{2}> {3}' -f $(Get-Date -Format dd.MM.yyyy-HH:mm:ss), $Type, $PID, $Text
try { Add-Content -Path $logFile -Value $logEntry }
catch {
Start-sleep -Milliseconds 50
Add-Content -Path $logFile -Value $logEntry
}
if ($LoggingLevel -eq "3") { Write-Host $Text }
}
#endregion Functions
#System Variables, do not change
$PreCheck = $true
$BackUpCheck = $false
$FinalBackupdirs = @()
#SCRIPT
##PRE CHECK
Write-au2matorLog -Type Info -Text "Start the Script"
Write-au2matorLog -Type Info -Text "Create Backup Dirs and Check all Folders an Path if they exist"
try {
#Create Backup Dir
$BackupDestination = $Destination + "\Backup-" + (Get-Date -format yyyy-MM-dd) + "-" + (Get-Random -Maximum 100000) + "\"
New-Item -Path $BackupDestination -ItemType Directory | Out-Null
Start-sleep -Seconds 5
Write-au2matorLog -Type Info -Text "Create Backupdir $BackupDestination"
try {
#Ceck all Directories
Write-au2matorLog -Type Info -Text "Check if BackupDirs exist"
foreach ($Dir in $Backupdirs) {
if ((Test-Path $Dir)) {
Write-au2matorLog -Type INFO -Text "$Dir is fine"
$FinalBackupdirs += $Dir
}
else {
Write-au2matorLog -Type WARNING -Text "$Dir does not exist and was removed from Backup"
}
}
try {
if ($UseStaging) {
if ((Test-Path $StagingPath)) {
Write-au2matorLog -Type INFO -Text "$StagingPath is fine"
}
else {
Write-au2matorLog -Type ERROR -Text "$StagingPath does not exist"
Write-au2matorLog -Type ERROR -Text $Error
$PreCheck = $false
}
}
}
catch {
Write-au2matorLog -Type ERROR -Text "Failed to Check Staging Dir $StagingPath"
Write-au2matorLog -Type ERROR -Text $Error
$PreCheck = $false
}
}
catch {
Write-au2matorLog -Type ERROR -Text "Failed to Check Backupdir $BackupDestination"
Write-au2matorLog -Type ERROR -Text $Error
$PreCheck = $false
}
}
catch {
Write-au2matorLog -Type ERROR -Text "Failed to Create Backupdir $BackupDestination"
Write-au2matorLog -Type ERROR -Text $Error
$PreCheck = $false
}
## BACKUP
if ($PreCheck) {
Write-au2matorLog -Type INFO -Text "PreCheck was good, so start with Backup"
try {
Write-au2matorLog -Type INFO -Text "Calculate Size and check Files"
$BackupDirFiles = @{ } #Hash of BackupDir & Files
$Files = @()
$SumMB = 0
$SumItems = 0
$SumCount = 0
$colItems = 0
$ExcludeString = ""
foreach ($Entry in $ExcludeDirs) {
#Exclude the directory itself
$Temp = "^" + $Entry.Replace("\", "\\").Replace("(", "\(").Replace(")", "\)") + "$"
#$Temp = $Entry
$ExcludeString += $Temp + "|"
#Exclude the directory's children
$Temp = "^" + $Entry.Replace("\", "\\").Replace("(", "\(").Replace(")", "\)") + "\\.*"
#$Temp = $Entry
$ExcludeString += $Temp + "|"
}
$ExcludeString = $ExcludeString.Substring(0, $ExcludeString.Length - 1)
[RegEx]$exclude = $ExcludeString
foreach ($Backup in $FinalBackupdirs) {
$Files = Get-ChildItem -LiteralPath $Backup -recurse -Attributes D+!ReparsePoint, D+H+!ReparsePoint -ErrorVariable +errItems -ErrorAction SilentlyContinue |
ForEach-Object -Process { Add-Member -InputObject $_ -NotePropertyName "ParentFullName" -NotePropertyValue ($_.FullName.Substring(0, $_.FullName.LastIndexOf("\" + $_.Name))) -PassThru -ErrorAction SilentlyContinue } |
Where-Object { $_.FullName -notmatch $exclude -and $_.ParentFullName -notmatch $exclude } |
Get-ChildItem -Attributes !D -ErrorVariable +errItems -ErrorAction SilentlyContinue | Where-Object { $_.DirectoryName -notmatch $exclude }
$BackupDirFiles.Add($Backup, $Files)
$colItems = ($Files | Measure-Object -property length -sum)
$Items = 0
$SumMB += $colItems.Sum.ToString()
$SumItems += $colItems.Count
}
$TotalMB = "{0:N2}" -f ($SumMB / 1MB) + " MB of Files"
Write-au2matorLog -Type INFO -Text "There are $SumItems Files with $TotalMB to copy"
#Log any errors from above from building the list of files to backup.
[System.Management.Automation.ErrorRecord]$errItem = $null
foreach ($errItem in $errItems) {
Write-au2matorLog -Type WARNING -Text ("Skipping `"" + $errItem.TargetObject + "`" Error: " + $errItem.CategoryInfo)
}
Remove-Variable errItem
Remove-Variable errItems
try {
Write-au2matorLog -Type INFO -Text "Run Backup"
foreach ($Backup in $FinalBackupdirs) {
$Index = $Backup.LastIndexOf("\")
$SplitBackup = $Backup.substring(0, $Index)
$Files = $BackupDirFiles[$Backup]
foreach ($File in $Files) {
$restpath = $file.fullname.replace($SplitBackup, "")
try {
# Use New-Item to create the destination directory if it doesn't yet exist. Then copy the file.
New-Item -Path (Split-Path -Path $($BackupDestination + $restpath) -Parent) -ItemType "directory" -Force -ErrorAction SilentlyContinue | Out-Null
Copy-Item -LiteralPath $file.fullname $($BackupDestination + $restpath) -Force -ErrorAction SilentlyContinue | Out-Null
Write-au2matorLog -Type Info -Text $("'" + $File.FullName + "' was copied")
}
catch {
$ErrorCount++
Write-au2matorLog -Type Error -Text $("'" + $File.FullName + "' returned an error and was not copied")
}
$Items += (Get-item -LiteralPath $file.fullname).Length
$Index = [array]::IndexOf($BackupDirs, $Backup) + 1
$Text = "Copy data Location {0} of {1}" -f $Index , $BackupDirs.Count
if ($File.Attributes -ne "Directory") { $count++ }
}
}
$SumCount += $Count
$SumTotalMB = "{0:N2}" -f ($Items / 1MB) + " MB of Files"
Write-au2matorLog -Type Info -Text "----------------------"
Write-au2matorLog -Type Info -Text "Copied $SumCount files with $SumTotalMB"
if ($ErrorCount ) { Write-au2matorLog -Type Info -Text "$ErrorCount Files could not be copied" }
$BackUpCheck = $true
}
catch {
Write-au2matorLog -Type ERROR -Text "Failed to Backup"
Write-au2matorLog -Type ERROR -Text $Error
$BackUpCheck = $false
}
}
catch {
Write-au2matorLog -Type ERROR -Text "Failed to Measure Backupdir"
Write-au2matorLog -Type ERROR -Text $Error
$BackUpCheck = $false
}
}
else {
Write-au2matorLog -Type ERROR -Text "PreCheck failed so do not run Backup"
$BackUpCheck = $false
}
## ZIP
if ($BackUpCheck) {
Write-au2matorLog -Type INFO -Text "BAckUpCheck is fine, so lets se if we need to ZIP"
if ($ZIP) {
Write-au2matorLog -Type INFO -Text "ZIP is on, so lets go"
if ($Use7ZIP) {
Write-au2matorLog -Type INFO -Text "We should use 7Zip for this"
try {
Write-au2matorLog -Type INFO -Text "Check for the 7ZIP Module"
if (Get-Module -Name 7Zip4Powershell) {
Write-au2matorLog -Type INFO -Text "7ZIP Module is installed"
}
else {
Write-au2matorLog -Type INFO -Text "7ZIP Module is not installed, try to install"
Install-Module -Name 7Zip4Powershell -Force
Import-Module 7Zip4Powershell
}
$Zip = $StagingPath + ("\" + $BackupDestination.Replace($Destination, '').Replace('\', '') + ".zip")
Write-au2matorLog -Type Info -Text "Compress File"
Compress-7Zip -ArchiveFileName $Zip -Path $BackupDestination
Write-au2matorLog -Type Info -Text "Move Zip to Destination"
Move-Item -Path $Zip -Destination $Destination
$ZIPCheck = $true
}
catch {
Write-au2matorLog -Type ERROR -Text "Error on 7ZIP compression"
Write-au2matorLog -Type ERROR -Text $Error
$ZIPCheck = $false
}
}
else {
}
}
else {
Write-au2matorLog -Type INFO -Text "No Zip, so go ahead"
}
}
else {
Write-au2matorLog -Type ERROR -Text "BAckUpCheck failed so do not try to ZIP"
}
##CLEANUP BACKUP
if ($Zip -and $RemoveBackupDestination -and $ZIPCheck)
{
try {
Write-au2matorLog -Type INFO -Text "Lets remove Backup Dir after ZIP"
#Remove-Item -Path $BackupDir -Force -Recurse
get-childitem -Path $BackupDestination -recurse -Force | remove-item -Confirm:$false -ErrorAction SilentlyContinue -Recurse
get-item -Path $BackupDestination | remove-item -Confirm:$false -ErrorAction SilentlyContinue -Recurse | Out-Null
}
catch {
Write-au2matorLog -Type ERROR -Text "Error to Remove Backup Dir: $BackupDestination"
Write-au2matorLog -Type ERROR -Text $Error
}
}
##CLEANUP VERSION
Write-au2matorLog -Type Info -Text "Cleanup Backup Dir"
$Count = (Get-ChildItem $Destination | Where-Object { $_.Attributes -eq "Directory" }).count
if ($count -gt $Versions) {
Write-au2matorLog -Type Info -Text "Found $count Backups"
$Folder = Get-ChildItem $Destination | Where-Object { $_.Attributes -eq "Directory" } | Sort-Object -Property CreationTime -Descending:$false | Select-Object -First 1
Write-au2matorLog -Type Info -Text "Remove Dir: $Folder"
$Folder.FullName | Remove-Item -Recurse -Force
}
$CountZip = (Get-ChildItem $Destination | Where-Object { $_.Attributes -eq "Archive" -and $_.Extension -eq ".zip" }).count
Write-au2matorLog -Type Info -Text "Check if there are more than $Versions Zip in the Backupdir"
if ($CountZip -gt $Versions) {
$Zip = Get-ChildItem $Destination | Where-Object { $_.Attributes -eq "Archive" -and $_.Extension -eq ".zip" } | Sort-Object -Property CreationTime -Descending:$false | Select-Object -First 1
Write-au2matorLog -Type Info -Text "Remove Zip: $Zip"
$Zip.FullName | Remove-Item -Recurse -Force
}
GitHub Repo
Make sure you get the latest version from GitHub.
Seidlm/PowerShell-Backup-Script: PowerShell Backup Script (github.com)
Michael Seidl aka Techguy
au2mate everything
Hallo,
ist es möglich, Dateien außerhalb von Unterordner zu (mit)kopieren?
Vielen Dank 🙂
Hallo, was meinst du genau damit?
Hallo
Vielen Dank für den Script. Ich finde das ganze echt toll. Vor allem mit den möglichen Backup-Versionen.
Wenn ich nun einen zu speichernden Pfad definiere, dann werden einzig die Unterordner (und die darin enthaltenen Dateien) gespeichert. Jedoch nicht die im Pfad abgespeicherten Dateien.
Beispiel:
$BackupDirs = “C:\Temp\OrdnerSave”
Nun werden die im OrderSave befindlichen UnterOrdner abespeichert. Aber die Files, die direkt im OrdnerSave liegen werden nicht in den $Destination-Pfad kopiert.
Hallo,
ich nehme das auf und werde das beim nächsten Release anpassen
Can this script be edited to add encryption and password protection to the resulting zip file?
Hi, sure, if you want to see this implemented, pleas add as feature request at GitHub
Hallo,
tolles Script und genau die Lösung für mich.
Ich bekomme leider die Fehlermeldung:
04.01.2022-11:21:38: Failed to Measure Backupdir
04.01.2022-11:21:38: Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat. Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat. Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat. Es ist nicht möglich, eine Methode für einen Ausdruck aufzurufen, der den NULL hat.
04.01.2022-11:21:38: BAckUpCheck failed so do not try to ZIP
Wo liegt denn mein Fehler?
VG
Hallo
benutzt du die aktuellste Version von GitHub?
Hallo Michael,
vielen Dank für das Script, funktioniert wunderbar und passt genau für meinen Einsatzzweck! Endlich mal etwas, das bei mir auf Anhieb funktioniert 😉
VG
Natasha
freut mich, danke
Hi,
ich bekomme leider einen Fehler. Eine Idee wo mein Fehler ist? Nutze die neuste Version.
Failed to Measure Backupdir
Fehler beim Aufrufen der Methode, da [System.IO.FileInfo] keine Methode mit dem Namen “op_Addition” enthält. Fehler beim Aufrufen der Methode, da [System.IO
.FileInfo] keine Methode mit dem Namen “op_Addition” enthält.
Hi,
bitte poste deine Fragen in Github, dort wird alles gesammelt und abgearbeitet.
Servus,
tolles Skript! Nur stehe ich ein wenig auf der Leitung: Ich möchte die lokalen Files am Rechner sammeln, ein ZIP daraus machen und dieses dann auf einen sicheren Speicherort kopieren (Fileserver). Wo kann ich den endgültigen Zielort (das Share) angeben? Weil wenn ich das Share bei $Destination angebe, werden alle Files auf das Share kopiert (1. Mal kopieren), dann wird von dort, aber lokal am Rechner das ZIP geschnürt (2. Mal kopieren) und dann das fertige ZIP wieder auf die Share kopiert (3. Mal kopieren). Was übersehe ich?
Hallo,
mit der $Staging Variable kannst du das steuern, denke das ist das was du benötigst
$UseStaging = $true #only if you use ZIP, than we copy file to Staging, zip it and copy the ZIP to destination, like Staging, and to save NetworkBandwith
Hey Michael,
Great script! My only thing about it is this. I’m trying to use the staging option, but from the way the script is written, it looks like you back everything up to the remote destination folder and then Zip things up to the Staging directory on the local folder and move that to the remote folder?
I would like to be able to use the Staging option to backup everything to the local Staging folder and then zip it, move the compressed zip to the remote folder, and then clear the staging folder on the local system?
Maybe I’m not reading the script right, but that’s how it seems to be working?
Thanks again for the awesome script!
Hallo,
wenn ich “$Zip = $true” und “$Use7ZIP = $false” habe,
wird in $Destination ein Ordner mit Inhalt stellt, aber keine zip-Datei.
Ich benutze Version 2.1
Im Skript ab Zeile 269 steht folgendes:
—————-
## ZIP
if ($BackUpCheck) {
Write-au2matorLog -Type INFO -Text “BAckUpCheck is fine, so lets se if we need to ZIP”
if ($ZIP) {
Write-au2matorLog -Type INFO -Text “ZIP is on, so lets go”
if ($Use7ZIP) {
Write-au2matorLog -Type INFO -Text “We should use 7Zip for this”
try {
…. hier steht noch mehr
}
catch {
…. hier steht noch mehr
}
}
else {
?? -> hier steht nichts drin
}
}
else {
Write-au2matorLog -Type INFO -Text “No Zip, so go ahead”
}
—————-
Bin ich richtig bei der Annahme, dass da etwas fehlt in diesem Teil, oder habe ich einen Denkfehler ?
MfG
Hallo Michael,
geniale Arbeit, danke dafür! Ich komme mit dem exclude leider nicht zurecht, unterordner möchte ich ausschließen, diese greifen aber leider nicht obwohl die Pfade die es nicht mitsichern soll mit vollständigem Speicherpfad angegen sind.
MfG
Hallo,
werde versuchen mal eine neue Version zu veröffentlichen und das zu fixen
Hallo Michael
Ich habe das BackupScript 2.0 verwendet und wollte fragen, ob die Möglichkeit besteht, mehrere Pfade unter $Destination anzugeben und wie ich das tun müsste?
Ich habe nämlich das Problem, dass ich gerne ein Backup mit der 3-2-1 Regel machen würde, jedoch funktioniert das Script nur dann, wenn ich einen einzigen Pfad unter $Destination angebe.
Ich hab schon mehreres ausprobiert, kriege aber immer nur einen Fehler.
Kann ich beim Skript auch mehrere Speicherorte für die Sicherenden Daten angeben?
Hallo,
danke für die Script Datei. Funktioniert soweit bis auf:
In meinem angegebenen Verzeichnis, zum sichern, sind Ordner und im root einige Dateien. Die Dateien werden nicht gesichert. Kann ich das ändern?
Grüße aus Berlin
Hallo Michael,
auch von mir herzlichen Dank für dieses geniale Skript, was ich auch schon seit Jahren einsetze.
In der neuesten Version habe ich jedoch auch das Problem, dass das Staging bei mir nicht funktioniert. Egal welche Parameter ich ändere. Zip = false oder true, Zip und 7zip true und false. Egal was ich einstelle, das Skript beginnt direkt in das Destination Verzeichnis zu sichern. In meinem Fall möchte ich am Standort A die Dateistruktur sichern, zippen und per WebDav zum NAS am Standort B (Destination Pfad) schicken.
Wie bereits beschrieben, beginnt das Skript aber direkt zum Standort B zu sichern, was mit einer ultraschnellen 16er Leitung sehr langwierig ist.
Viele Grüße und ein frohes neues Jahr
Alex