Copy user data from one remote computer to another, then copy only what’s changed later?

So I’m working on a script to simplify our PC replacement procedure; one of the biggest time sinks currently is copying all of the user’s data while we’re out in the field. To get around this, some of our techs copy data over the network beforehand, but you run into issues with the user having changed documents and potentially not bringing over those changes.

To solve this, I want to make a solution that’s the best of both worlds, allowing technicians to copy data over the network beforehand to get the bulk of the data transfer done, while enabling them to only copy what’s changed when they are out in the field replacing the user’s computer. In an ideal world, we could just use robocopy/rsync, but since only one computer will be online at a time during the replacement, this isn’t really possible.

Here is what I have so far. It copies non-standard folders on the root of C, their user profile (excluding links and downloads) and any PST files they may have in their appdata folder for Outlook, then generates a hash of every file to an external drive that is attached to the technician’s machine:

function Invoke-InitialSmartDataTransfer($OldPCName, $NewPCName, $ExternalDrive, $PrincipalUser) { if (-not(Test-Path -Path ($ExternalDrive + ":PC Deployment"))) { New-Item -Path ($ExternalDrive + ":") -Name "PC Deployment" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ($ExternalDrive + ":PC Deployment$OldPCName"))) { New-Item -Path ($ExternalDrive + ":PC Deployment") -Name "$OldPCName" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ($ExternalDrive + ":PC Deployment$OldPCNameC"))) { New-Item -Path ($ExternalDrive + ":PC Deployment$OldPCName") -Name "C" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUser"))) { New-Item -Path "\$NewPCNameC$PC DeploymentCUsers" -Name "$PrincipalUser" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppData"))) { New-Item -Path "\$NewPCNameC$PC DeploymentCUsers$PrincipalUser" -Name "AppData" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppDataLocal"))) { New-Item -Path "\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppData" -Name "Local" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppDataLocalMicrosoft"))) { New-Item -Path "\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppDataLocal" -Name "Microsoft" -ItemType "directory" | Out-Null } if (-not(Test-Path -Path ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppDataLocalMicrosoftOutlook"))) { New-Item -Path "\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppDataLocalMicrosoft" -Name "Outlook" -ItemType "directory" | Out-Null } $Cfolders = get-item -path "\$OldPCNameC$*" -Exclude "*Windows*","Users","Temp","Program Files*", "Lotus" | where-object {$_.PSIsContainer -eq $true} Write-Output "Copying files on root of C to C:PC Deployment on new PC..." foreach ($folder in $Cfolders) { Copy-Item -Path $folder.FullName -Destination ("\$NewPCNameC$PC DeploymentC") -Recurse | Out-Null } $Cfiles = get-item -path "\$OldPCNameC$*" | where-object {$_.PSIsContainer -eq $false} foreach ($file in $Cfiles) { Copy-Item -Path $file.FullName -Destination ("\$NewPCNameC$PC DeploymentC") } Write-Output "Copying $Principaluser user profile..." $Pfolders = get-item -path "\$OldPCNameC$Users$PrincipalUser*" -Exclude "Links","Downloads" | where-object {$_.PSIsContainer -eq $true} foreach ($folder in $Pfolders) { Copy-Item -Path $folder.FullName -Destination ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUser") -Recurse } $Pfiles = get-item -path "\$OldPCNameC$Users$PrincipalUser*" | where-object {$_.PSIsContainer -eq $false} foreach ($file in $Pfiles) { Copy-Item -Path $file.FullName -Destination ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUser") } $PSTs = get-childitem -path "\$OldPCNameC$Users$PrincipalUserAppDataLocalMicrosoftOutlook*" -Include "*.pst" foreach ($PST in $PSTs) { Copy-Item -Path $PST.FullName -Destination ("\$NewPCNameC$PC DeploymentCUsers$PrincipalUserAppDataLocalMicrosoftOutlook") -Force | Out-Null } Write-Output "Hashing copied files to external drive..." $hashlocs = get-childitem -Path "\$NewPCNameC$PC DeploymentC" -Recurse -File foreach ($file in $hashlocs) { $hash = Get-Filehash -Path $file.FullName -Algorithm MD5 $destinationStub = (($file.DirectoryName).TrimStart("\$NewPCNameC$PC DeploymentC")) New-Item -Path ($ExternalDrive + ":PC Deployment$OldPCNameC$destinationStub") -Value $hash.Hash -ItemType "file" -Name ($file.Name + ".hsh") -Force | Out-Null } } 

It works…kinda…some of the folder structure that is generated on the external drive has the beginning of the folder name cut off; I have a feeling it has something to do with me not fully understanding the behavior of TrimStart.

The idea is that once this initial transfer has been done, another transfer will be run on the PC in the field to check against all these generated hashes, and copy over anything that has a different hash than before.

Is there an easier way to accomplish this that I am too blind to see? Is this feasible at all? Thanks for any assistance.

submitted by /u/rmg22893
[link] [comments]

Leave a Reply