COPY-ITEM Passthru not working when encountering error - powershell

Within ISE, I've tried both the below. Neither is working. The only way is to clear $error and test after the copy attempt. Any suggestions?
$cpy = Copy-Item -Path "D:\~a\2K0NVK0.xt" -Destination "D:\~Bkup-F\2K0NVK10.txt" -Force -passthru -ErrorAction SilentlyContinue
if($cpy){ $cpy # only displays on successful copy }
Try{
Copy-Item -Path "D:\~a\2K0NVK0.xt" -Destination "D:\~Bkup-F\2K0NVK10.txt" -Force -ErrorAction SilentlyContinue
} Catch { write-host "Hit a bug!" # not being displayed }

A try/catch only works when ErrorAction is set to Stop.

Related

PS Script to uninstall Firefox from multiple locations

I am working on creating a script to uninstall Firefox from multiple locations. I have a script that I've created and it works to an extent. I have made changes to my original script based on the answer below plus some other changes
$LocalUsers = (Get-ChildItem -Path "C:\Users").name
# Uninstalling from Program Files
if (Test-Path "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "${env:ProgramFiles(x86)}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
if (Test-Path "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "${env:ProgramFiles}\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
# Uninstalling for each user
ForEach ($LocalUser in $LocalUsers){
$Userpath = "C:\Users\" + $LocalUser
if (Test-Path "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe"){
Start-Process -FilePath "$Userpath\AppData\Local\Mozilla Firefox\uninstall\helper.exe" -ArgumentList '/S' -Verbose #-ErrorAction SilentlyContinue
}
Start-Sleep 20
# Remove shortcuts from appdata
Remove-Item -Path "$userpath\AppData\Local\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\AppData\LocalLow\Mozilla" -Force -Recurse -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
Remove-Item -Path "$userpath\desktop\firefox.lnk" -Force -Verbose #-ErrorAction SilentlyContinue
}
# Remove related registry keys
$pathToRemove = #(
'HKLM:\Software\Mozilla'
'HKLM:\SOFTWARE\mozilla.org'
'HKLM:\SOFTWARE\MozillaPlugins'
'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)
foreach($path in $pathToRemove) {
if(Test-Path $path) {
try {
Remove-Item $path -Recurse -Force -Verbose #-ErrorAction SilentlyContinue
}
catch {
Write-Warning $_.Exception.Message
}
}
}
The script has worked on some machines where it uninstalls the application, however, for others trace of it is being left behind in Windows Program Files. It is appearing as a dead link. I know it is a dead link because it is missing the Firefox logo. The strange thing is its points to %localappdata%\Mozilla Firefox\uninstall\helper.exe per the error
What the app should look like if installed (ignoring the version just a screenshot from online):
I'm assuming the problem is your chained if \ elseif \ else conditions, what could be happening is that if the first condition was $true you're only removing the first registry key and then exiting the chained conditions (this is by design):
# only results in 'hello if' and then exits the chained conditions
if($true) {
'hello if'
}
elseif($true) {
'hello elseif'
}
What you can do in this case is store all the paths in an array and then loop over them, testing if the path exists and, if it does, remove it:
$pathToRemove = #(
'HKLM:\Software\Mozilla'
'HKLM:\SOFTWARE\mozilla.org'
'HKLM:\SOFTWARE\MozillaPlugins'
'HKLM:\SOFTWARE\WOW6432Node\Mozilla'
'HKLM:\SOFTWARE\WOW6432Node\mozilla.org'
'HKLM:\SOFTWARE\WOW6432Node\MozillaPlugins'
'C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Firefox.lnk'
)
foreach($path in $pathToRemove) {
if(Test-Path $path) {
try {
Write-Verbose "Attempting to remove: $path" -Verbose
Remove-Item $path -Recurse -Force
Write-Verbose "Successfully removed: $path" -Verbose
}
catch {
Write-Warning $_.Exception.Message
}
}
}

How to handle multiple custom "Catch" error messages in Powershell?

I have 3 commands inside of a Try and I want custom Catch error messages for each of them in case of an error
e.g. If the first will fail then I would like to get the following message: "Error creating a directory!"
If the second will fail then: "Copy items failed"
If the third will fail then: "Content is not created"
How can I apply that?
Try{
New-Item -ItemType Directory -Name "Script" -Path "C:\Temp\" -Force
Copy-Item -Path $FilePath_ps1 -Destination C:\temp\script -Force
Set-Content -Value "test" -Path "C:\Temp\Script\test.txt" -Force
}
Catch{
" what code do I need here?"
}
Thanks for your help.
The answer zett42 gave is correct. Here is how you would implement it in your solution:
$errorAction = "STOP"
Try{
$errorMsg = "New-Item failed"
New-Item -ItemType Directory -Name "Script" -Path "C:\Temp\" -Force -ErrorAction $errorAction
$errorMsg = "Copy-Item failed"
Copy-Item -Path $FilePath_ps1 -Destination C:\temp\script -Force -ErrorAction $errorAction
$errorMsg = "Set-Content failed"
Set-Content -Value "test" -Path "C:\Temp\Script\test.txt" -Force -ErrorAction $errorAction
}Catch{
$errorMsg + " with error: $_"
}
The output would be for instance:
Copy-Item failed with error: Cannot bind argument to parameter 'Path'
because it is null.
I have added the ErrorAction to make sure it stops on every error right after the execution.

Error not being logged into output log file

I have the following script where, when the if(-not) condition is met, the log file is being generated but not error is being written in the log file.
I have very basic understanding of scripting languages and as a result cannot understand why nothing is being logged. Help is appreciated.
$resulterror = $error[0].exception.message
$BckDate = Get-Date -Format "ddMMyyyy"
$BckFolder = "<path>"+$BckDate
$log = "<path>"+$BckDate+".log"'
Copy-Item -Path $BckFolder -Destination <drive-letter> -ErrorAction silentlyContinue -recurse
if(-not $?) {$resulterror >> $log ; invoke-expression -Command "<path-of-ps-script-to-run>"}
else {"Backup "+$BckDate+" done successfully" >> $log}
The real paths have been hidden with the "path" in <> explaining that it is a directory path.
The path of the script triggered when the if(-not) condition is met is replaced with path-of-ps-script-to-run in <>. The <> are just brackets for the comments so don't confuse them with actual code symbols.
I would use the -ErrorVariable advanced parameter to store the error message in that variable and access it:
Copy-Item -Path $BckFolder -Destination <drive-letter> -ErrorAction silentlyContinue -recurse -ErrorVariable copyError
if($copyError)
{
$resulterror | Out-File -FilePath $log -Append
invoke-expression -Command "<path-of-ps-script-to-run>"
}
else
{
"Backup "+$BckDate+" done successfully" | Out-File -FilePath $log -Append
}
Your variable $resulterror is empty since you saved it at the very begining of the script and there were no errors at that time. Try to use explicit $error[0].exception.message instead of $resulterror on IF condition.
$BckDate = Get-Date -Format "ddMMyyyy"
$BckFolder = "<path>"+$BckDate
$log = "<path>"+$BckDate+".log"
Copy-Item -Path $BckFolder -Destination <drive-letter> -ErrorAction silentlyContinue -recurse
if(-not $?) {$error[0].exception.message >> $log ; invoke-expression -Command "<path-of-ps-script-to-run>"}
else {"Backup "+$BckDate+" done successfully" >> $log}

Capture the messages by cmdlets in PowerShell

I am running the below script. If the Copy-Item command is successfully completed, it does not show any messages such as how many files are copied. How do I capture this?
Note: I also need to capture the error message which the script is doing correctly.
$LogFile = "P:\users\Logname.log"
$msg = Copy-Item P:\Bkp_20130610\* P:\users -force -recurse -ErrorAction SilentlyContinue
if (-not $?)
{
msg1 = $Error[0].Exception.Message
Write-Host "Encountered error. Error Message is $msg1."
exit
}
$msg > $LogFile
Write-Host "Hello"
You can obtein a list of copied files in this way
$files = copy-item -path $from -destination $to -passthru
pipe it to | ? { -not $_.psiscontainer } if you are copying folder and you don't want them in the count
then use
$files.count
You can use the -Verbose switch with the Copy-Item cmdlet:
$msg=Copy-Item P:\Bkp_20130610\* P:\users -force -recurse -ErrorAction SilentlyContinue -Verbose

Exception Logging in PowerShell

I am currently having an issue logging exceptions in my PowerShell script. I am trying to copy a file to C:\Windows\System32 and I want to add an error line to my log file if it errors. I have tried this two ways so far.
Example 1:
$LogPath = "C:\Test.txt
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
Copy-Item $scriptPath\Devcon.exe C:\Windows\System32 -ErrorAction SilentlyContinue -ErrorVariable $Errors
Foreach($error in $Errors)
{
add-content -Path $LogPath -Value $($error.Exception) -Force
}
Example 2:
$LogPath = "C:\Test.txt
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
Try{
Copy-Item $scriptPath\Devcon.exe C:\Windows\System32
}
Catch [System.Exception]
{
add-content -Path $LogPath -Value "There was an error why trying to copy the file." -Force
add-content -Path $LogPath -Value $Error -Force
}
I can add items to the log file so I know it's not a permissions issue with the file. What am I missing?
I believe the error you are getting is non-terminating. This is why it does not end up in a catch block.
Try this instead of your Copy-Item line:
Copy-Item $scriptPath\Devcon.exe C:\Windows\System32 -ErrorAction Stop
Help on ErrorAction (MSDN).