-ErrorAction with Get-ADComputer not hiding errors - powershell

I'm just beginning to dip into PowerShell with AD so I apologize if the question seems obvious.
I am trying to check if which of the devices provided in a list are in AD. So far I've used the code from:
Powershell - verify object exists in AD
It works just fine, but the "-ErrorAction SilentlyContinue" does not actually suppress the error messages. I get the below:
Get-ADComputer : Cannot find an object with identity: 'test' under:
'DC=test,DC=dom'.
At C:\Users\testaccount\Desktop\test.ps1:171
char:19
+ if (#(Get-ADComputer $target -ErrorAction SilentlyContinue).Count)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (test:ADComputer) [Get-ADComputer], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADComputer
The code I am using is as follows:
foreach ($target in $devicelist)
{
if (#(Get-ADComputer $target -ErrorAction SilentlyContinue).Count)
{
$existingdevices += $target
}
else
{
#display error notification
}
}
What I am looking for is suppressing the error message to no longer show in console - for the script to actually silently continue on error.
Any and all help will be appreciated!

So lets talk about whats happening.
There are 2 types of errors Terminating and Non-Terminating.
Terminating stops the execution of a command and throws an Exception. A non-terminating returns a write-out error message.
-ErrorAction takes care of Non-Terminating errors
Try{}Catch{} takes care of Terminating errors.
In your case
foreach ($target in $devicelist)
{
try{
if (#(Get-ADComputer $target -ErrorAction SilentlyContinue).Count)
{
$existingdevices += $target
}
else
{
#display non-terminating error notification
}
}catch{
#display Terminating error notification
}
}

Use output redirection: 2> $Null
Get-ADComputer -Server BlahBlah -Identity ComputerThatDoesntExist 2> $Null

Related

If statement in PowerShell dependant on if RPC Server is unavailable

I'm writing a script in PowerShell that ideally would gather information from another server. If it's not able to reach that server, I want to prompt it to have the user manually enter the information. I know how to do all of these, but I'm getting hung up when the RPC Server is unavailable. I will also say that I know how to fix the error when it occurs, but I do not want to rely on my end users to have to go in and fix this.
As an example, if I run:
Get-WmiObject Win32_ComputerSystem -Computer 10.5.21.94
the result I get back is:
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:1 char:1
+ Get-WmiObject Win32_ComputerSystem -Computer 10.5.21.94
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject],
COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I'm trying to find a way to write an if statement that will check to see if the RPC server is available or not, but I'm not sure what to check in order to create a true/false variable. And again, I'm not really looking for someone to tell me how to write the if statement, I'm just trying to figure out any query I can run to determine if I can properly connect to this server and get a result back that can tell me to continue on or not.
An easy way to get around it in an if-statement is just to ignore potential errormessages with Erroraction and use a -not statement to check whether it can reach the destination or not and then append a $false value to a variable if it can't.
See the below example.
$status = ""
if (!(Get-WmiObject Win32_ComputerSystem -ComputerName 10.5.21.94 -ErrorAction SilentlyContinue)) {
Write-Host "Server is unavailable!"
$status += $false
}
else {
Get-WmiObject Win32_ComputerSystem -ComputerName 10.5.21.94
}
if ($status -eq $false) {
$Server = Read-Host "Please enter the destionation"
Get-WmiObject Win32_ComputerSystem -ComputerName $Server
}
There was a suggestion for a Try/Catch block, but since this is not a terminating error, it didn't work initially. Then I found this:
Try/catch does not seem to have an effect
There is an answer in there about making all errors terminating:
try {
$ErrorActionPreference = "Stop"; #Make all errors terminating
get-item filethatdoesntexist; # normally non-terminating
write-host "You won't hit me";
} catch{
Write-Host "Caught the exception";
Write-Host $Error[0].Exception;
}finally{
$ErrorActionPreference = "Continue"; #Reset the error action pref to default
}
This gave me exactly what I was looking for!

Handling Domain Join Errors

I have created a basic script to add a PC to the domain. Although this works there is room for error, and I want to put in some error handling.
do {
Add-Computer -DomainName $Domain -Credential(get-credential)
} while (!$?)
Using !$? runs the while loop while the last command is not successful.
However, there are various errors that return. Whether the PC is off the network, incorrect user ID or password, or domain specification, I want to be able to handle those errors and display something meaningful.
One of the errors returned
Add-Computer : This command cannot be executed on target computer('PCName') due to
following error: Logon failure: unknown user name or bad password.
At line:1 char:13
+ Add-Computer <<<< -DomainName $Domain -Credential(get-credential);
+ CategoryInfo : InvalidOperation: (PCNAME:String) [Add-Computer], InvalidOperationException
+ FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.AddComputerCommand
Working with error handlers in lets say VBA, an error ID is given, and using if statements you can do something with it.
The FullyQualifiedErrorID in the error above is the same across all errors received for different reasons, so I do not believe I can use that.
How can I capture the specific error "Logon failure: unknown user name or bad password." or other errors and display a meaningful message so the admin can take appropriate action?
If nothing else you should be able to use the error message for distinguishing between errors:
do {
$joined = $true
$cred = Get-Credential
try {
Add-Computer -DomainName $Domain -Credential $cred -ErrorAction Stop
} catch {
$joined = $false
switch -regex ($_.Exception.Message) {
'.*unknown user name.*' { ... }
'.*domain does not exist.*' { ... }
...
default { 'Unexpected error' }
}
}
} until ($joined)
Note that you'll need to set the error action to Stop (-ErrorAction Stop), because otherwise the errors would be non-terminating and thus not catchable.
Use it with the -ErrorAction parameter:
Add-Computer ... -ErrorAction SilentlyContinue -ErrorVariable computerError
The ErrorVariable is an array, so the resulting error will be stored in:
$computerError[0]
To use the same variable over and over again, use a + in front of the var name:
Add-Computer -ErrorVariable +manyErrors
And the last error will always be:
$manyErrors[$manyerrors.count - 1]
To get the last error code if it has a corresponding Win32 error code then run the following
$manyErrors[$manyerrors.count - 1].Exception.InnerException.NativeErrorCode
And then if you gather the potential error codes you could do the following
if ($manyErrors[$manyerrors.count - 1].Exception.InnerException.NativeErrorCode -eq 1)
{
Write-Host error happened
}
elseif ($manyErrors[$manyerrors.count - 1].Exception.InnerException.NativeErrorCode -eq 2)
Write-Host other error happened
}

Catching Get-EventLog errors

I'm writing a simple script to parse some event logs but I need to silence some errors for times when there are no results, or if the instanceid is invalid:
PS C:\> get-eventlog Application -instanceid 1111
Get-EventLog : No matches found
At line:1 char:13
+ get-eventlog <<<< Application -instanceid 1111
+ CategoryInfo : ObjectNotFound: (:) [Get-EventLog], ArgumentException
+ FullyQualifiedErrorId : GetEventLogNoEntriesFound,Microsoft.PowerShell.Commands.GetEventLogCommand
I can do that and silence it, but that would also silence other errors:
PS C:\> try { get-eventlog Application -instanceid 1111 -erroraction stop } catch { }
I tried this but it doesn't work:
PS C:\> try { get-eventlog Application -instanceid 1111 -erroraction stop } catch [ObjectNotFound] { }
Unable to find type [ObjectNotFound]: make sure that the assembly containing this type is loaded.
At line:1 char:91
+ try { get-eventlog Application -instanceid 1111 -erroraction stop } catch [ObjectNotFound] <<<< { }
+ CategoryInfo : InvalidOperation: (ObjectNotFound:String) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
you can use -ErrorAction SilentlyContinue and check your $error variable after it,
$error[0]
It will always contains the last error object.
By no means the only option but you could try something like this:
$result = get-eventlog Application -instanceid 1111 -erroraction silentlycontinue
if($result){
Write-Host "Found some."
} else{
Write-Host "wah wah wah waaaah... you know like the trombone sound"
}
Once again I dont read a post fully. To make better on my answer I offer up this which might help your try block woes
try {
get-eventlog Application -instanceid 1111 -ErrorAction Stop
} Catch [Exception]{
$theError = $_
Switch($theError .Exception.GetType().FullName){
System.InvalidOperationException{Write-Host "This happened: $($theError.Exception.Message)"}
System.ArgumentException {Write-Host "This happened: $($theError.Exception.Message)"}
default{"Something else happened: $($theError.Exception.GetType().FullName)"}
}
}
Use -Stop to create a terminating error. Capture any exceptions and put the error object into variable so it can be used in other scopes later. Get the exception name and use a switch statement on it to determine appropriate action. In your case of "No matches found" that throws a [System.ArgumentException] which you can tell from looking at the value of $_.Exception.GetType().FullName. Capture the specific errors in the switch statement and if you have not already caught a particular exception before you can see the details in default.
For what its worth [System.InvalidOperationException] occurred when I replaced "Application" in the cmdlet call to "Fizgig"
you should try following syntax to get your error while not stopping script execution :
try
{
# check for eventLog
Get-EventLog -LogName "Application" -InstanceId 1111 -ErrorAction Stop
}
catch
{
# send error as ID
Write-Warning "Error -Message $($_.Exception.Message) -Line $($_.InvocationInfo.ScriptLineNumber) -Time $(Get-Date -Format 'HH.mm.ss.fff')"
}

How to prevent ManagementObjectNotFoundException from printing

I'm trying to test out a script that creates exchange mailboxes for existing users. At the end I want to have a little piece that tests and informs the user whether or not it was successful. What I have is below.
$mail = Get-Mailbox user#domain.com
$checkmail = #($mail).count
if($checkmail -eq 0)
{
write-host "Does not exist"
}
else
{
write-host "exists"
}
This actually works just fine, but when the object doesn't exist, it also spits out a huge Powershell error to boot. I just don't want that part to be there. I've tried a try/catch block on the whole thing, and it for some reason just ignored it. The error is as follows:
Get-Mailbox : The operation could not be performed because object 'user#domain.com' could not
be found on the domain controller 'domainnamehere'
+ $mail = Get-Mailbox user#domain.com
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-Mailbox], ManagementObjectNotFoundException
+ FullyQualifiedErrorID : 3AAE54AC,Microsoft.Exchange.Management.RecipientTasks.Getmailbox
Any help would be appreciated.
One thing you could do is set the -ErrorAction for Get-Mailbox
$mailbox = Get-Mailbox asdf#ba.net -ErrorAction SilentlyContinue
The error for that command will be surpressed from the console ( but still occur ). You will have to check the value of $mailbox in case it is empty with a simple If.
If($mailbox){
Write-Host "Good mailbox"
} Else {
Write-Host "Bad mailbox"
}
The try block might not have worked if the error was non-terminating. If you have a try block setting -ErrorAction Stop might have made that work as well.

