try/catch error handling - powershell

I'm trying to create a script to delete all files out of %temp%. It works but now I need to get rid of the errors. Below is what I have but I'm still getting errors. Any ideas?
try
{
Get-Childitem $Env:temp | Remove-Item -Recurse -Force
}
Catch
{
}

Lots of files in temp can be in use or otherwise inaccessible for removable as that is the scratch space for processes to leave data.
Most common cmdlets support -ErrorAction so that you don't have to the change the default one and risk missing an important error. In your case you can use ...
Get-Childitem $Env:temp | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Since you are not generating terminating errors which is what Try is for you can just remove the block entirely.
FWIW if you really do need try/catch make sure you use terminating errors
try{
Get-ChildItem $Env:temp | Remove-Item -Recurse -Force -ErrorAction Stop
} Catch{
# Handle Stuff
Write-Host "Removal not 100% successful"
}

Related

Hide output of -WhatIf parameter when using New-Item

I want to test if New-Item throws an error, for which i am using the -WhatIf parameter and catch the error if an error occurs. If no error occurs, i dont want the -WhatIf output in my console.
I tried the following, but the "WhatIf:"-Output still gets printed to the Powershell console:
New-Item -Path $Path -Name $Name -ItemType $ItemType -ErrorAction stop -WhatIf | Out-Null
I also tried to use $WhatIfPreference as in this StackOverflow answer, which had the same result.

How to wait for permission denied type erros over the network

