powershell error checking during file copy with recursion - powershell

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."
}
}

Related

How can I Completely Uninstalling OneDrive and delete OneDrive related Folders on C:\ Drive?

I'm working on removing bloatware that is preinstalled on a number of computers.
I've been able to create a small script to remove the items that are preinstalled from the Microsoft Store and one that uninstalls Teams completely.
However; I'm having some troubles creating a solid script to uninstall OneDrive completely.
So far I have the below:
#Instructions found on https://www.wintips.org/how-to-disable-uninstall-install-onedrive-in-windows-10-8-7/]
#Modified slightly for simplicity and to kill the OneDrive process before uninstallation of application
#To Kill OneDrive.exe process
taskkill /f /im OneDrive.exe
#To uninstall OneDrive if using 64-bit System:
C:\windows\SysWOW64\OneDriveSetup.exe /uninstall
#To uninstall Onedrive if using a 32-bit system:
C:\windows\System32\OneDriveSetup.exe /uninstall
#Added to Removes the OneDrive Folders that are on the laptop.
$dirpath = "C:\Users\$env:UserName\OneDrive"
$dirpath2 = "C:\Users\$env:UserName\OneDrive - CompanyName"
#conditional to delete OneDrive related folders of C Drive. This is where I run into trouble
if ((test-path -LiteralPath $dirpath) -or (test-path -LiteralPath $dirpath2)) {(remove-Item -LiteralPath $dirpath) -or (remove-Item -LiteralPath $dirpath2)}
#Remove-Item -LiteralPath "C:\Users\$env:UserName\OneDrive" -Force -Recurse
#Remove-Item -LiteralPath "C:\Users\$env:UserName\OneDrive - CompanyName" -Force -Recurse
exit
It seems that there might be a logic issue with my conditional statement. When I run this script it does delete both folders that I'm intending to delete, but it returns "False" instead of "True" as I would expect.
I think what is happening is that it is running the remove-Item -LiteralPath $dirpath portion before it is able to reach the logical operator. I'm under this impression, because if I use the -and operator it will only remove the first Folder "C:\Users\$env:UserName\OneDrive"
Any suggestions to resolve this issue or improve the script overall would be appreciated. Thank you.
You should use a foreach
$dirpaths = "C:\Users\$env:UserName\OneDrive", "C:\Users\$env:UserName\OneDrive - CompanyName"
Foreach ($dirpath in $dirpaths) {
if (test-path -LiteralPath $dirpath) {remove-Item -LiteralPath $dirpath}
}
if ((test-path -LiteralPath $dirpath) -or (test-path -LiteralPath $dirpath2)) {(remove-Item -LiteralPath $dirpath) -or (remove-Item -LiteralPath $dirpath2)}
That logic is broken.
Try this:
if (test-path -LiteralPath $dirpath) {
Remove-Item -LiteralPath $dirpath
}
elseif (test-path -LiteralPath $dirpath2){
remove-Item -LiteralPath $dirpath2
}
else {
Write-Error -Message "We ain't found shit!"
}
Lastly
You don't need to do any of that because Remove-Item does not stop if it cannot find a file/path/directory - it continues.
Remove-Item c:\thisisafakepath\, e:\anotherfakepath\, C:\Powershell\TestCSVs\out.csv -WhatIf -ErrorAction SilentlyContinue
Write-Host "Script continues..."
Outputs:
C:> . 'C:\Powershell\Scripts\trydelete.ps1'
What if: Performing the operation "Remove File" on target "C:\Powershell\TestCSVs\out.csv".
Script continues...

unblock-file can get rid of prompt warning when try to run ps1 file from internet machine

i want to rename photos based on exif data on my remote machine, the code is as follows:
Unblock-File -path ..\exif-datetaken.ps1
Get-ChildItem *.jpg | foreach {
#Write-Host "$_`t->`t" -ForegroundColor Cyan -NoNewLine
$date = (..\exif-datetaken.ps1 $_.FullName)
if ($date -eq $null) {
Write-Host '{ No ''Date Taken'' in Exif }' -ForegroundColor Cyan
return
}
$newName = $date.ToString('yyyy-MM-dd HH-mm-ss') + $_.extension
$newName = (Join-Path $_.DirectoryName $newName)
Write-Host $newName -ForegroundColor Cyan
mv $_ $newName
}
i use unblock-file to get rid of warning, as i need to click on button to confirm for each photo manually,
but i found unblock-file do not work, i still get that warning prompt,
is it the wrong way to do to resolve this problem ?
Almost any file you download from the web will have ADS (alternate date stream) attached which indicates that it came form the web, and should not be trusted.
You have to use Unblock-File to get rid of that ADS.
If you are doing this for lots of downloaded files, then you have to do that to all of them before take any other actions on them.
ForEach ($TargetPath in $TargetPaths)
{
$TargetPath
Get-ChildItem -Path $TargetPath -Recurse | Unblock-File
Start-Sleep -Seconds 1
}
# Your rename code here
If you are running into prompts, after any downloaded file, then you may need to implement the -Confirm or -Force switch as where prudent.
Unblock-File -Confirm:$false
Rename-Item -Confirm:$false
Unblock is really only needed for downloaded files.
If you are getting other prompts the some lock is on the file or a permission issue. Yet, since you are not showing the error, we are left to guess.

try/catch error handling

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"
}

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!