Handle Directory Exists Exception - powershell

I am new to PowerShell. I have a piece of code which checks whether a folder "ilalog" exists or not. When I run this script first time, it is checking for the folder "ilalog",if it does not exist,it is creating. When I run the script second time. I receive the error below:
An item with the specified name D:\Temp\ilalog already exists
"FullyQualifiedErrorId :
DirectoryExist,Microsoft.PowerShell.Commands.NewItemCommand".
how to handle this exception
I have tried using try and Catch block
$rgflder="ilalog"
[bool]$checkrg=Test-Path D:\Gdump\$rgfolder -PathType Any
if ( $checkrg -eq $False)
{
try{
New-Item -Path "D:\Gdump" -Name "$rgflder" -ItemType "directory"
}
catch [System.IO.IOException]
{
if ($_.CategoryInfo.Category -eq $resExistErr) {Write-host "Dir Exist"}
}
}
else
{
Write-Output "Directory Exists"
}

If you want to continue processing your script while taking action based on an error type, a simple way is to just examine the $error variable. Using Trap may be an option as well.
$error.clear()
New-Item -Path "D:\Gdump" -Name "$rgflder" -ItemType "directory"
if ($error[0].Exception.GetType().Fullname -eq 'System.IO.IOException') {
"Dir Exists"
}
else {
"Dir was created"
}
If you want to use try-catch, you need to treat your non-terminating error as a terminating error to activate the catch block. You can do this with -ErrorAction Stop.
try {
New-Item -Path "D:\Gdump" -Name "$rgflder" -ItemType "directory" -ErrorAction Stop
}
catch [System.IO.IOException]
{
"Exception caught!"
}
Alternatively, you can manage this within your session by setting $ErrorActionPreference = 'Stop', which will apply to all commands within that session.
Keep in mind that the value passed to -ErrorAction overrides the setting in $ErrorActionPreference. Also, error action settings have no affect on terminating errors. So you cannot expect to set -ErrorAction Continue and have code continue processing on a terminating error.
Many commands return objects that may or may not be terminating errors. You will find more success explicitly, specifying when you want to throw a terminating error.
You can read more about error action preference at About Common Parameters. I actually like Everything About Exceptions for exception handling in PowerShell.

Why not simply do like below?
$rgflder="ilalog"
# combine the path and foldername
$rgPath = Join-Path -Path 'D:\Gdump' -ChildPath $rgflder
# test if the folder already exists
if (Test-Path $rgPath -PathType Container) {
Write-Output "Directory Exists"
}
else {
# if not, create the new folder
try {
$null = New-Item -Path $rgPath -ItemType Directory -ErrorAction Stop
Write-Output "Created directory '$rgPath'"
}
catch {
# something terrible happened..
Write-Error "Error creating folder '$rgPath': $($_.Exception.Message)"
}
}

Related

Try Catch Query Powershell

Can anyone advise why when I run this script I still get a generic error generated by powershell? It is nested in an IF statement originally.
try {
Remove-Item -Path "C:\Users$env:USERNAME\AppData\Local\Microsoft\Outlook" -Force -Recurse | Out-Null
} catch { "Appdata Cache does not exist!"
}
catch only works on terminating errors. So you’ll have to change your try statement to. Also you’re missing a “\” in your path
Try{
Remove-Item C:\Users\$env:USERNAME\AppData\Local\Microsoft\Outlook" -Force -Recurse -ErrorAction Stop
}Catch{
“Appdata cache doesn’t exist”
}
Also Remove-Item doesn’t return an object so you don’t need to redirect it to null

Directory creation failure and no errors