Write custom error to log on RPC server unavailable

I want to output a custom error message to a log, when a GWMI query fails. I can catch the exception, but apparently only the last one, because the output in my error file only has the name of the last computer in the list. I am using a list of computers I know do not have WMI enabled. There should be an entry for each one.
I have a list of domain computers in a text file, each on a single line, no trailing characters. I loop through the file to get network information, using GWMI. Some of the computers do not have WMI enabled, and I want to know which ones. My current script just throws a:
gwmi : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:12 char:17
+ $base = gwmi win32_networkadapterconfiguration -computername $comp | whe ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
whenever it loops through a machine that does not have wmi enabled.
This does not identify the computer that threw the exception. What I would like is for every time the RPC server is unavailable... error is thrown, for a custom error message to be written to a log with the name of the computer that threw the exception.
My script:
$computers = Get-Content -path f:\scripts\docs\computer_list_test.txt
if (F:\scripts\wmi_mac_output.txt){
rm F:\scripts\wmi_mac_output.txt
}
foreach ($comp in $computers) {
try
{
$base = gwmi win32_networkadapterconfiguration -computername $comp -ErrorAction Stop | where {$_.dnsdomain -eq "mydomain.com"}
$machine = $base.DNSHostName
$mac = $base.MACAddress
$ip = $base.IPAddress
"<COMPUTER>`n`tname: $machine`n`tMAC: $mac`n`tIP: $ip`n</COMPUTER>" | Out-File F:\scripts\wmi_mac_output.txt
}
catch [Exception]
{
if ($_.Exception.GetType().Name -eq "COMException")
{
"$comp has no winrm" > f:\scripts\docs\error.txt
}
}
}
Thank you.
I can catch the exception, but apparently only the last one, because the output in my error file only has the name of the last computer in the list.
The issue is that the error.txt is being overwritten instead of appended.
"$comp has no winrm" > f:\scripts\docs\error.txt
Change to:
"$comp has no winrm" >> f:\scripts\docs\error.txt