In a script, I use Get-ChildItem -File -Recurse in order to check my permissions on subfolders. Then, I try to read the first character of every files. My goal is to catch Permission Denied type errors using $Error. It works well locally. But when I execute the script on a remote server with a UNC long path, the errors aren't generated. If I run manually the Get-ChildItem command just after the execution of the script, which is supposed to generate some errors, it display the files but does not generate errors. If I wait a few minutes and I run it again, I finally get the errors displayed.
Is there a way to wait for the errors to be generated?
Here is the specific part of my code which doesn't generate any error over the network:
# Check if the current item is a folder or a file
If($elem.Attributes -eq 'Directory')
{
# Get all child items of File type
$subElem = Get-ChildItem -LiteralPath $elem.FullName -File -Recurse -ErrorAction SilentlyContinue
# Parse subfolders and files to check permissions integrity. To generate an Permission Denied error, a file must be open
ForEach($subItem in $subElem)
{
# Read the first character of the current sub-item
Get-Content -LiteralPath $subItem.FullName -Encoding byte -TotalCount 1 -ErrorAction SilentlyContinue | Out-Null
}
}
Else
{
# Read the first character of the current element
Get-Content -LiteralPath $elem.FullName -Encoding byte -TotalCount 1 -ErrorAction SilentlyContinue | Out-Null
}
I finally found the solution myself.
In this script, I use the module NTFSSecurity (https://github.com/raandree/NTFSSecurity) in order to manage ACLs and inheritance. Over the network, it seems to be a bit slow.
Before the bit of code I shared above, I have a few lines which check and updates a bunch of ACLs over the network. As it takes some time, errors are only generated some time after. In this case, if the command encounter an error, it just continues but doesn't display or catch the error at the same time.
I used errors to detect items on which I had to recover the access. Now, I use another cmdlet coming with the NTFSSecurity module, Get-NTFSEffectiveAccess.
I wrote a little function which does perfectly the trick:
Function Check-MyAccess([String]$Path)
{
# Get effective permissions
$effectiveAccess = Get-NTFSEffectiveAccess -Path $Path -ErrorAction SilentlyContinue
# Check to be, at least, able to read the item
If(($effectiveAccess -eq $Null) -or ($effectiveAccess.AccessRights -Match 'Synchronize') -or ((($effectiveAccess.AccessRights -Like '*Read*') -or ($effectiveAccess.AccessRights -Like '*Modify*') -and ($effectiveAccess.AccessControlType -Match 'Deny'))))
{
Return $False
}
Else
{
Return $True
}
}

UnauthorizedAccessException using Copy-Item on remote fileserver

I'm trying to copy about 10 folders each containing a ~3KB .txt file onto a remote fileshare with some seconds latency. I'm using Powershells Copy-Item like this:
try
{
Copy-Item -Path $source -Destination $destination -Recurse -ErrorAction Stop
}
catch
{
Write-Error $_.Exception.ToString()
}
The user running the script has read, write and execute permissions on the fileserver share and on the local source.
On first run, the destination folder is empty. Everything works fine.
On second run, the files and folders already exist. So before running the code above I first run a check using Test-Path and in case the folder exists a delete using Remove-Item like this:
try
{
if(Test-Path -Path $path -ErrorAction Stop)
{
Remove-Item -Recurse -Path $path -ErrorAction Stop
}
}
catch
{
Write-Error $_.Exception.ToString()
}
Nobody else edits those files. However, when running the script a dozent times, once in a while, for a reason I don't understand, i'm suddenly getting UnauthorizedAccessException errors for some of the folders while copying. The exact error is:
System.UnauthorizedAccessException: access denied
---> System.ComponentModel.Win32Exception: access denied
in Microsoft.PowerShell.Commands.FileSystemProvider.NativeDirectoryExists(String
path) in
System.Management.Automation.SessionStateInternal.IsItemContainer(CmdletProvider
providerInstance, String path, CmdletProviderContext context
please note: I'm getting those errors AFTER the deletion of the old files on the remote fileserver has compleated successfully.
This is a years old post but maybe one can benefit from that. You don't have to remove beforehand. You can just use -Force to override existing files.
try
{
Copy-Item -Path $source -Destination $destination -Recurse -ErrorAction Stop -Force
}
catch
{
Write-Error $_.Exception.ToString()
}
You may need try to run the command line as Administrator.
Masi, Powershell copy-item function is not really that great IMO. Why not use robocopy/Powershell hybrid here?
Example:
$source = "C:\temp"
$destination ="\\\RemoteServer\Temp"
robocopy $source $destination /s /mt:8

PowerShell - suppress Copy-Item 'Folder already exists' error

When I run a recursive Copy-Item from a folder that has sub folders to a new folder that contains the same sub folders as the original, it throws an error when the subfolders already exist.
How can I suppress this because it is a false negative and can make true failures harder to see?
Example:
Copy-Item "C:\realFolder\*" "C:\realFolder_new" -recurse
Copy-Item : Item with specified name C:\realFolder_new\subFolder already exists.
You could try capturing any errors that happen, and then decide whether you care about it or not:
Copy-Item "C:\realFolder\*" "C:\realFolder_new" -recurse -ErrorVariable capturedErrors -ErrorAction SilentlyContinue
$capturedErrors | foreach-object { if ($_ -notmatch "already exists") { write-error $_ } }
If you add -Force to your command it will overwrite the existing files and you won't see the error.
-Recurse will replace all items within each folder and all subfolders.
Copy-Item "C:\realFolder\*" "C:\realFolder_new" -Recurse -Force
You can set the error handling behavior to ignore using:
Copy-Item "C:\realFolder\*" "C:\realFolder_new" -recurse -ErrorAction SilentlyContinue
However this will also suppress errors you did want to know about!

powershell error checking during file copy with recursion

I have a program that copies folders and files recursively.
example:
Copy-Item -path "$folderA" -destination "$folderB" -recurse
Sometimes the files do not copy. Is there a way to "step inside the recursion" or a better way to do it, so I can enable some kind of error checking during the process rather than after wards. Possibly even do a Test-Path and prompt for a recopy?
You can. For example the following code snippet will actually copy and check each file for possible errors. You can also put your custom code at the beginning to check for some prerequisites:
get-childItem $source -filter *.* | foreach-object {
# here you can put your pre-copy tests...
copy-item $_.FullName -destination $target -errorAction SilentlyContinue -errorVariable errors
foreach($error in $errors)
{
if ($error.Exception -ne $null)
{
write-host -foregroundColor Red "Exception: $($error.Exception)"
}
write-host -foregroundColor Red "Error: An error occured during copy operation."
}
}