Powershell Try Catch IOException DirectoryExist - powershell

I'm using a power shell script to copy some files from my computer to a USB drive. However, even though I'm catching the System.IO exception, I still get the error at the bottom. How do I properly catch this exception, so it shows the message in my Catch block.
CLS
$parentDirectory="C:\Users\someUser"
$userDirectory="someUserDirectory"
$copyDrive="E:"
$folderName="Downloads"
$date = Get-Date
$dateDay=$date.Day
$dateMonth=$date.Month
$dateYear=$date.Year
$folderDate=$dateDay.ToString()+"-"+$dateMonth.ToString()+"-"+$dateYear.ToString();
Try{
New-Item -Path $copyDrive\$folderDate -ItemType directory
Copy-Item $parentDirectory\$userDirectory\$folderName\* $copyDrive\$folderDate
}
Catch [System.IO]
{
WriteOutput "Directory Exists Already"
}
New-Item : Item with specified name E:\16-12-2014 already exists.
At C:\Users\someUser\Desktop\checkexist.ps1:15 char:9
+ New-Item -Path $copyDrive\$folderDate -ItemType directory
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceExists: (E:\16-12-2014:String) [New-Item], IOException
+ FullyQualifiedErrorId : DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand

If you want to catch an exception for a New-Item call, you need to do two things:
Set $ErrorActionPreference = "Stop" by default its value is Continue. This will make the script Stop in case of exceptions.
Trap the correct exception and/or all of them
if you want to trap all exceptions, just use catch without arguments:
catch
{
Write-Output "Directory Exists Already"
}
if you want to trap a specific exception, first find out which one it is, by checking the value of
$error[0].Exception.GetType().FullName
and in your case the value is:
System.IO.IOException
then you can use this value as an argument to your catch, like this:
catch [System.IO.IOException]
{
Write-Output "Directory Exists Already"
}
Source worth reading: An introduction to Error Handling in Powershell

In addition you can spot exactly Directory Exist (unfortunally no File Exist error type for files).
$resExistErr=[System.Management.Automation.ErrorCategory]::ResourceExists
try {
New-Item item -ItemType Directory -ErrorAction Stop
}
catch [System.IO.IOException]
{
if ($_.CategoryInfo.Category -eq $resExistErr) {Write-host "Dir Exist"}
}

If you add -ErrorAction Stop to the line creating the directory you can catch [System.IO.IOException](not [System.IO]). You should also catch all other exceptions that can potentially occur:
try {
New-Item -Path $copyDrive\$folderDate -ItemType directory -ErrorAction Stop
Copy-Item $parentDirectory\$userDirectory\$folderName\* $copyDrive\$folderDate -ErrorAction Stop
}
catch [System.IO.IOException] {
WriteOutput $_.Exception.Message
}
catch {
#some other error
}

I don't suggest actually catching the error in this case. Although that may be the correct action in general, in this specific case I would do the following:
$newFolder = "$copyDrive\$folderDate"
if (-not (Test-Path $newFolder)) {
New-Item -Path $newFolder -ItemType directory
Copy-Item $parentDirectory\$userDirectory\$folderName\* $newFolder
} else {
Write-Output "Directory Exists Already"
}

Related

Powershell terminate execution

