Unable to catch the error using try..catch in powershell - powershell

I am trying to catch the error if DL is not found. I have written the below code
try
{
Get-DistributionGroup -Identity "#AB-TestDL"|select ManagedBy -ErrorAction Stop
}
catch
{
if($Error[0] -match "couldn't be found on")
{
Write-Host "DL not found"
}
}
But when i run the code, it throws an error as "#AB-TestDL" couldn't be found on ...
Please help me capture this error. Thanks..

Try using the -ErrorAction Stop parameter on the Get-DistributionGroup -Identity "#AB-TestDL" CmdLet instead of Select-Object.
Select-Object can be used to create a new object but it isn't a error for the CmdLet when a property does not exist.
C:\> [PSCustomObject]#{ Test = 123 } | Select Test2 -ErrorAction Stop
Test2
-----
You can however make it work different (while i still suggest moving -ErrorAction Stop to the first CmdLet):
Set-StrictMode -Version 3
$Object = [PSCustomObject] #{
Test = 123
}
try {
$null = $Object.Test2
} catch {
throw "I don't extist and catch because of strictmode version 3"
}
Just an idea which came into my head. I actually never used strictmode this way.

Related

Powershell Send an email if success or if error

I have a script that looks at a CSV, filters the email address and performs some tasks:
foreach($aduser in (import-csv "C:\Temp\users.csv")){
Get-ADUser -filter "emailaddress -eq '$($aduser.emailaddress)'"|
Set-ADobject -ProtectedFromAccidentalDeletion $false
Get-ADUser -filter "emailaddress -eq '$($aduser.emailaddress)'" |
Set-ADUser -Enabled $false
Get-ADUser -filter "emailaddress -eq '$($aduser.emailaddress)'" |Move-ADObject -TargetPath "OU=Sep 20,OU=Disabled User Accounts,DC=Mydomain,DC=Domain,DC=uk" -PassThru | Disable-ADAccout}
If ($Error){
$FailMailParams = #{
To = 'Example#Gmail.com'
From = 'Example#Gmail.com'
SmtpServer = 'My.smtp.server'
Subject = 'Script Errors Out'
Body = 'There was an error with the script!!'
}
Send-MailMessage #FailMailParams
} else {
$SuccessMailParams = #{
To = 'Example#Gmail.com'
From = 'Example#gmail.com'
SmtpServer = 'My.smtp.server'
Subject = 'Success'
Body = 'The script ran successfully'
}
Send-MailMessage #SuccessMailParams
}
The problem I am facing is that even if the script runs successfully I still get the error email. If I change the code to if ($error -eq 1) and the code errors out I get the successful email. I think it's the If ($error) Variable causing the issue but I don't know what to use?
Error control can be handled in different ways. In your code, you have nothing that is indicating $error that should be set to 1.
I suggest you to find some examples of how to use the Try-Catch structure, as you will have to use it a lot in Powershell.
Find an example below which should be easy to adopt for your already made code:
try
{
# Code that performs the work intended
}
catch
{
# What to do in case any error is raised from above Try section
$error = 1
}
finally
{
# Here you post code that will be executed no matter errors happened or not,
# for example your email definition and execution.
}
Said this, your code has more room for improvement, but if you are starting with it, let's not focus on that part still.

Throw message not being shown

