Error handling - PowerShell script - powershell

I have the following powershell script that cycles through a list of hostnames and changes the DNS settings for the active interfaces:
$servers = Get-Content C:\users\kevin.todd\desktop\serverlist.txt
foreach($server in $servers)
{
Write-Host "Connect to $server..."
$nics = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server -ErrorAction Inquire | Where{$_.IPEnabled -eq "TRUE"}
$newDNS = "10.100.10.81","10.100.10.82"
foreach($nic in $nics)
{
Write-Host "`tExisting DNS Servers " $nic.DNSServerSearchOrder
$x = $nic.SetDNSServerSearchOrder($newDNS)
if($x.ReturnValue -eq 0)
{
Write-Host "`tSuccessfully Changed DNS Servers on " $server
}
else
{
Write-Host "`tFailed to Change DNS Servers on " $server
}
}
}
The problem is on some hosts I get the following error:
Get-WmiObject : The RPC server is unavailable. (Exception from
HRESULT: 0x800706BA) At C:\Documents and
Settings\user1\desktop\changednsserver.ps1:20 char:26
+ $nics = Get-WmiObject <<<< Win32_NetworkAdapterConfiguration
-ComputerName $server -ErrorAction Inquire | Where{ $_.IPEnabled -eq
"TRUE"}
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject],
COMException
+ FullyQualifiedErrorId :
GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Existing DNS Servers You cannot call a method on a null-valued
expression. At C:\Documents and
Settings\user1\desktop\changednsserver.ps1:30 char:42
+ $x = $nic.SetDNSServerSearchOrder <<<< ($newDNS)
+ CategoryInfo : InvalidOperation:
(SetDNSServerSearchOrder:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
And I'm asked the following question by Powershell:
The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
[Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help
(default is "Y"):
I would like the script to just answer A - Yes to all and continue running the script. The problem is it just halts the script until I manually enter "A". How can I have it automatically answer and continue?

Well the short answer is to not tell it to stop in the first place:
$nics = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server -ErrorAction Inquire | Where{$_.IPEnabled -eq "TRUE"}
Try:
$nics = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server -ErrorAction SilentlyContinue | Where{$_.IPEnabled -eq "TRUE"}

If you need to see where Errors occur, you have also a possibility to define an error variable using the switch
-ErrorVariable $<variable>
If errors occur in a foreach loop, the Error variable will be an array of error messages you can later analyze by querying the defined error variable with an array index echo $<EVariable>[<index>]
it would be something like echo $MyErrorArray[0] to get the first occurred error in that array.
An elegant way would be to have all that added to a textbox/combobox for log purposes but the coice of error handling ananalyzing is yours.

Related

How to create Powershell custom error output?

I want to make a small PS script that checks the status of a service logon account against a server list.
What i need to do is, if a server is down, it shows a custom error message that tells me which server from the list is offline, instead of the default bulky red error message.
Here is what i came up with so far.
This is the RPC error powershell shows if something wrong with a server.
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At V:\HRG01\MPE_HRG01_Information-Technology\Share\ITSS-Core\Icinga Monitor Software\Service Check\Get-Service Log On.ps1:1 char:1
+ Get-WmiObject win32_service -ComputerName (Get-Content -path ".\serverlist.txt") ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
PS Exception
PS c:\> $Error[0].Exception.GetType().FullName
System.Runtime.InteropServices.COMException
I searched on the internet for a solution, and this is what i came up with at last, but of course not working.
$servers= Get-Content -path ".\serverlist.txt"
foreach ($server in $servers)
{
try {
Get-WmiObject win32_service -ComputerName $server |
Where-Object {$_.Name -eq "icinga2"} -ErrorAction Continue |
format-list -Property PSComputerName,Name,StartName
}
catch [System.Runtime.InteropServices.COMException]
{
Write-Host "ERROR: $Server connection error"
}
}
Tee-Object .\Results.txt -Append
Read-Host -Prompt "Press Enter to exit"
I'd really appreciate your help
The error is on Get-WmiObject not Where-Object. And you have to set error action to stop to catch terminating error.
$servers= Get-Content -path ".\serverlist.txt"
foreach ($server in $servers)
{
try {
Get-WmiObject win32_service -ComputerName $server -ErrorAction Stop |
Where-Object {$_.Name -eq "icinga2"} |
format-list -Property PSComputerName,Name,StartName
}
catch [System.Runtime.InteropServices.COMException]
{
Write-Host "ERROR: $Server connection error"
}
}
Tee-Object .\Results.txt -Append
Read-Host -Prompt "Press Enter to exit"

Powershell Remote Stop and Disable Service

SO Braintrust. I'm not a Powershell person, but I'm working on it. Trying to address yet another zero-day, I'm trying to build a reuseable script to remotely stop and disable the affected service. It is based on a script I got from a Microsoft MVP at (ultimately): http://portal.sivarajan.com/2010/07/stopstart-or-enabledisable-service_26.html
The prompt for the service name was added by me as well as the output information (Write-host & Add-Content lines), so I could get a results summation (the output part's not working fully, but it's the least of my concerns at the moment.).
$output = "c:\scripts\results.csv"
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output Start"
cls
$Cred = Get-Credential
$service = Read-Host -Prompt 'Enter Service Name" '
Import-CSV C:\Scripts\computers.csv | %
{
$computer = $_.ComputerName
Write-Host "Working on $computer"
Add-content -path $output "$computer"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).stopservice()
Add-content -path $output " Stop - $result"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).ChangeStartMode("Disabled")
Add-content -path $output " Disable - $result"
}
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output End"
when I run it, I get an error on the computer name
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'.
The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Scripts\StopAndDisableService.ps1:12 char:54
+ ... result = (Get-WmiObject win32_service -computername $computer -filter ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Get-WmiObject : Cannot validate argument on parameter 'ComputerName'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Scripts\StopAndDisableService.ps1:14 char:54
+ ... result = (Get-WmiObject win32_service -computername $computer -filter ...
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-WmiObject], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Computer.csv contains one computer name per line, no punctuation, no FQDN, just the computer name
Special thanks to #Mathias R. Jessen for his help on this. Final working code. you will have to analyze the screen output to catch any errors and see which machines it did not catch due to being offline # time of running (some output file items have been commented out since they don't work as intended)
$output = "c:\scripts\results.csv"
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output Start"
cls
$Cred = Get-Credential
$service = Read-Host -Prompt 'Enter Service Name" '
Import-CSV C:\Scripts\computers.csv -Header ComputerName | % {
$computer = $_.ComputerName
Write-Host "Working on $computer"
Add-content -path $output "$computer"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).stopservice()
#Add-content -path $output " Stop - $result"
$result = (Get-WmiObject win32_service -computername $computer -filter "name='$service'" -Credential $cred).ChangeStartMode("Disabled")
#Add-content -path $output " Disable - $result"
}
Add-content -path $output "======================"
Add-content -path $output "StopAndDisableService Output End"
Analyzing results on the screen output, any results with
Just the machine name - means it's processed without error on that machine (success)
RPC server is unavailable means machine is offline
Cannot call a method on Null-Valued expression on line 12 or line 14 means that service doesn't exist on that machine
The results.csv output file will contain list of names of the machines this script was run against

