From 157cc390f0ba8506c3ddb678dcdc68dfa4981b61 Mon Sep 17 00:00:00 2001 From: Zachary Gorman Date: Tue, 11 Jun 2024 11:59:33 -0700 Subject: [PATCH 1/3] Add custom path option to UserProfileBackup --- Private/UserProfileBackup.ps1 | 213 +++++++++------------------------- 1 file changed, 57 insertions(+), 156 deletions(-) diff --git a/Private/UserProfileBackup.ps1 b/Private/UserProfileBackup.ps1 index 639a747..2089641 100644 --- a/Private/UserProfileBackup.ps1 +++ b/Private/UserProfileBackup.ps1 @@ -1,4 +1,4 @@ -function Get-UserProfileBackup($Computer) { + function Get-UserProfileBackup ($Computer) { <# .SYNOPSIS Backs up a user profile. @@ -10,39 +10,27 @@ #Charles Beddow maintains the UserProfileBackup - #The folders that this back up file grabs - $FoldersToCopy = @( - 'Desktop' - 'Downloads' - 'Favorites' - 'Documents' - 'Pictures' - 'Videos' - 'AppData\Local\Google\Chrome\User Data\Default\Bookmarks' - 'AppData\Roaming\Microsoft' - 'Sticky Notes' - - ) - - if($Computer -eq $null){ + if($null -eq $Computer){ $Computer = Read-Host -Prompt 'Enter computer name: ' } $ConfirmUser = $null #Collects the most recent users for options to backup if($Computer -eq $env:COMPUTERNAME) - { - Import-Module "\\basagh\team\shsisdesktopsolutions\Powershell\Get-PC\Modules\PCLocal\PCLocal.psm1" - - #Below are commands for the local PC when using "get-pc" by itself - $lastUser = Get-PCLastUserLocal + { + $lastUser = Get-ChildItem -Path C:\Users -Directory -Force -Exclude Public,Default,'Default User','All Users' | + Sort-Object -Property LastWriteTime -Descending | Select-Object -First 3 -ExpandProperty Name + if($null -eq $lastUser){ + Write-warning "PC unreachable or no profiles to back up" + return + } } else { $lastUser = Invoke-Command -ComputerName $Computer -SessionOption (New-PSSessionOption -NoMachineProfile) -ScriptBlock { Get-ChildItem -Path C:\Users -Directory -Force -Exclude Public,Default,'Default User','All Users' | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 3 -ExpandProperty Name } - if($lastUser -eq $null){ + if($null -eq $lastUser){ Write-warning "PC unreachable or no profiles to back up" return } @@ -51,7 +39,7 @@ Write-Host "Latest Users: $lastUser" #Asks user to pick which profile to backup - while( $ConfirmUser -eq $null ){ + while($null -eq $ConfirmUser){ $User = Read-Host -Prompt 'Choose user to backup' if( -not ( Test-Path -Path "\\$Computer\c$\Users\$User" -PathType Container ) ){ @@ -66,13 +54,6 @@ break } } - <# - Write-Host "Scanning user profile..." - $profileSize = scan-dir "\\$Computer\c$\Users\$User" - - $sizeout = "{1} profile is {0:n3}GB" -f $profileSize,$user - Write-Host $sizeout - #> $ConfirmUser = Read-Host -Prompt "Copy profile? (y/n) or Restore profile (r)" @@ -144,86 +125,68 @@ #Chooses Site to Backup the profile to Write-Host "Choose Site to backup" - for($i=0;$i -lt 8; $i++){ + $i = 0 + $numSites = $backupLocations.length + for($i=0;$i -lt $numSites; $i++){ $out = "[{0}]: {1}" -f $i, $backupLocations[$i].Site Write-Host $out } + Write-Host "[$i]: Custom destination" [int]$site = Read-Host "Site" - if(!(($site -ge 0 ) -and ($site -lt 8))){ + if(($site -ge 0 ) -and ($site -lt $numSites)){ + $BackupDestination = $backupLocations[$site].Path + $Destination = "$BackupDestination\$DestinationFileName" + #Creates a backup directory named "ComputerName-User-TodaysDate" + New-Item -Path $Destination -ItemType Directory | Write-Verbose + } elseif ($site -eq $numSites) { + $BackupDestination = Read-Host "Enter a PC asset, hostname, or custom path" + # Parse input for asset tag, hostname, then full path + if ($BackupDestination -match "^[1-9]{5}$") { + $BackupDestination = Get-AssetConversion $BackupDestination + } + # Treat as hostname and see if it's reachable + if (Test-Connection -ComputerName $BackupDestination -Count 1) { + # If so, get the filesystem path + $BackupDestination = "\\$BackupDestination\c$\Users\$User" + } + # Finally, test if this path works + if (-not ($BackupDestination -and (Test-Path "$BackupDestination"))) { + Write-Warning "Unable to access [$BackupDestination]" + return + } + $Destination = $BackupDestination + } else { Write-Warning "Invalid input please restart script" return } - $BackupDestination = $backupLocations[$site].Path - $Destination = "$BackupDestination\$DestinationFileName" - #Creates a backup directory named "ComputerName-User-TodaysDate" - New-Item -Path $Destination -ItemType Directory | Write-Verbose - if($User -eq "Public"){ - $FoldersToCopy = @('Desktop') - } #Creates a log file New-Item -Path $Destination\backuplog.txt -Force | Write-Verbose $log = Join-Path -Path $Destination -ChildPath backuplog.txt - Write-Host "Copying profile to $Destination" - - - foreach( $Folder in $FoldersToCopy ){ - - $Source = Join-Path -Path $SourceRoot -ChildPath $Folder - Write-Host "Copying $Folder" - - if( $Folder -eq 'Sticky Notes'){ - $Source = Join-Path -Path $SourceRoot -ChildPath 'AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState' - - } - #Checks if folder paths are available - if( -not ( Test-Path -Path $Source ) ){ - Write-Warning "Could not find path`t$Source" - continue - } - - - if( -not ( Test-Path -Path $Destination -PathType Container ) ){ - Write-Warning "Could not find path`t$Destination" - continue - } - - if($Folder -eq 'AppData\Roaming\Microsoft'){ - #If it's time to copy AppData folder it changes the copy destination to build the proper directory tree - - $Destination = Join-Path -Path $Destination -ChildPath 'AppData\Roaming\Microsoft' - - Copy-Item -Path (Get-Item -Path "$Source\*" -Exclude ('Teams')).FullName -Destination $Destination -Recurse -Force -PassThru | Out-File $log -Append - - Write-Host 'complete' - continue - } - if ($Folder -eq 'Sticky Notes'){ - $Destination = Join-Path -Path "$BackupDestination\$DestinationFileName" -ChildPath 'Sticky Notes' - } - Copy-Item $Source -Destination $Destination -Recurse -PassThru | Out-File $log -Append - Write-Host "complete" - } - + Invoke-UserProfileTransfer $SourceRoot $Destination + if(($site -ge 0 ) -and ($site -lt $numSites)){ + #Manually backup sticky notes since we don't always want them to transfer + $StickySource = Join-Path -Path $SourceRoot -ChildPath 'AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState' + $StickyDestination = Join-Path -Path "$Destination" -ChildPath 'AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState' + New-Item -Path $StickyDestination -ItemType Directory | Write-Verbose + Copy-Item $StickySource -Destination $StickyDestination -Recurse -PassThru | Out-File $log -Append - - #Cleans up Citrix Shortcuts + #Cleans up Citrix Shortcuts + + Write-Host "Removing Citrix Shortcuts from backup" + $Shortcuts = Get-ChildItem -Path $CopiedUserDesktop -Filter *.lnk - Write-Host "Removing Citrix Shortcuts from backup" - $Shortcuts = Get-ChildItem -Path $CopiedUserDesktop -Filter *.lnk + foreach($Shortcut in $Shortcuts){ + $sh = New-Object -ComObject WScript.Shell - - foreach($Shortcut in $Shortcuts){ - $sh = New-Object -ComObject WScript.Shell - - if($sh.CreateShortcut($Shortcut.FullName).TargetPath -eq 'C:\Program Files (x86)\Citrix\ICA Client\SelfServicePlugin\SelfService.exe') { - Remove-Item $Shortcut.FullName - } + if($sh.CreateShortcut($Shortcut.FullName).TargetPath -eq 'C:\Program Files (x86)\Citrix\ICA Client\SelfServicePlugin\SelfService.exe') { + Remove-Item $Shortcut.FullName + } + } } Write-Host "Complete" - } #endregion @@ -279,68 +242,6 @@ Write-Warning "The backup you have chosen does not exist" break } - if($User -eq "Public"){ - $FoldersToCopy = @('Desktop') - } - foreach( $Folder in $FoldersToCopy ){ - - #Special Case for AppData - if($Folder -eq 'AppData\Roaming\Microsoft'){ - $Folder = 'AppData' - } - $CurrentRestoreFolder = Join-Path -Path $FullRestorationSource -ChildPath $Folder - - #Special Case for Google Bookmarks - if($Folder -eq 'AppData\Local\Google\Chrome\User Data\Default\Bookmarks'){ - Write-Host "Restoring Chrome Bookmarks" - if( -not ( Test-Path -Path $FullRestorationSource\Bookmarks)){ - Write-Host "No Chrome Bookmarks backup" - continue - } - if( -not ( Test-Path -Path "$SourceRoot\AppData\Local\Google\Chrome")){ - Write-Warning "Restoring Chrome bookmarks but Chrome is not installed on this machine" - - } - if( -not ( Test-Path -Path "$SourceRoot\AppData\Local\Google\Chrome\User Data\Default")){ - New-Item "$SourceRoot\AppData\Local\Google\Chrome\User Data\Default" -ItemType Container | Write-Verbose - } - - Copy-Item $FullRestorationSource\Bookmarks -Destination "$SourceRoot\AppData\Local\Google\Chrome\User Data\Default\Bookmarks" -Force - Write-Host "complete" - continue - } - - #Special Case for Sticky Notes - if($Folder -eq 'Sticky Notes'){ - continue - } - - Write-Host "Restoring $Folder" - - #Checks if folder paths are available - if( -not ( Test-Path -Path $CurrentRestoreFolder -PathType Container ) ){ - Write-Warning "Could not find path`t$Source" - continue - } - if( -not ( Test-Path -Path $SourceRoot -PathType Container ) ){ - Write-Warning "Could not find path`t$Destination" - continue - } - - Copy-Item $CurrentRestoreFolder -Destination $SourceRoot -Recurse -Force - Write-Host "complete" - } + UserProfileTransfer $FullRestorationSource $SourceRoot } - #endregion - }#End Function - - #Helper Function - function scan-dir($Path) { - if ( (Test-Path $Path) -and (Get-Item $Path).PSIsContainer ){ - $DirectorySize = (Get-ChildItem -Path $path -File -Recurse -Force -ErrorAction SilentlyContinue | - Measure-Object -Property Length -Sum).Sum / 1GB - - Return $DirectorySize - } -} - + } From 115cf5dc06b262d7c860b9dbc8a1aef9878b0092 Mon Sep 17 00:00:00 2001 From: Zachary Gorman Date: Tue, 11 Jun 2024 12:02:04 -0700 Subject: [PATCH 2/3] Add UserProfileTransfer so UserProfileBackup will work --- Private/UserProfileTransfer.ps1 | 89 +++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Private/UserProfileTransfer.ps1 diff --git a/Private/UserProfileTransfer.ps1 b/Private/UserProfileTransfer.ps1 new file mode 100644 index 0000000..f4923bd --- /dev/null +++ b/Private/UserProfileTransfer.ps1 @@ -0,0 +1,89 @@ +function Invoke-UserProfileTransfer { + param($srcPath, $dstPath) + <# + .SYNOPSIS + Backs up a user profile to a specified filepath. + .DESCRIPTION + Takes a input of hostname and user and will make a copy of the user profile + and the Microsoft Roaming Folder and back it up to a specified filepath. + #> + + #The folders that this back up file grabs + $FoldersToCopy = @( + 'Desktop' + 'Downloads' + 'Favorites' + 'Documents' + 'Pictures' + 'Videos' + 'AppData\Local\Google\Chrome\User Data\Default\Bookmarks' + 'AppData\Roaming\Microsoft' + 'Sticky Notes' + ) + + #Creates a log file + New-Item -Path $dstPath\backuplog.txt -Force | Write-Verbose + $log = Join-Path -Path $dstPath -ChildPath backuplog.txt + + Write-Host "Copying profile to $dstPath" + + for ($i = 0; $i -lt $FoldersToCopy.Length; $i++) { + $Folder = $FoldersToCopy[$i] + + Write-Progress -Activity "User Profile Transfer from $srcPath to $dstPath" -Status $Folder -PercentComplete ($i / $FoldersToCopy.Length)*100 + + $Source = Join-Path -Path $srcPath -ChildPath $Folder + $Destination = $dstPath + Write-Host "Copying $Folder" + + if( $Folder -eq 'Sticky Notes'){ + $Source = Join-Path -Path $srcPath -ChildPath 'AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState' + $Destination = Join-Path -Path "$dstPath" -ChildPath 'AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState' + New-Item -Path $Destination -ItemType Directory | Write-Verbose + } + + if($Folder -eq 'AppData\Local\Google\Chrome\User Data\Default\Bookmarks'){ + if( -not ( Test-Path -Path $Source )){ + Write-Host "No Chrome Bookmarks present" + continue + } + if( -not ( Test-Path -Path "$Destination")){ + Write-Warning "Restoring Chrome bookmarks but Chrome is not installed on this machine" + + } + if( -not ( Test-Path -Path "$Destination")){ + New-Item "$Destination" -ItemType Container | Write-Verbose + } + + Copy-Item $Source -Destination "$Destination" -Force | Out-File $log -Append + Write-Host "complete" + continue + } + + #Checks if folder paths are available + if( -not ( Test-Path -Path $Source ) ){ + Write-Warning "Could not find path`t$Source" + continue + } + + if( -not ( Test-Path -Path $Destination -PathType Container ) ){ + Write-Warning "Could not find path`t$Destination" + continue + } + + if($Folder -eq 'AppData\Roaming\Microsoft'){ + #If it's time to copy AppData folder it changes the copy destination to build the proper directory tree + + $Destination = Join-Path -Path $Destination -ChildPath 'AppData\Roaming\Microsoft' + + Copy-Item -Path (Get-Item -Path "$Source\*" -Exclude ('Teams')).FullName -Destination $Destination -Recurse -Force -PassThru | Out-File $log -Append + + Write-Host 'complete' + continue + } + Copy-Item $Source -Destination $Destination -Recurse -PassThru | Out-File $log -Append + Write-Host "complete" + } + Write-Progress -Activity "User Profile Transfer from $srcPath to $dstPath" -Completed + #endregion + }#End Function \ No newline at end of file From 36541996e32a32d2943cd58721f85c2becaf36d8 Mon Sep 17 00:00:00 2001 From: Zachary Gorman Date: Wed, 12 Jun 2024 17:04:39 -0700 Subject: [PATCH 3/3] Removed old site from UserProfileTransfer --- Private/UserProfileBackup.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Private/UserProfileBackup.ps1 b/Private/UserProfileBackup.ps1 index 2089641..dd1957d 100644 --- a/Private/UserProfileBackup.ps1 +++ b/Private/UserProfileBackup.ps1 @@ -106,11 +106,6 @@ Site='SPCH' Path="\\SHSCMSPCH\ProfileBackup"} $backupLocations += $obj - $obj = New-Object PSObject -Property @{ - Site='Old Team Share' - Path="\\basagh\team\SHSISDesktopSolutions\General Shared Items\User Profile Backup"} - $backupLocations += $obj - $Date = Get-Date -Format "MM-dd" $DestinationFileName = "$Computer-$User-$Date"