I'm trying to print my own error messages using throw. Consider this example:
$computerName = $env:COMPUTERNAME
$adsi = [adsi]("WinNT://$computerName")
if (!($adsi.Children.Find($userGroup, 'group')))
{
throw "User group not found."
}
If the user group is incorrect, this error message is shown:
Exception calling "Find" with "2" argument(s): The group name could not be found.
Is there a way to show my throw message, rather than the generic exception?
try this:
$computerName = $env:COMPUTERNAME
$adsi = [adsi]("WinNT://$computerName")
try {
$adsi.Children.Find($userGroup, 'group')
}
catch{
throw "User group not found."
}
[adsi] has a habit of throwing terminating errors. This happens with Get-ADUser as well. This is why capturing the error in a try/catch (like in whatever's answer) is necessary.
As an alternative you can check if the group exists by querying all local groups first and see if yours exists.
$computerName = $env:COMPUTERNAME
$adsi = [adsi]("WinNT://$computerName")
$localGroups = $adsi.children | Where-Object{$_.SchemaClassName -eq "Group"}
If($userGroup -notin $localGroups.Name){
throw "Your group is in another castle."
}
or a variant
if(-not ($adsi.children | Where-Object{$_.SchemaClassName -eq "Group" -and $_.Name -eq $userGroup})){
throw "Your group is in another castle."
}
Depending on where you are continuing with this code it might be advantageous to store this information once.

Catching error in Powershell and rewriting output

I'm trying to craft a script to resolve a long list of domain names to IP addresses. Some of these aren't defined and I need to catch the error and just return a "blank value." In the script below, I tried doing this using a basic If/Then, but I still get a wordy error (at the bottom) rather than just a blank value. Any ideas how to get around this? I really appreciate it!
----- SCRIPT -----
$names = Get-Content C:\temp\names.txt
ForEach ($name in $names) {
$ipAddress = [System.Net.Dns]::GetHostAddresses("$name")[0].IPAddressToString;
if ($ipAddress) {
Write-Host $name"-"$ipAddress
}
else {
Write-Host $name"-"
}
}
---- OUTPUT/ERROR ----
mydomain.com-1.2.3.4
yourdomain.com-4.3.2.1
Exception calling "GetHostAddresses" with "1" argument(s): "The requested name is valid, but no data of the requested type was found"
anotherdomain.com-5.5.5.5
---- What I'd Like to See -----
mydomain.com-1.2.3.4
yourdomain.com-4.3.2.1
NOTDEFINEDDOMAIN.tld-
anotherdomain.com-5.5.5.5
---- HERE'S THE SOLUTION THAT WORKED - THANK YOU!----
$names = Get-Content C:\temp\names.txt
ForEach ($name in $names) {
Try {
$ipAddress = [System.Net.Dns]::GetHostAddresses("$name")[0].IPAddressToString;
Write-Host $name"-"$ipAddress
}
Catch {
Write-Host $name"-"
}
}
Update of answer:
Catching error in Powershell and rewriting output
I need to catch the error and just return a "blank value
Use try/catch:
$names = Get-Content C:\temp\names.txt
ForEach ($name in $names)
{
try
{
$ipAddress = [System.Net.Dns]::GetHostAddresses("$name")[0].IPAddressToString;
Write-Host $name"-"$ipAddress
}
catch
{
Write-Host $name"-"
$_.Exception.Message # <- Check this to read and rewrite exception message
}
}
---- What I'd Like to See -----
If you want - you can manipulate of exception message like as string - this is line to get message in catch block:
$_.Exception.Message
Other way to get info about errors is $Error variable (it's the array/list of errors)...
More information:
http://vwiki.co.uk/Exceptions_and_Error_Handling_(PowerShell)
PowerShell Tutorial – Try Catch Finally and error handling in PowerShell
Using PowerShell $Error variable
about_Try_Catch_Finally
Update 2:
I forgot about one thing - try/catch working only with terminating errors.
I'm not sure about type of error in your case (because can't reproduce it), however sometimes you may want to add to your command:
-Error Stop

Catch error and restart the if statement

I have a powershell script that adds a computer to a domain. Sometimes, when I run the script I get the following error and when I run it for the second time it works.
How can I make the script to check if I get this error, and if so then to retry adding it to the domain?
I have read that it is hard to try and catch errors like that. Is that correct? Is there a better/different way to catch the error?
Thank you!
Code:
if ($localIpAddress -eq $newIP)
{ # Add the computer to the domain
write-host "Adding computer to my-domain.local.. "
Add-Computer -DomainName my-domain.local | out-null
} else {...}
Error:
This command cannot be executed on target computer('computer-name') due to following error: The specified domain either does not exist or could not be contacted.
You can use the built in $Error variable. Clear it before executing code, then test if the count is gt 0 for post error code.
$Error.Clear()
Add-Computer -DomainName my-domain.local | out-null
if($Error.count -gt 0){
Start-Sleep -seconds 5
Add-Computer -DomainName my-domain.local | out-null}
}
You could setup a function to call itself on the Catch. Something like:
function Add-ComputerToAD{
Param([String]$Domain="my-domain.local")
Try{
Add-Computer -DomainName $Domain | out-null
}
Catch{
Add-ComputerToAD
}
}
if ($localIpAddress -eq $newIP)
{ # Add the computer to the domain
write-host "Adding computer to my-domain.local.. "
Add-ComputerToAD
} else {...}
I haven't tried it to be honest, but I don't see why it wouldn't work. It is not specific to that error, so it'll infinitely loop on repeating errors (i.e. another computer with the same name exists in AD already, or you specify an invalid domain name).
Otherwise you could use a While loop. Something like
if ($localIpAddress -eq $newIP)
{ # Add the computer to the domain
write-host "Adding computer to my-domain.local.. "
While($Error[0].Exception -match "The specified domain either does not exist or could not be contacted"){
Add-Computer -DomainName my-domain.local | out-null
}
}

Try method in powershell

So I want to build a try method into my powershell script below. If I am denied access to a server, I want it to skip that server. Please help..
[code]$Computers = "server1", "server2"
Get-WmiObject Win32_LogicalMemoryConfiguration -Computer $Computers | Select-Object `
#{n='Server';e={ $_.__SERVER }}, `
#{n='Physical Memory';e={ "$('{0:N2}' -f ($_.TotalPhysicalMemory / 1024))mb" }}, `
#{n='Virtual Memory';e={ "$('{0:N2}' -f ($_.TotalPageFileSpace / 1024))mb" }} | `
Export-CSV "output.csv"[/code]
Try/catch functionality is built-into PowerShell 2.0 e.g.:
PS> try {$i = 0; 1/$i } catch { Write-Debug $_.Exception.Message }; 'moving on'
Attempted to divide by zero.
moving on
Just wrap you script in a similar try/catch. Note you could totally ignore the error by leaving the catch block empty catch { } but I would recommend at least spitting out the error info if your $DebugPreference is set to 'Continue'.
You can simply suppress errors with the ErrorAction parameter:
Get-WmiObject Win32_LogicalMemoryConfiguration -Computer $Computers -ErrorAction SilentlyContinue | ...
You can use trap to replicate Try/Catch, see http://huddledmasses.org/trap-exception-in-powershell/ or http://weblogs.asp.net/adweigert/archive/2007/10/10/powershell-try-catch-finally-comes-to-life.aspx for examples.
Use a filter function? Like this tutorial explains.
He passes a list of computers to his pipeline - first it tries to ping each one, and then only passes the ones that respond to the next command (reboot). You could customize this for whatever actual functionality you wanted.