Try-Catch: Why I'm still having uncaught errors? [duplicate]

This question already has an answer here:
try, catch doesent seem to work
(1 answer)
Closed 5 years ago.
I'm running the following script to identify whether there is drive Z: on a server. It contains try/catch, but I'm still getting "RPC-server is not available" errors like this:
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At C:\Users\vlitovch\Documents\Get-DriveZRemotely.ps1:19 char:26
+ ... $a = Get-WmiObject Win32_LogicalDisk -ComputerName $($comp.DNS ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
for the hosts that are listed in AD, but don't exist. Why? And on the top of this for these hosts I have "Cannot get disks" error message as well, so they don't fall into the catch block.
function Get-Moment {
Get-Date -Format 'MM/dd/yyyy HH:mm:ss'
}
#if (Test-Path -Path $logFile1) {Remove-Item -Path $logFile1 }
ipmo ActiveDirectory
$Servers = Get-ADComputer -Filter 'Name -like "*"' -SearchBase 'OU=Production,OU=Windows,OU=Servers,DC=contoso,DC=com'
foreach ($comp in $Servers) {
"INFO $(Get-Moment) Host:$($comp.DNSHostName)" | Write-Output
try {
$a = Get-WmiObject Win32_LogicalDisk -ComputerName $($comp.DNSHostName)
} catch {
"EROR $(Get-Moment) Host:$($comp.DNSHostName) Couldn't reach the host!" | Write-Output
continue
}
if ($a) {
$diskz = $false
foreach ($disk in $a) {
if ($disk.DeviceID -eq 'Z:') {$diskz = $true}
}
if (!$diskz) {
"EROR $(Get-Moment) Host:$($comp.DNSHostName) Disk Z: is absent." | Write-Output
}
} else {
"EROR $(Get-Moment) Host:$($comp.DNSHostName) Cannot get disks" | Write-Output
}
}
Some things in powershell throw non-terminating errors, which do not trigger on-error events.
adding -ErrorAction Stop to the end of the Get-WmiObject command will force it to become terminating, and thus trigger the try{}catch{} block.

Suppressing fatal error (access denied)

Going round in a circle here...
I'm trying to handle and continue from 'fatal errors' in scripts. I know the -EA silentlycontinue doesn't work but keep coming back to using foreach to get around it but solutions I find don't work for me for example and this is an example not what I'm trying to do...
The code:
get-content serverLists.txt |
foreach {get-wmiobject -computer $_ -query "Select * from win32_logicaldisk where drivetype=3"} |
Format-Table SystemName,DeviceID,Size,FreeSpace,VolumeName
Dies with:
get-wmiobject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:1 char:40
+ get-content serverLists.txt | foreach {get-wmiobject -computer $_ -query "Select ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
I want it to just continue, I've tried and investigated try/catch this just gives me the error in a readable format and stops, I've looked at ping/port check solutions but some servers are behind firewalls but certain ports are open etc I just want it to handle the fatal error and just carry on...
BTW this isn't a rights issue, it'll pass through a whole bunch of servers fine then the script will die on one and stop
try..catch should do what you want:
Get-Content serverLists.txt | % {
try {
gwmi -Computer $_ -Query "SELECT * FROM Win32_LogicalDisk WHERE DriveType=3"
} catch {}
} | Format-Table SystemName,DeviceID,Size,FreeSpace,VolumeName
or you could change $ErrorActionPreference:
$ErrorActionPreference = "SilentlyContinue"
Get-Content serverLists.txt | % {
gwmi -Computer $_ -Query "SELECT * FROM Win32_LogicalDisk WHERE DriveType=3"
} | Format-Table SystemName,DeviceID,Size,FreeSpace,VolumeName

Powershell: error handling with try and catch

I'm writing a script and want to control the errors. However im having trouble finding information on error handling using the try, catch. I want to catch the specific error (shown below) and then perform some actions and resume the code. What code is needed for this?
This is the code i am running and im entering in a invalid username when prompted.
Get-WMIObject Win32_Service -ComputerName localhost -Credential (Get-Credential)
Get-WmiObject : User credentials cannot be used for local connections
At C:\Users\alex.kelly\AppData\Local\Temp\a3f819b4-4321-4743-acb5-0183dff88462.ps1:2 char:16
+ Get-WMIObject <<<< Win32_Service -ComputerName localhost -Credential (Get-Credential)
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Can anyone figure out why I can't trap this exception when trying to trap exceptions of type [System.Management.ManagementException]?
PowerShell should be able to trap exceptions that match certain exception classes, but even though the exception class for below is [System.Management.ManagementException] it won't catch it in that catch block!
i.e:
Try
{
Get-WMIObject Win32_Service -ComputerName localhost -Credential (Get-Credential) -ErrorAction "Stop"
}
Catch [System.Management.ManagementException]
{
Write-Host "System.Management.ManagementException"
Write-Host $_
$_ | Select *
}
Catch [Exception]
{
Write-Host "Generic Exception"
Write-Host $_
$_ | Select *
}
Works the same as:
Try
{
Get-WMIObject Win32_Service -ComputerName localhost -Credential (Get-Credential) -ErrorAction "Stop"
}
Catch [Exception]
{
Write-Host "Generic Exception"
Write-Host $_
$_ | Select *
}
Doesn't make sense to me.
You could also catch the error in the Generic Exception catch block and then check the text to see if it matches the words you are after, but it is a bit dirty.
You must use -erroraction stop to enter into the try/catch or trap scriptblock. You can test this :
Clear-Host
$blGoOn = $true
while ($blGoOn)
{
trap
{
Write-Host $_.exception.message
continue
}
Get-WMIObject Win32_Service -ComputerName $computer -Credential (Get-Credential) -ErrorAction Stop
if ($?)
{
$blGoOn=$false
}
}