I am using powershell to process csv files in a directory when no file found with current date stamp I want the process to raise an error notifying file not found and exit.
# Powershell raise error and exit
# File name: sale_2020_02_03.csv
$getLatestCSVFile = Get-ChildItem -Path $Folder -Filter "*.csv" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
if ($getLatestCSVFile)
{
try
{
# Process .csv file
}
catch
{
# on error
$ErrorMessage = $_.Exception.Message
throw "$ErrorMessage"
}
}
else
{
# If current date file not found raise error and exit
Send-MailMessage
throw "File not found"
}
As for this...
I would like to have the powershell script to stop execution
... that is what the Exit keyword is for or the '-ErrorAction Stop' option is for.
As for this...
if the code gets into the else block in the else block I want to
notify file not found
... as per my above, same thing, and you have to set that.
Meaning stuff like ...
Clear-Host
$Error.Clear()
try
{
# Statement to try
New-Item -Path 'D:\Temp\DoesNOtExist' -Name 'Test.txt' -ItemType File -ErrorAction Stop
}
catch
{
# What to do with terminating errors
Write-Warning -Message $Error[0]
}
# Results
<#
WARNING: Could not find a part of the path 'D:\Temp\DoesNOtExist\Test.txt'.
#>
Or using multiple catch statements, like ...
Example: Force file warning
Clear-Host
$Error.Clear()
try
{
# Results in NoSupportException
# Statement to try
New-Item -Path 'D:\Temp\Temp' -Name my:Test.txt -ItemType File -ErrorAction Stop
# Results in DirectoryNotFoundException
# New-Item -Path 'D:\Temp\Temp' -Name 'Test.txt' -ItemType File -ErrorAction Stop
}
catch [System.NotSupportedException]
{
# What to do with terminating errors
Write-Warning -Message 'Illegal chracter or filename.'
}
catch [System.IO.DirectoryNotFoundException]
{
# What to do with terminating errors
Write-Warning -Message 'The path is not valid.'
}
catch
{
# What to do with terminating errors
Write-Warning -Message 'An unexpected error occurred.'
}
# Results
<#
WARNING: Illegal character or filename.
#>
Example: Force path warning
Clear-Host
$Error.Clear()
try
{
# Results in NoSupportException
# Statement to try
# New-Item -Path 'D:\Temp\Temp' -Name my:Test.txt -ItemType File -ErrorAction Stop
# Results in DirectoryNotFoundException
New-Item -Path 'D:\Temp\Temp' -Name 'Test.txt' -ItemType File -ErrorAction Stop
}
catch [System.NotSupportedException]
{
# What to do with terminating errors
Write-Warning -Message 'Illegal chracter or filename.'
}
catch [System.IO.DirectoryNotFoundException]
{
# What to do with terminating errors
Write-Warning -Message 'The path is not valid.'
}
catch
{
# What to do with terminating errors
Write-Warning -Message 'An unexpected error occurred.'
}
# Results
<#
WARNING: The path is not valid.
#>
See also this discussion, which is a similar use case. Pay particular attention the the 'Exit vs Return vs Break' answer.
Terminating a script in PowerShell

Error action not stopping script

