Powershell Scripting Assistance : Copy file with error correction

ITguy565
ITguy565 used Ask the Experts™
on
Experts, Looking for additional PowerShell scripting assistance

Function copy-File1 {
Param(
	[Parameter(Mandatory=$true)]
	$FileName
)
	#Drive Locations
	$tempDir = "$($locations.tempdir)"
	$WorkingDir = "$($locations.working_Dir)"
    $tdrivedir = "$($locations.tdrivedir)"
	[string]$filenamenew = "$(&$filenames.cwf_FileNameNew)"
    [string]$Destination = "$(&$filenames.cwf_Destination)"
    [string]$WorkFileloc = "$(&$filenames.cwf_WorkFileLoc)"
	
	#filename Trim
	$FileName = $FileName.Trim()
	If ([string]::IsNullOrEmpty($FileName)) {
		Throw 'Argument FileName is empty!'
	}
	$filePath = Join-Path -Path $tempDir -ChildPath $FileName
	#Identify which File is being Processed
	Write-Host -ForegroundColor Green "Processing File ""$($filePath)"" ..." -NoNewline
	#Test File Destination Path to see if File Exists.. If it Exists Remove it
	If (Test-Path -Path $filePath) {
		Write-Host " $($filePath) Already Exists : Removing File From Temp Location" -NoNewline
		#Error Handling for Remove-Item Command
		Try {
			$itemtemp = Get-Item -Path $filePath -ErrorAction Stop
 			Remove-Item $itemtemp -ErrorAction Stop
			Write-Host -ForegroundColor Green " Successfully Removed File $FileName" -NoNewline
		
		#Add Error Handing for Copy Command
			Write-Host -ForegroundColor Green "Setting $($workingdir) location"
			Set-Location $WorkingDir;
			if (Test-Path -Path $workingdir){
				Try {
					Write-Host -foregroundcolor green "Path Successfully set to $($workingdir)"
					Write-Host -ForegroundColor Green "Copying "$($locations.tempdir)\$filename" to $Destination"
					copy-item -path "$($locations.tempdir)\$filename" -Destination $Destination
					if (Test-Path $filename) {
						Write-Host -foregroundcolor Green "The file $filename was successfully Copied"}

				} Catch {
							Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red;
							Write-Host -foregroundcolor red "$filename was not Copied Successfully"
				}
			
			}else {
					Write-Host "Couldn't set the proper location : script will Terminate";
					pause;
					end}			
		} Catch {
			Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red -NoNewline
		}
	} Else {
		Write-Host " $($filePath) does not exist." -NoNewline
			Write-Host -ForegroundColor Green "Setting $($workingdir) location"
			Set-Location $WorkingDir;
			if (Test-Path -Path $workingdir){
				Try {
					Write-Host -foregroundcolor green "Path Successfully set to $($workingdir)"
					Write-Host -ForegroundColor Green "Copying "$($locations.tempdir)\$filename" to $Destination"
					copy-item -path "$($locations.tempdir)\$filename" -Destination $Destination
					if (Test-Path $filename) {
						Write-Host -foregroundcolor Green "The file $filename was successfully Copied"}

				} Catch {
							Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red;
							Write-Host -foregroundcolor red "$filename was not Copied Successfully"
				}
			
			}else {
					Write-Host "Couldn't set the proper location : script will Terminate";
					pause;
					end}		
	}
}

Open in new window



The code above is a first attempt at a error handling copy file script. While the code appears to be executing correctly, it is not copying the file requested into the proper location as it appears to successfully do.

Thanks in advance for you assistance with this.

Can anyone shead some light on a more efficient way to accomplish this Properly.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2018
Distinguished Expert 2018
Commented:
* Where are the $locations and $filenames objects referenced in lines 7-12 coming from? And if they're regular strings, you don't need a subexpression.
* $tdrivedir and $filenamenew are never used in the function.
* In lines 10-12. the subexpressions start with an ampersand, so PowerShell is trying to execute whatever is in the variable following it. I don't think that's what's intended here.
* Don't use [type] at the left of the equal sign, unless you know exactly what you're doing (strongly typing a variable) and why you need it. PowerShell was designed so that you usually won't have to worry about types.
* You're testing for the existence of $workingDir after you (try to) set the location to said directory.
* There's no command "end" (line 74). If it's a function inside a larger script, you should rename it to the <Verb>-<Noun> syntax, and ideally add a 2 to 3 letter prefix in front of the noun, to distinguish your own functions from default cmdlets (Copy-MyFile, Copy-ItgFile, whatever). <Verb> should be from the list obtained by "Get-Verb".
* You have lots of unnecessary duplicate script - once an existing target file has been removed, you can run the same code as when the target file didn't exist yet.

