When I run the script below, it throws error "The process cannot access the file because it is being used by another process":
$RetailSource = Join-Path -Path 'D:\Folder' -ChildPath 'Retail'
$GroupSource = Join-Path -Path 'D:\Folder' -ChildPath 'Group'
$UATSource = Join-Path -Path 'D:\Folder' -ChildPath 'UAT'
$GRSource = Join-Path -Path 'D:\Folder' -ChildPath 'Report'
#$PMDashsource = Join-Path -Path 'D:\Folder' -ChildPath 'Dashboard' $style="<Style>Body{Font:arial 10pt}</Style>"
####################################################################################
# group these paths into a single array variable
####################################################################################
$Source = $RetailSource, $GroupSource, $UATSource, $GRSource
$RetailDest = '\\192.168.1.10\Folder1' # 1st Destination Location
$GroupDest = '\\192.168.1.10\Folder2' # 2nd Destination location
$UATDest = '\\192.168.1.10\Documents\Folder3' # Added 3rd destination location in this version 1.7.2V
#$PMDest = 'D:\ToolUpload\Folder4' $GRDest = '\\192.168.1.10\Folder5'
$ArchiveData = '\\192.168.1.10\backup_{0:yyyyMMddHHmm}' -f (Get-Date)
$LogFolder = 'D:\Uploadlogs-EIP'
#Logs will be generate in csv file at the below location.
$LogFile = 'D:\Uploadlogs-EIP\uploadlog_{0:yyyyMMdd}.csv' -f (Get-Date)
# make sure the output LogFolder exist
# by adding the -Force switch there is no need to use Test-Path first, because if
# the folder already exists, the cmdlet will return the DirectoryInfo of that,
# otherwise it will create a new folder. Since we don't want output, we use $null = ..
$null = New-Item -Path $LogFolder -ItemType Directory -Force
# loop through the files in the source folders and collect the outputted objects.
####################################################################################
# $Source is an ARRAY of paths
####################################################################################
$files = @(Get-ChildItem -Path $Source -File -Force -Recurse)
if ($files.Count -eq 0) { exit } #check the condition if the file doesn't exit then exit the code
$result = $files | ForEach-Object {
Write-Host "Processing file '$($_.FullName)'"
# create an object with (for now) 2 empty properties
$out = $_ | Select-Object @{Name = 'Date'; Expression = { (Get-Date) } },
@{Name = 'Source'; Expression = { $_.FullName } },
@{Name = 'FileSize'; Expression = { $_.Length / 1GB } },
Destination, # depends on the file name
@{Name = 'Archive'; Expression = { $ArchiveData } },
Result
# test if the file has a correct name
if ($_.BaseName -notmatch 'Retail Platform|Group Platform|Dashboard-Group|5 Year Report') {
# file does not have the correct naming convention
$out.Archive = $null
$out.Result = "Error: Incorrect filename"
}
else {
# depending on its name, get the correct destination folder
$destFolder = if ($_.Name -match "Retail Platform.qvw") {
$RetailDest
}
elseif ($_.Name -match "5 Year Report.qvw") {
$GRDest
}
elseif ($_.Name -match "Dashboard-Group.qvw") {
$GRDest
}
elseif ($_.Name -match "Group Intelligence Platform.qvw") {
$GroupDest
}
else {
$UATDest
}
# create the backup destination folder if it didn't already exist
# the first file in column 'Source' is now responsible for creating the backup folder
$null = New-Item -Path $destFolder -ItemType Directory -Force
# get the full path and filename for the destination
$existingFile = Join-Path -Path $destFolder -ChildPath $_.Name
# add the destination folder to the output object
$out.Destination = $destFolder
try {
# if a file with that name already exists in the destination, move it to the Archive folder
if (Test-Path -Path $existingFile -PathType Leaf) {
# create the Archive folder if it didn't already exist
$null = New-Item -Path $ArchiveData -ItemType Directory -Force
Move-Item -Path $existingFile -Destination $ArchiveData -ErrorAction Stop -Force
# add the archived file to the output object
$out.Archive = $existingFile
Write-Host "File '$existingFile' has been backed-up to '$ArchiveData'"
}
# next move the file from the source folder to its destination (either $RetailDest or $GroupDest)
$_ | Move-Item -Destination $destFolder -ErrorAction Stop
$out.Result = 'The tool has been uploaded'
Write-Host "The File '$($_.FullName)' has been moved to '$destFolder'"
}
catch {
# ouch.. something went horribly wrong on a Move-Item action
Write-Warning "An error occurred: $_.Exception.Message"
$out.Result = "Error: $($_.Exception.Message)"
####################################################################
# $LogFile will be saved later as CSV,
####################################################################
}
}
# output the object so it gets collected in variable $result
$out }
# now you can save the results as structured CSV file to open in Excel
$result | Export-Csv -Path $LogFile -UseCulture -NoTypeInformation -Append -Force
# and display on the screen using Out-GridView as the data will probably be too wide for
Format-Table $result | Out-GridView -Title 'Backup results'
# and send an email with the resulting CSV file as attachment
$result1 = $result
$htmlTemplate = @"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>File upload status</title>
<style>
body, table {font-family: sans-serif; font-size: 10pt; color: #000000;}
table {border: 1px solid black; border-collapse: collapse;}
th {border: 1px solid black; background: #dddddd; padding: 3px;}
td {border: 1px solid black; padding: 3px;}
</style>
</head>
<body>
<H2>Please find the following Tool upload status</H2>
@@TABLE@@
</body>
</html>
"@
$body = $htmlTemplate -replace '@@TABLE@@', (($result1 | ConvertTo-Html -Fragment) -join [Environment]::NewLine)
# if you want, you can save this to a file $body | Set-Content -Path 'C:\Desktop\serverstatus.html'
$EmailParams = @{
SmtpServer = 'xyz.mail.protection.outlook.com'
Port = '25'
Subject = 'The File Upload Status'
To = '[email protected]'
From = "[email protected]"
Body = $body
BodyAsHTML = $true
}
Send-MailMessage @EmailParams
CodePudding user response:
I have read the script and I think the error gets from using the $out variable and updating its parameters like $out.archive
and so on but without $out.update()
at the end
By the way, I see you're using $null = ... to avoid output it is preferred to use pipeline like | Out-Null
it is preferred to update us with line cased error it may help if this doesn't help
CodePudding user response:
I see you have changed your SO username since I wrote this answer.
Anyway, there are two Move-Item
commands in the code that both can show that error if any of the two files cannot be accessed.
If you want the error to also reveal what file this was, you can update the code inside the try{..} catch {..}
block like this:
try {
# if a file with that name already exists in the destination, move it to the Archive folder
if (Test-Path -Path $existingFile -PathType Leaf) {
# store the file that we will try to move in a variable in case we hit the catch{..} block
$fileThatCouldThrowError = $existingFile
# create the Archive folder if it didn't already exist
$null = New-Item -Path $ArchiveData -ItemType Directory -Force
Move-Item -Path $existingFile -Destination $ArchiveData -ErrorAction Stop -Force
# add the archived file to the output object
$out.Archive = $existingFile
Write-Host "File '$existingFile' has been backed-up to '$ArchiveData'"
}
# next move the file from the source folder to its destination (either $RetailDest or $GroupDest)
# if we got here, the file that could throw an exception is in $_.FullName
# store that file in the variable in case we hit the catch{..} block
$fileThatCouldThrowError = $_.FullName
$_ | Move-Item -Destination $destFolder -ErrorAction Stop
$out.Result = 'The tool has been uploaded'
Write-Host "The File '$($_.FullName)' has been moved to '$destFolder'"
}
catch {
# ouch.. something went horribly wrong on a Move-Item action
Write-Warning "An error occurred on file '$fileThatCouldThrowError': $_.Exception.Message"
$out.Result = "Error on file '$fileThatCouldThrowError': $($_.Exception.Message)"
####################################################################
# $LogFile will be saved later as CSV,
####################################################################
}