# Custom backup script function backup_aragorn { param( [switch]$diskoverride, [switch]$skipappdir, [string]$usedisk=$null) . (Join-Path $PSScriptRoot handle_exclude_lists.ps1) $myName = $env:COMPUTERNAME # Identify the backup disk if ($usedisk) { ($backupDisk, $partial) = get_specific_disk $usedisk } else { ($backupDisk, $partial) = check_disk $diskoverride } # Backup folder $backup_dir = "$HOME\Local" if (!(Test-Path $backup_dir) ) { mkdir $backup_dir } # Setup to use 7zip if (! (Test-Path 'C:\Program Files\7-Zip\7z.exe')) { Write-Error "Unable to locate 7-zip program file" throw 'Unable to locate 7-zip executable' } Set-Alias sz 'C:\Program Files\7-Zip\7z.exe' # Start the log file $logger = customLogger $backupDisk $myName $logger.StartLog() # Create a compressed version of the App Dir if (!($skipappdir)) { # Create the main backup file $backup_file = "$backup_dir\appdir.7z" # Make sure we start in the home folder Set-Location $HOME # Remove the previous file (start clean each time) if (Test-Path $backup_file) { Remove-Item $backup_file } # Load the exclude list $exclude = parse_appdata_exclude # Generate the compressed backup Invoke-Command -ScriptBlock { sz a -bb0 -t7z $args[0] $args[1] "$HOME\AppData" } -ArgumentList @($exclude, $backup_file) } ## ## Copy Everything to the disk ## # Define Options $basicOptions = "/MIR /COPY:DT /SL /XJ /DST /NDL /NP /TEE /R:1 /W:2 /LOG+:{0} /XF Thumbs.db" -f ($logger.logfile) $homeOptions = getRobocopyOptions $logger.logfile # Exclude Videos on smaller disks if ($partial) { $basicOptions += " /XD D:\david\Videos" } # Backup Home Directory backupDir $backupDisk $myName $HOME "David" $homeOptions # Backup the Data disk backupDir $backupDisk $myName "D:\david\" "dDavid" $basicOptions backupDir $backupDisk $myName "D:\public\" "dPublic" $basicOptions # Wrap up and update the log $logger.EndLog() } # Get the age of the backup to make sure we are using the right disk function check_disk($diskoverride=$false) { $backupDisk = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.VolumeName -match "Backup" -or $_.VolumeName -match "Seagate"} $partialBackup = $false # Test the age of the backup on the disk $last_updated = Get-Date (Get-Content (Join-Path $backupDisk.DeviceID "Aragorn\updated.txt")) if ($last_updated.AddDays(20) -lt (Get-Date)) { if (!($diskoverride)) { Write-Host -ForegroundColor DarkRed "This disk was last used less than 3 weeks ago. Override with -diskoverride." throw 'Unable to proceed' } } # How much free space is there? if ($backupDisk.FreeSpace / 1gb -lt 20) { Write-Host -ForegroundColor DarkRed "There is less than 20gb free on the disk." throw 'Unable to proceed' } # If it is a big disk, backup the videos as well if ($backupDisk.Size / 1gb -lt 1200) { Write-Host "Disk is small enough to do a partial backup" $partialBackup = $true } # Return the disk letter and whether to do the full backup return ($backupDisk.DeviceID, $partialBackup) } function get_specific_disk($letter) { $backupDisk = Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.DeviceID -imatch $letter} # Return the disk letter and whether to do the full backup return ($backupDisk.DeviceID, $false) } function customLogger($backupDisk, $myName) { $logger = [PSCustomObject]@{ startTime = Get-Date logfile = "$HOME\backuplog_{0}.txt" -f (Get-Date -UFormat %Y%m%d-%H%M) endTime = $null updateFile = ("{0}\{1}\updated.txt" -f ($backupDisk, $myName)) } $StartLogScript = { Set-Content $this.logfile ( "`nStart Time: {0}`n`n" -f ($this.startTime) ) } $memberParam = @{ MemberType = "ScriptMethod" InputObject = $logger Name = "StartLog" Value = $StartLogScript } Add-Member @memberParam $EndLogScript = { Set-Content -Value (Get-Date) -Path $this.updateFile $this.endTime = Get-Date $start = "Start Time: {0}" -f $this.startTime $end = "Finish Time: {0}" -f $this.endTime Add-Content $this.logfile "`n`n$start`n$end" $ts = New-TimeSpan $this.startTime $this.endTime Write-Host ("The backup took {0:N1} minutes to complete" -f $ts.TotalMinutes) notepad $this.logfile } $memberParam = @{ MemberType = "ScriptMethod" InputObject = $logger Name = "EndLog" Value = $EndLogScript } Add-Member @memberParam return $logger } # Backup the specified directory function backupDir($diskID, $myName, $src, $dstDir, $options, $basedir="") { $dst = "{0}\{1}\{2}" -f ($diskID, $myName, $dstDir) # If we are working with a special base directory, set it here if ($basedir) { $dst = "{0}\{1}\{2}" -f ($diskID, $basedir, $dstDir) } # Make sure it exists and start the backup if (!(Test-Path $dst)) { mkdir $dst } & robocopy $src $dst $options.Split() } # Robocopy options function getRobocopyOptions($log) { $excludeList = @" AppData Application Data MicrosoftEdgeBackups Cookies .cache .vagrant.d "@ # Build the exclude rules $xd = "/XD" foreach ($line in $excludeList.Split("`n")) { $xd += ' "' + "$HOME\" + $line.Trim() + '"' } # Return the exclude options return "/MIR /COPY:DT /SL /XJ /DST /NDL /NP /TEE /R:0 /W:2 /LOG+:$log /XF NTUSER.* UsrClass.* Thumbs.db $xd" } Export-ModuleMember backup_aragorn