I made a function and I thought it worked well. In my primary script I am importing the function and then calling it. The idea of the function is simply to make a filename with a path.
At the end of the function I added a portion that would check if the directory exists and if not create it.
Here are the problems.
I get no errors.
The directory is not always created`.
When the primary script runs and attempts to export the csv it doesn't because the directory doesn't exist.
3a) if I create the directory everything works.
The folder it tries to create is "C:\Reports" but I am an admin on the computer and I understand it should be in special folders. I suppose I can force that if you folks want. But I would think I would get an error if the directory could not create as written below.
Portion of the function that should be working.
$ProcessError = $null
IF (!(test-path $DirectoryName)) {
New-Item -Path $DirectoryName -ItemType Directory -ErrorAction SilentlyContinue -ErrorVariable ProcessError -Force
If ($ProcessError) {
Write-Warning "Problem trying to create $DirectoryName."
}
Return [string]$FullPath
}
This is the primary call to the function and what is strange is I get no error here as well in section 2 primary below!!
section 1 primary
If ($SimChange -eq $True) {
$ResultFileName = MRNAP -ReportName "ExampleGoogleLicenseReport" -Move -JustDate
}
Else {
$ResultFileName = MRNAP -ReportName "GoogleLicenseReport" -Move -JustDate
}
Section 2 primary
$ProcessError = $null
$Results | Export-Csv $ResultFileName -NoTypeInformation -ErrorVariable ProcessError -ErrorAction SilentlyContinue
If ($ProcessError) {
Write-Warning "Unable to save report output to $ResultFileName"
}
url to function that creates the filename.
https://github.com/dcazman/MRNAP/blob/main/MRNAP.ps1
I find this all very frustrating and Section 2 primary above. Should be giving me that warning as written....I thought.
In the comments there is chat about a bug and using try catch. Additionally, we have talked about this problem on stack before with
Create directory if it does not exist
and
Function return value in PowerShell
What I did for now that works.
IF (!(test-path $DirectoryName)) {
$Dircreate = New-Item -ItemType Directory -Force -Path $($DirectoryName.Substring(0, 3)) -Name $($DirectoryName.Substring(3)) -ErrorAction SilentlyContinue -ErrorVariable ProcessError | Out-Null
If ($ProcessError) {
Write-Warning "Problem trying to create $DirectoryName."
[bool]$Created = $False
}
Else {
[bool]$Created = $true
}
}
If ($Created) {
If ($FullPath -as [string]) {
Return [string]$FullPath
}
Else {
Return [string]$FullPath[1]
}
}
This above doesn't use a try catch but I will give that a shot later.
For some bug reason creating the directory was changing $fullpath from a string to an array and that is why the test above works using the -as [string]

Powershell Scripting Variables

I have set some variables in PowerShell. The variables are created at the beginning of my script. However, the values for the variables are being executed at start which in turns gives and error message. Ex:
$checker = get-item -path C:\users\user\desktop\Foldername
$finder = Test-path -Path $checker
if($finder -eq $finder )
{
}
Else
{
Create-Item -Path C:/users/user/desktop -name "Foldername" -itemtype Directory
}
I do know that if I run this it will give me an error because the directory never existed and I can just change the variable order to avoid errors.
My question is that this script is going to be more lines of code than this and I would have to create the variable right when its needed to avoid errors.
How can I use these variables like a regular programming language where the variables are ignored until called upon.
Using Get-Item and checking with Test-Path afterwards is not a good design. Two better ways:
Use Get-Item only and check for $null to check for its existence:
$checker = Get-Item -Path C:\users\user\desktop\Foldername -ErrorAction SilentlyContinue
if ($checker) {
# do something with the existing folder
} else {
Create-Item -Path C:/users/user/desktop -Name "Foldername" -ItemType Directory
}
Use Test-Path only to check for its existence:
if (Test-Path -Path C:\users\user\desktop\Foldername) {
# do something with the existing folder
} else {
Create-Item -Path C:/users/user/desktop -Name "Foldername" -ItemType Directory
}

PowerShell Verbose-Parameter

I have a few questions about the verbose-parameter.
Example script:
try {
New-Item -Path "C:\Test.txt" -ItemType "File" -ErrorAction Stop -Verbose
}
catch {
Write-Host $Error[0]
}
Output:
VERBOSE: Execute the "Create file" operation for the target "Target: C:\Test.txt".
Access to the path "C: \ Test.txt" was denied.
How do I save the verbose message in a variable?
Is it possible to edit the verbose message automatically generated by PowerShell before saving it in a log file (add date and time)?
Example script (not working):
try {
New-Item -Path "C:\Test.txt" -ItemType "File" -ErrorAction Stop -Verbose *> $LogFile
}
catch {
Write-Host $Error[0]
}
Are there better suggestions to write a "success" log file than with the parameter verbose and without having to write it manually?
Thank you!
You can assign the verbose output to a variable if you merge the Verbose stream into standard output stream (4>&1):
$output = New-Item "C:\Test.txt" -ItemType "File" -ErrorAction Stop -Verbose 4>&1
Since New-Item also returns the newly created file, you'll want to split the output into verbose vs normal again:
$verboseOutput,$normalOutput = $output.Where({$_ -is [System.Management.Automation.VerboseRecord]}, 'Split')
And now you can prepend timestamps to the records in $verboseOutput before writing them to disk

How handle errors with copy-item

I have a backup script that copies several directories of files to a backup location. Unfortunately, not all of the files in the folder are accessible. What the history is, is that they were archived, and what's left is a filename with a grey x on it. When I try to copy it, I get the following message:
Copy-Item : Access to the path 'E:\Backup\Loc\DO\zOLD_Under Review for NOT USED_keep for now\2006-06\N.doc' is denied.
At C:\Users\me\Documents\powershellFiles\Backup.ps1:13 char:4
+ Copy-Item -Path $SourcePath -Destination $DestinationPath -Force - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (N.doc:FileInfo) [Copy-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : CopyDirectoryInfoItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand
Yes, it's complaining at the To Location, not the From Location. I have opened up the directory/files so it's not read only, but still get this.
Also, getting through these copy errors takes a really long time. If I could avoid trying to copy these files in the first place, it would be much quicker. There's probably 200 of these files that are archived.
However, I'm copying the folder, not the filenames individually. There are ones that aren't archived in that folder. There isn't a plan to clean them up. I'm trying to identify when an error occurs, but it's only hitting my breakpoint if $error.Exception -ne $null statement after it writes the errors to screen and takes forever failing (see comment).
Any idea how I can either filter out the ones that are archived, or grab them and check them against an array or list so I don't get an error message? I haven't figured out how to find them as they happen since it's copying the entire folder.
I was looking at error checking during copy-item but I don't see how to apply that to my issue.
This is the copy method:
function CopyFileToFolderUNC($SourcePath, $DestinationPath){
if(-Not (Test-Path $SourcePath))
{
$global:ErrorStrings.Add("Exception: No such path, $SourcePath;; ")
write-output "++ Error: An error occured during copy operation. No such path, $SourcePath ++"
}
Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -Recurse -errorVariable errors
foreach($error in $errors)
{
if ($error.Exception -ne $null)
{
$global:ErrorStrings.Add("Exception: $($error.Exception);; ")
write-output "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++" #this breakpoint is hit after giving errors on screen and taking a long time/failing to copy files it can't reach
}
write-output "Error: An error occured during copy operation. Exception: $($error.Exception)"
}
}
This is my latest try based on what was suggested by #theo, but it's trying to copy files I hadn't tested attributes for a file I can copy, just the dir above it:
function CopyFileToFolderUNC($SourcePath, $DestinationPath, $exclude){
if(-Not (Test-Path $SourcePath )) #-PathType Container
{
$global:ErrorStrings.Add("Exception: No such path, $SourcePath;; ")
write-output "++ Error: An error occured during copy operation. No such path, $SourcePath ++"
}
#$tempFileName = [System.IO.Path]::GetFileName($SourcePath)
#$tempDestFileNamePath = "$DestinationPath\$tempFileName"
Get-ChildItem -Path $SourcePath -Recurse -Force | ForEach {$_} {
#test if maybe we are dealing with an off-line file here
#or use the enum name 'Offline'
# or use the numeric value: 4096
#$oldAttribs = $null
$attr = $_.Attributes.value__
write-output "++ $_ $attr ++"
if (($_.Attributes -eq [System.IO.FileAttributes]::Offline) -or ($_.Attributes.value__ -eq "4096")) {
$_.Attributes=[System.IO.FileAttributes]::Normal
#$oldAttribs = $_.Attributes
#make it a 'normal' file with only the Archive bit set
#$_.Attributes = [System.IO.FileAttributes]::Archive
#log that the file was an issue and copy the other ones
$global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. Offline. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, Offline $_ ++"
} #if
elseif(($_.Attributes -eq [System.IO.Fileattributes]::Archive) -or ($_.Attributes.value__ -eq "32")) {
$global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. Archive. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, Archive $_ ++"
} #elseif
elseif(($_.Attributes -eq [System.IO.Fileattributes]::SparseFile) -or ($_.Attributes.value__ -eq "512")) {
$global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. SparseFile. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, SparseFile $_ ++"
} #elseif
elseif(($_.Attributes -eq [System.IO.Fileattributes]::ReparsePoint) -or ($_.Attributes.value__ -eq "1024")) {
$global:ErrorStrings.Add("Found offline file in backup dir, $_. Logging info and not copying this file. ReparsePoint. Please investigate.;; ")
write-output "++ Error: An error occured during copy operation. No such path or file, ReparsePoint $_ ++"
} #elseif
else {
#the file is not or no longer off-line, so proceed with the copy
$_ | Copy-Item -Destination $DestinationPath -Force -Recurse -ErrorVariable errors
foreach($error in $errors)
{
if ($error.Exception -ne $null)
{
$global:ErrorStrings.Add("Exception: $($error.Exception);; ")
write-output "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++"
}
write-output "Error: An error occured during copy operation. Exception: $($error.Exception)"
}
} #else
#if ($oldAttribs) {
# $_.Attributes = $oldAttribs
#}
} #Get-ChildItem
For example, I'm testing a dir at \\drive\folder\Forms\C Forms\ and it says it's a good attribute "16", but there's a file in that dir that the copy is trying to copy over to my dest dir and I'm seeing it has this for attributes: file.pdf Archive, SparseFile, ReparsePoint, Offline. But I'm not testing that file, the last thing I tested attributes for was the dir it's in.
To me it looks like the files you describe are Off-line files.
In your function you can test if that is the case using something like this:
function CopyFileToFolderUNC($SourcePath, $DestinationPath){
if(-Not (Test-Path $SourcePath)) {
$global:ErrorStrings.Add("Exception: No such path, $SourcePath;; ")
Write-Output "++ Error: An error occured during copy operation. No such path, $SourcePath ++"
}
# test if maybe we are dealing with an off-line file here
if ((Get-Item -Path $SourcePath).Attributes -band 4096) { # or use the enum name 'Offline'
# or use .Net:
# [System.IO.File]::GetAttributes($SourcePath) -band 4096
Write-Output "Did not copy: File '$SourcePath' is currently off-line. "
}
else {
# the file is not off-line, so proceed with the copy
Copy-Item -Path $SourcePath -Destination $DestinationPath -Force -Recurse -errorVariable errors
foreach($error in $errors) {
if ($error.Exception) {
$global:ErrorStrings.Add("Exception: $($error.Exception);; ")
Write-Output "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++" #this breakpoint is hit after giving errors on screen and taking a long time/failing to copy files it can't reach
}
Write-Output "Error: An error occured during copy operation. Exception: $($error.Exception)"
}
}
}
EDIT
From your comment I understand the function was not meant for a single file, but for all files found in a directory named $SourcePath.
In that case, here's an updated function that should do the trick:
function CopyFileToFolderUNC($SourcePath, $DestinationPath){
if(-Not (Test-Path $SourcePath -PathType Container)) {
$global:ErrorStrings.Add("Exception: No such path '$SourcePath'")
Write-Output "++ Error: An error occured during copy operation. No such path '$SourcePath' ++"
}
Get-ChildItem -Path $SourcePath -File | ForEach-Object {
# test if maybe we are dealing with an off-line file here
# or use the enum name 'Offline'
# or use the numeric value: 4096
if ($_.Attributes -band [System.IO.FileAttributes]::Offline) {
Write-Output "Did not copy: File '$($_.FullName)' is currently off-line."
}
else {
# the file is not off-line, so proceed with the copy
$_ | Copy-Item -Destination $DestinationPath -Force -Recurse -ErrorVariable errors
foreach($error in $errors) {
if ($error.Exception) {
$global:ErrorStrings.Add("Exception: $($error.Exception);; ")
Write-Output "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++"
}
Write-Output "Error: An error occured during copy operation. Exception: $($error.Exception)"
}
}
}
}
If by dealing with the files you mean you still want to copy them, use this instead:
function CopyFileToFolderUNC($SourcePath, $DestinationPath){
if(-Not (Test-Path $SourcePath -PathType Container)) {
$global:ErrorStrings.Add("Exception: No such path '$SourcePath'")
Write-Output "++ Error: An error occured during copy operation. No such path '$SourcePath' ++"
}
Get-ChildItem -Path $SourcePath -File | ForEach-Object {
# test if maybe we are dealing with an off-line file here
# or use the enum name 'Offline'
# or use the numeric value: 4096
$oldAttribs = $null
if ($_.Attributes -band [System.IO.FileAttributes]::Offline) {
$oldAttribs = $_.Attributes
# make it a 'normal' file with only the Archive bit set
$_.Attributes = [System.IO.FileAttributes]::Archive
}
# the file is not or no longer off-line, so proceed with the copy
$_ | Copy-Item -Destination $DestinationPath -Force -Recurse -ErrorVariable errors
foreach($error in $errors) {
if ($error.Exception) {
$global:ErrorStrings.Add("Exception: $($error.Exception);; ")
Write-Output "++ Error: An error occured during copy operation. Exception: $($error.Exception) ++"
}
Write-Output "Error: An error occured during copy operation. Exception: $($error.Exception)"
}
# if you want the attributes in the original file to be restored, use:
if ($oldAttribs) {
$_.Attributes = $oldAttribs
}
}
}
See FileAttributes Enum for all possible attribute values.
Hope that helps