Consider this simple code:
Read-Host $path
try {
Get-ChildItem $Path -ErrorAction Continue
}
Catch {
Write-Error "Path does not exist: $path" -ErrorAction Stop
Throw
}
Write-Output "Testing"
Why is 'Testing' printed to the shell if an invalid path is specified?
The script does not stop in the catch block. What am I doing wrong?
In your Try Catch block, you need to set Get-ChildItem -ErrorAction Stop
so the exception is caught in the Catch block.
With continue, you are instructing the command to not produce a terminating error when an actual error occurs.
Edit:
Also, your throw statement is useless there and you do not need to specify an error-action for Write-Error.
Here's the modified code.
$path = Read-Host
try {
Get-ChildItem $Path -ErrorAction stop
}
Catch {
Write-Error "Path does not exist: $path"
}
Additional note
You could apply this default behavior (if that is what you want) to the entire script by setting the default action to stop using :
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
I think this is what you need:
$path = Read-Host 'Enter a path'
try {
Get-ChildItem $Path -ErrorAction Stop
}
Catch {
Throw "Path does not exist: $path"
}
Write-Output "Testing"
Per Sage's answer, you need to change to -ErrorAction Stop in the Try block. This forces the Get-ChildItem cmdlet to throw a terminating error, which then triggers the Catch block. By default (and with the Continue ErrorAction option) it would have thrown a non-terminating error which are not caught by a try..catch.
If you then want your code to stop in the Catch block, use Throw with the message you want to return. This will produce a terminating error and stop the script (Write-Error -ErrorAction Stop will also achieve a terminating error, it's just a more complicated method. Typically you should use Write-Error when you want to return non-terminating error messages).

Catch "Cannot Find File"

I have been searching for a while, but I cannot find the exception in PowerShell that would catch a "Cannot find file" error.
I would also like to have this loop until the user types in the correct file name to get.
# Ask user for file to read from
Try {
$readFile = Read-Host "Name of file to read from: "
$ips = GC $env:USERPROFILE\Desktop\$readFile.txt
}
Catch {
}
The error you get is a non-terminating error, and thus not caught. Add -ErrorAction Stop to your Get-Content statement or set $ErrorActionPreference = 'Stop' and your code will work as you expect:
try {
$readFile = Read-Host "Name of file to read from: "
$ips = GC $env:USERPROFILE\Desktop\$readFile.txt -ErrorAction Stop
} catch {
}
Don't use try/catch blocks for flow control. That is a generally-frowned-on practice, especially in PowerShell, since PowerShell's cmdlets will write errors instead of throwing exceptions. Usually, only non-PowerShell .NET objects will throw exceptions.
Instead, test if the file exists. That gives you much greater error control:
do
{
$readFile = Read-Host "Name of file to read from: "
$path = '{0}\Desktop\{1}.txt' -f $env:USERPROFILE,$readFile
if( (Test-Path -Path $path -PathType Leaf) )
{
break
}
Write-Error -Message ('File ''{0}'' not found.' -f $path)
}
while( $true )

test-path returns permission denied - how to do error handling

i try to do error handling within my powershell script. but i always get an fatal. i tried a few things, e. g. try{ } catch{ } - but i did it not get to work.
any ideas or Solutions?
Function Check-Path($Db)
{
If ((Test-Path $Db) –eq $false) {
Write-Output "The file $Db does not exist"
break
}
}
It Returns:
Test-Path : Zugriff verweigert
In K:\access\access.ps1:15 Zeichen:6
+ If ((Test-Path $Db) -eq $false) {
+ ~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (K:\ss.mdb:String) [Test-Path], UnauthorizedAccessException
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.TestPathCommand
Somewhat confusingly Test-Path actually generates an error in a number of cases. Set the standard ErrorAction parameter to SilentlyContinue to ignore it.
if ((Test-Path $Db -ErrorAction SilentlyContinue) -eq $false) {
I cannot answer directly. So this has to do:
I strongly disagree with your answer. Test-Path does show $false when you run it against a network share that is not accessible, but it will be false also (without Exception) when the Server is not reachable.
So your answer simply ignores anything but a reachable share.
What is neccessary however is a try-catch-block that handles this better:
[cmdletbinding()]
param(
[boolean]$returnException = $true,
[boolean]$returnFalse = $false
)
## Try-Catch Block:
try {
if ($returnException) {
## Server Exists, but Permission is denied.
Test-Path -Path "\\Exists\Data\" -ErrorAction Stop | Out-Null
} elseif ($returnFalse) {
## Server does not exist
Test-Path -Path "\\NoExists\Data\" -ErrorAction Stop | Out-Null
}
} catch [UnauthorizedAccessException] {
## Unauthorized
write-host "No Access Exception"
} catch {
## an error has occurred
write-host "Any other Exception here"
}
The really important part however is the ErrorAction on the Test-Path command, otherwise the exception will be wrapped around a system management error and is thus not catchable. This is in detail explained here:
PowerShell catching typed exceptions

Windows Script to Rename and move files

I have been tasked with creating an archive process using either a Windows Batch or PowerShell script. I have seen a few examples here on StackExchange but nothing that does exactly what I need and I am running into some issues.
Here is the background:
I have 3 folders
Incoming
Archive
Outgoing
Our main system puts xml files into the Incoming directory and I have to create a script that will run every 5 mins and do the following ....
Iterate through all the xml files in the Incoming folder
Rename them to OriginalFilename.ready_to_archive
Copy all ready_to_archive_files into the Archive directory
Once in the archive directory rename them back to OriginalFilename.xml
Copy all ready_to_archive_files into the Outgoing directory
Once in the Outgoing directory rename them back to OriginalFilename.xml
Delete all ready_to_archive_files from the Incoming directory
Of course if any stage fails then it should not go to the next one since we do not want to delete files that have not been archived properly.
I have had a look at Folder iteration with Move-Item etc but I run into so many issues. This is really not my main working field so any help would be appreciated.
Thanks
-- EDIT --
Here is the PowerShell script I created:
$SCRIPT_DIRECTORY = "d:\Temp\archive\"
$IPS_OUTPUT_DIRECTORY = "d:\Temp\archive\one\"
$ARCHIVE_DIRECTORY = "d:\Temp\archive\two\"
$BIZTALK_INCOMING_DIRECTORY = "d:\Temp\archive\three\"
$ORIGINAL_EXTENSION = ".xml"
$PREP_EXTENSION = ".ready_for_archive"
$ARCHIVE_EXTENSION = ".archive"
#STEP 1
Try
{
"Attempting to rename file from .xml to .archive"
Set-Location -Path $IPS_OUTPUT_DIRECTORY
Get-ChildItem *.xml | Rename-Item -NewName { $_.Name -replace $ORIGINAL_EXTENSION,$PREP_EXTENSION
}
}
Catch [system.exception]
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
"Error in Step 1: $FailedItem : $ErrorMessage"
Set-Location -Path $SCRIPT_DIRECTORY -ErrorAction Stop #Stop here and return to the script's
base directory - DO NOT CONTINUE!!!!!
Break
}
Finally
{
"end of step 1"
#STEP 2
Try
{
"Attempting to copy ready_to_archive file from One to Two"
Get-ChildItem -path $IPS_OUTPUT_DIRECTORY -recurse -include *.$PREP_EXTENSION |
Foreach-Object { Copy-Item -path $_ -destination { $_.FullName -replace
$IPS_OUTPUT_DIRECTORY,$ARCHIVE_DIRECTORY}}
}
Catch [system.exception]
{
"caught an error in step 2"
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
"Error in Step 2: $FailedItem : $ErrorMessage"
Set-Location -Path $SCRIPT_DIRECTORY -ErrorAction Stop #Stop here and return to the script's base directory - DO NOT CONTINUE!!!!!
Break
}
Finally
{
"end of step 2"
#STEP 3
Try
{
"Attempting to rename files from .ready_to_archive to .archive"
Set-Location -Path $ARCHIVE_DIRECTORY
Get-ChildItem *.xml | Rename-Item -NewName { $_.Name -replace $PREP_EXTENSION,$ARCHIVE_EXTENSION }
}
Catch [system.exception]
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
"Error in Step 3: $FailedItem : $ErrorMessage"
Set-Location -Path $SCRIPT_DIRECTORY -ErrorAction Stop #Stop here and return to the script's base directory - DO NOT CONTINUE!!!!!
Break
}
Finally
{
"end of step 3"
#STEP 4
Try
{
"Attempting to copy archive file from one to three"
Copy-Item -path $IPS_OUTPUT_DIRECTORY -include "*.ready_to_archive" -Destination $BIZTALK_INCOMING_DIRECTORY
}
Catch [system.exception]
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
"Error in Step 4: $FailedItem : $ErrorMessage"
Set-Location -Path $SCRIPT_DIRECTORY -ErrorAction Stop
Break
}
Finally
{
"end of step 4"
#STEP 5
Try
{
"Attempting to rename file from .ready_to_archive to .xml"
Set-Location -Path $BIZTALK_INCOMING_DIRECTORY
Get-ChildItem *.$PREP_EXTENSION | Rename-Item -NewName { $_.Name -replace $PREP_EXTENSION,$ORIGINAL_EXTENSION }
}
Catch [system.exception]
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
"Error in Step 5: $FailedItem : $ErrorMessage"
Set-Location -Path $SCRIPT_DIRECTORY -ErrorAction Stop
Break
}
Finally
{
"end of step 5"
#STEP 6
Try
{
"Attempting to remove original file from One"
Remove-Item $IPS_OUTPUT_DIRECTORY + "*.ready_to_archive" -force #I need to specify the specific file not just any ready_to_archive file!!!!
}
Catch [system.exception]
{
$ErrorMessage = $_.Exception.Message
$FailedItem = $_.Exception.ItemName
"Error in Step 6: $FailedItem : $ErrorMessage"
Set-Location -Path $SCRIPT_DIRECTORY -ErrorAction Stop
Break
}
Finally
{
"end of step 6"
}
}
}
}
}
"END OF SCRIPT"
}
And here is a screenshot of the execution: (Ok I do not have enough rep points to add a screenshot so here is a txt dump of the output) ...
PS D:\Temp\archive> .\archive.ps1
Attempting to rename file from .xml to .archive
end of step 1
Attempting to copy ready_to_archive file from One to Two
end of step 2
Attempting to rename files from .ready_to_archive to .archive
end of step 3
Attempting to copy archive file from one to three
end of step 4
Attempting to rename file from .ready_to_archive to .xml
end of step 5
Attempting to remove original file from One
Error in Step 6: : A positional parameter cannot be found that accepts argument '+'.
end of step 6
PS D:\Temp\archive>
The only thing that actually works in this script is that the .xml file in folder 'one' is properly renamed to .ready_to_archive' but nothing else happens.
The error is from Remove-Item $IPS_OUTPUT_DIRECTORY + "*.ready_to_archive" -force.
Use this code: Remove-Item -Path "$($IPS_OUTPUT_DIRECTORY)*.ready_to_archive" -force.