How to handle multiple custom "Catch" error messages in Powershell? - 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.

Related

Powershell. Writing information to the log with and without an error

I'm trying to get powershell to write information about the execution of an operation to a log file. There is a folder with logs, it is necessary that the script delete files older than a certain number of days from the folder (implemented) and record information about the deletion of files or the absence of files in the folder (in case of an error when executing the script). Now the script writes information to the log about the absence of files, then if they are. Tell me what to do wrong? The text is as follows:
if ($error) {"No files found" *>> "D\TEST\Log $(gat-date -f dd-MM-yyy).txt"}
else {"Files deleted" *>> "D\TEST\Log $(gat-date -f dd-MM-yyy).txt"}
In principle $error is a automatic variable containg all errors occured within the current session. From my point of view its a better approach to use try/catch to handle errors. By doing so you can specify the error message to write to the logfile that matches the error, instead of writing the same error message for any kind of errors e.g.:
try {
#do someting
"Did something successfully" | set-content -path $logfilePath -Append -Force -Confirm:$false
}
Catch {
#gets executed if a terminating error occured
write-error "Failed to do something, Exception: $_"
"Failed to do something, Exception: $_" | set-content -path $logfilePath -Append
}
But back to your example, you could do:
$date = get-date -Format dd-MM-yy
$logFilePath = "D\TEST\Log_$date.txt"
If ($error){
"No files found" | set-content -path $logfilePath -Append -Force -Confirm:$false
}
Else {
"Files deleted" | set-content -path $logfilePath -Append -Force -Confirm:$false
}
ok based on the comment you could go this route:
$date14daysBack = (get-date).AddDays(-14)
$date = Get-Date -Format dd-MM-yyyy
$LogfilePath = "D:\TEST\Log_$date.txt"
try {
#try to map drive, if something goes wrong stop processing. You do not have to escape the $ if you use single quotes
New-PSDrive -Name "E" -PSProvider "FileSystem" -Root '\\Computer\D$\TEST' -Persist -ErrorAction:Stop
}
Catch {
"Failed to map drive '\\Computer\D$\TEST' - Exception $_" | Set-Content -Path $logfilePath -Append -Force
throw $_
}
try {
#I replaced forfiles and the delete operation with the powershell equivalent
$files2Remove = get-childitem -path E:\ -recurse | ?{$_.LastWriteTime -ge $date14daysBack}
$null = remove-item -Confirm:$false -Force -Path $files2remove.FullName -ErrorAction:stop
}
Catch {
"Failed to delete files: $($files2remove.FullName -join ',') - Exception: $_" | Set-Content -Path $logfilePath -Append -Force
}
#If files were found
If ($files2Remove){
"Files deleted, count: $($files2remove.count)" | Set-Content -Path $logfilePath -Append -Force
}
Else {
"No files found" | Set-Content -Path $logfilePath -Append -Force
}
Currently the code does not filter for '.' like in your sample: /m . - do I understand this correctly the filename is only a dot, nothing else?
The script has earned in the following form:
#cleaning up errors
$Error.Clear()
#days storage
$int = 11
#connecting a network drive
New-PSDrive -Name "E" -PSProvider "FileSystem" -Root "\\Computer\D`$\TEST" -Persist
#deleting files
FORFILES /p E:\ /s /m *.* /d -$int /c "CMD /c del /Q #FILE"
#disabling a network drive
Remove-PSDrive E
#recording information in the log
$date = Get-Date -Format dd-MM-yyyy
$LogfilePath = "D:\TEST\Log_$date.txt"
(Get-Date) >> $LogfilePath
if ($Error){"No files found" | Add-content -path $LogfilePath -Force -Confirm:$false}
Else {"Files deleted" | Add-Content -path $LogfilePath -Force -Confirm:$false}

Powershell Logging_Functions Causing Unexplained Error

I managed to get rid of the message by changing line 53 to :
New-Item -Path $sFullPath -ItemType File -Force
Which also allows removal of the Test-Path above this (thanks to -Force), But I don't understand why New-Item would try to create a new folder when -ItemType File has been specified, AND the path and name have both been provided ...
I am trying to use Logging_Functions.ps1 Module which I got here.
This is how I am calling it:
."\\DC1\NETLOGON\PSSubs\Logging_Functions.ps1"
Log-Start -LogPath "\\DC1\NETLOGON\PSSubs" -LogName "Test_Log.log" -ScriptVersion "1.5"
As per the documentation. However, when running the above I am seeing this annoying message:
New-Item : The file '\DC1\NETLOGON\PSSubs' already exists.
At \DC1\NETLOGON\PSSubs\Logging_Functions.ps1:53 char:5
+ New-Item -Path $LogPath -Value $LogName -ItemType File
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (\DC1\NETLOGON\PSSubs:String) [New-Item], IOException
+ FullyQualifiedErrorId : NewItemIOError,Microsoft.PowerShell.Commands.NewItemCommand
Even though this error appears, the file is created and I have no idea why it is complaining about the folder name, as line 53 is not asking it to create the folder.
When I run the exact same line inside the actual Logging_Functions.ps1 file, it works without error. I've included the Log-Start function below (which I altered slightly on line 53 to replace -Value with -Name as this seems correct):
Function Log-Start{
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)][string]$LogPath,
[Parameter(Mandatory=$true)][string]$LogName,
[Parameter(Mandatory=$true)][string]$ScriptVersion
)
Process{
$sFullPath = $LogPath + "\" + $LogName
#Check if file exists and delete if it does
If((Test-Path -Path $sFullPath)){
Remove-Item -Path $sFullPath -Force
}
#Create file and start logging
New-Item -Path $LogPath -Name $LogName -ItemType File
Add-Content -Path $sFullPath -Value "***************************************************************************************************"
Add-Content -Path $sFullPath -Value "Started processing at [$([DateTime]::Now)]."
Add-Content -Path $sFullPath -Value "***************************************************************************************************"
Add-Content -Path $sFullPath -Value ""
Add-Content -Path $sFullPath -Value "Running script version [$ScriptVersion]."
Add-Content -Path $sFullPath -Value ""
Add-Content -Path $sFullPath -Value "***************************************************************************************************"
Add-Content -Path $sFullPath -Value ""
#Write to screen for debug mode
Write-Debug "***************************************************************************************************"
Write-Debug "Started processing at [$([DateTime]::Now)]."
Write-Debug "***************************************************************************************************"
Write-Debug ""
Write-Debug "Running script version [$ScriptVersion]."
Write-Debug ""
Write-Debug "***************************************************************************************************"
Write-Debug ""
}
}
Can anyone please help explain what the difference is here? Why would one way cause an error and not the other, when they are supposedly doing the exact same thing? Thanks!
You can change all of this:
#Check if file exists and delete if it does
If((Test-Path -Path $sFullPath)){
Remove-Item -Path $sFullPath -Force
}
#Create file and start logging
New-Item -Path $LogPath -Name $LogName -ItemType File
To the following one liner, as the -Force will overwrite any file that already exists:
New-Item -Path $sFullPath -ItemType File -Force

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).

COPY-ITEM Passthru not working when encountering error

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.