Restructured:
Function Copy-File1 {
Param(
	[Parameter(Mandatory=$true)]
	$FileName
)
	#Drive Locations
	$tempDir = $locations.tempdir
	$workingDir = $locations.working_Dir
	$tdrivedir = $locations.tdrivedir
	$filenamenew = $filenames.cwf_FileNameNew
	$destination = $filenames.cwf_Destination
	$WorkFileloc = $filenames.cwf_WorkFileLoc
	
	$FileName = $FileName.Trim()
	If ([string]::IsNullOrEmpty($FileName)) {
		Throw 'Argument FileName is empty!'
	}
	$filePath = Join-Path -Path $tempDir -ChildPath $FileName
	#Identify which File is being Processed
	Write-Host "Processing file '$($filePath)' ..." -ForegroundColor Green -NoNewline
	Try {
		#Test File Destination Path to see if File Exists.. If it Exists Remove it
		If (Test-Path -Path $filePath) {
			$action = "Removing existing file '$($filePath)' from Temp location"
			Write-Host $action -NoNewline
			$itemTemp = Get-Item -Path $filePath -ErrorAction Stop
			Remove-Item $itemTemp -ErrorAction Stop
			Write-Host "Successfully removed file $($FileName)" -ForegroundColor Green -NoNewline
		}
		$action = "Setting '$($workingDir)' location"
		Write-Host -ForegroundColor Green $action
		If (Test-Path -Path $workingDir) {
			Set-Location -Path $workingDir
			Write-Host "Path successfully set to '$($workingDir)'" -ForegroundColor Green
			$action = "Copying '$($filePath)' to '$($destination)'"
			Write-Host $action -ForegroundColor Green
			Copy-Item -Path $filePath -Destination $Destination -ErrorAction Stop
			Write-Host "The file $($FileName) was successfully copied" -ForegroundColor Green
		} Else {
			Throw "Expected folder '$($workingDir)' not found!"
		}
	} Catch {
		Write-Host "Action failed: $($action)" -ForegroundColor Red
		Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red
		Write-Host "Script will terminate"
		pause
	}
}	

Open in new window

oBdA, Thanks for the response.

Here are the definitions for what I am using in the script.  :

$locations = ""|Select Working_Dir, tempDir, tdrivedir, local_Working
    $locations.Working_Dir = {\\server1\c$\WORKING_DIR}
    $locations.local_Working = {(get-childitem C:\users\ -Recurse |? {($_.name -like "working_dir") -and ($_.Attributes -like "Directory*")}).fullname}
    $locations.tempDir = {\\server1\c$\WORKING_DIR\Temp}
    $locations.tdrivedir = {\\server2\c$\tempT}

Open in new window


When I try and execute the code above, it is returning with :

Processing file '' ...Action failed:
Error Message: Cannot bind argument to parameter 'Path' because it is null.
Script will terminate
Press Enter to continue...
Sorry for my delay in responding, we are finishing preparations for a hurricane at the moment.
Most Valuable Expert 2018
Distinguished Expert 2018

Commented:
You can take your time, I'm still in Kansas ...

$locations.Working_Dir = {\\server1\c$\WORKING_DIR}
...

Open in new window

You're defining a scriptblock here, that the function will then just turn into its string representation. That's overly complicated and hard to understand (because the scriptblock by itself will just fail), with no benefit.
I'd recommend to just use a regular string, because that's what you need and expect anyway.

$locations.local_Working = {(get-childitem C:\users\ -Recurse |? {($_.name -like "working_dir") -and ($_.Attributes -like "Directory*")}).fullname}

Open in new window

This is the only case where the scriptblock would actually work as such (so the $filenames variables are defined like that as well, I guess?).
But it would only make sense if in the time between the scriptblock's definition in the main script and the resolution in the function, the target folder you're looking for might have changed. If this folder is supposed to stay the same during the whole runtime of the script, you're better off with retrieving the folder at the script start and saving the path as a regular string.
And just in case: note that this might return more than one folder.

In other words:
Either
Replace lines 7-12 in my script above with the originals:
	$tempDir = "$($locations.tempdir)"
	$WorkingDir = "$($locations.working_Dir)"
	$tdrivedir = "$($locations.tdrivedir)"
	$filenamenew = "$(&$filenames.cwf_FileNameNew)"
	$Destination = "$(&$filenames.cwf_Destination)"
	$WorkFileloc = "$(&$filenames.cwf_WorkFileLoc)"

Open in new window


Or leave the script as is, and set the variables you're passing to regular strings instead of scriptblocks.
Thanks again oBdA

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial