In the last part we looked at the Get-FolderInformation function, which returns an object describing a folder so the user can tell if they want to process it or not. This part is going to focus on the Move-ArchiveObject function which will actually perform the archive (or return from archive) process on a chosen folder. The full script can be found here.
Move-ArchiveObject
function Move-ArchiveObject { param ( [Parameter(Mandatory=$True,ValueFromPipeline=$true)] [PSObject]$SourceObject ) BEGIN { } PROCESS { Write-Debug "Entering Move-ArchiveObject function" if ($SourceObject.Direction -eq "To Archive") { #See if there's already a folder at the target location. if(!(Test-Path -Path $SourceObject.FullArchivePath)) { Copy-Item -Path $SourceObject.FullSourcePath -Destination $SourceObject.FullArchivePath -Recurse #After copying the folder, make sure its size matches the original before deleting the original and #creating the symbolic link. if ($SourceObject.Size -eq (Get-FolderSize $SourceObject.FullArchivePath)) { Remove-Item -Path $SourceObject.FullSourcePath -Recurse & CMD.EXE /c "MKLINK /j $($SourceObject.FullSourcePath) $($SourceObject.FullArchivePath)" > $Null $SourceObject.Successful=$True }else { $SourceObject.Message="Source and Destination folder sizes differ. Aborting archive operation." } }else { $SourceObject.Message="Destination already exists." } }else { #Delete the symbolic link and copy the original back to the sourcepath. (Get-Item -Path $SourceObject.FullSourcePath).Delete() Copy-Item -Path $SourceObject.FullArchivePath -Destination $SourceObject.FullSourcePath -Recurse #Don't delete the archive unless the source copy's size matches the archive copy. if ($SourceObject.Size -eq (Get-FolderSize -Path $SourceObject.FullSourcePath)) { Remove-Item -Path $SourceObject.FullArchivePath -Recurse $SourceObject.Successful=$True }else { $SourceObject.Message="Source and Destination folder sizes differ. Aborting archive operation." } } Write-Output $SourceObject Write-Debug "Leaving Move-ArchiveObject function" } }
Breaking the above down into (semi) manageable chunks;
function Move-ArchiveObject { param ( [Parameter(Mandatory=$True,ValueFromPipeline=$true)] [PSObject]$SourceObject ) BEGIN { } PROCESS {
This function will take the PSObjects we created in the Get-FolderInformation function and process them. We need to make the $SourceObject mandatory and allow processing of them from the pipeline.
Write-Debug "Entering Move-ArchiveObject function" if ($SourceObject.Direction -eq "To Archive") { #See if there's already a folder at the target location. if(!(Test-Path -Path $SourceObject.FullArchivePath)) {
There are two main actions we could perform; either archiving a folder or returning a folder back from the archive. Which we can perform on the folder contained in $SourceObject has already been detected by Get-FolderInformation. In the case of moving to an archive we first check that there isn’t already a folder with the source folder’s name in the archive folder.
Copy-Item -Path $SourceObject.FullSourcePath -Destination $SourceObject.FullArchivePath -Recurse
The above statement copies the source folder to the archive path, recursively copying any subfolders. These properties of the PSObject have been populated as part of the Get-FolderInformation function.
if ($SourceObject.Size -eq (Get-FolderSize $SourceObject.FullArchivePath)) { Remove-Item -Path $SourceObject.FullSourcePath -Recurse & CMD.EXE /c "MKLINK /j $($SourceObject.FullSourcePath) $($SourceObject.FullArchivePath)" > $Null $SourceObject.Successful=$True }else { $SourceObject.Message="Source and Destination folder sizes differ. Aborting archive operation." }
After the copy has finished we want to make sure the size of the copy matches the original (which was stored as a property in $SourceObject). If it matches, we remove the original (Remove-Item -Path $SourceObject.FullSourcePath -Recurse) and then create a symbolic link from the old source path to the new, copied archive. Finally, we mark the operation as successful ($SourceObject.Successful=$True).
If the source and destination sizes don’t match then we keep $SourceObject.Successful as the default ($False) and write a descriptive message about the failure to the object.
}else { $SourceObject.Message="Destination already exists." }
If the destination folder did exist then we keep $SourceObject.Successful as $False and we write an error message to the object.
}else { #Delete the symbolic link and copy the original back to the sourcepath. (Get-Item -Path $SourceObject.FullSourcePath).Delete() Copy-Item -Path $SourceObject.FullArchivePath -Destination $SourceObject.FullSourcePath -Recurse
This is the case where the move direction is from the archive (i.e. we’re returning an archived folder back to it’s original location). For this we need to delete the original symbolic link and copy the archived folder back into its place.
Note the brackets on “(Get-Item -Path $SourceObject.FullSourcePath).Delete()“; first we get the item at the $SourceObject.FullSourcePath location and then we use the Delete method on it. If we’d excluded the brackets around the first part PowerShell would have looked for the delete method on the $SourceObject.FullSourcePath object, which would have failed.
if ($SourceObject.Size -eq (Get-FolderSize -Path $SourceObject.FullSourcePath)) { Remove-Item -Path $SourceObject.FullArchivePath -Recurse $SourceObject.Successful=$True }else { $SourceObject.Message="Source and Destination folder sizes differ. Aborting archive operation." } } Write-Output $SourceObject Write-Debug "Leaving Move-ArchiveObject function" } }
To finish we check that the source and destination file sizes match and if so we delete the archived folder. If they don’t we keep $SourceObject.Successful as $False and return an error.
Finally, we return the modified $SourceObject.
Those are the main functions complete! In the next part we’ll look at a couple of small housekeeping functions before the main body of the script in the last part.