Suppressing fatal error (access denied) - powershell

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

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"

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.

PowerShell script to get logged in user

I am looking to run a script on a remote machine using an automation tool that runs the scripts in the system context.
What I have so far:
$userId = Get-Process -IncludeUserName explorer | % username | sort Username -Unique
Write-Host $userid.ToLower()
Results:
Get-Process : A parameter cannot be found that matches parameter name
'IncludeUserName'.
At line:1 char:39
+ $userId = Get-Process -IncludeUserName <<<< explorer | % username | sort Username -Unique
+ CategoryInfo : InvalidArgument: (:) [Get-Process], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.GetProcessCommand
ToLower : You cannot call a method on a null-valued expression.
At line:2 char:27
+ Write-Host $userid.ToLower <<<< ()
+ CategoryInfo : InvalidOperation: (ToLower:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Any ideas how to help this script? Or the cause of the errors?
The error says it all; the switch -IncludeUserName is not available on your computer. That's because it requires PowerShell 4.0 or above like Ansgar mentioned.
One solution is to install the latest Windows Mangement Framework (WMF) which includes the latest version of PowerShell.
You can also use the WMI-class Win32_Process to get the user and/or domain by calling the object's GetOwner()-method. Ex:
Get-WmiObject -Class Win32_Process -Filter "Name = 'explorer.exe'" |
ForEach-Object { $_.GetOwner() | % { "$($_.Domain)\$($_.User)" } } |
Sort-Object -Unique
the following script might help you. I'm not completely certain if the invoked command will get the remote logged in user, because I'm not on a work computer right now but it came from the internet so it must be true.
$Computers = (Get-Content "\\<sharedrive\<directory>\Computers.txt)
Foreach ($Computer in $Computers){ `
Invoke-Command -ComputerName $Computer -ScriptBlock `
{Get-WMIObject -Class Win32_ComputerSystem).Username} `
}

Permissions for using gwmi win32_ntlogevent instead of get-eventog?

The problem I have: get-eventlog works (I tested by doing "run as" on the PoSH ISE). Get-WMIObject win32_ntlogevent does not. It's a perm issue of some sort. Help please.
Background:
I've built a script that uses gwmi win32_ntlogevent to pull event logs. (I chose it because it was an order of magnitude faster than either get-winevent or get-eventlog, even with filters).
However, I cannot reach some other servers in my environment. So I had the Servers group add a credential to connect under, that has some sort of Log Reader right. (not sure what they added)
Get-Eventlog:
$server = "myserver"
get-eventlog -ComputerName $server -logname "application"
(above returns results)
Get-WMIObject win32_ntlogevent does not. Neither with
Get-WmiObject win32_ntlogevent -ComputerName $server
or
$time = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime('2015/05/01 5:00:00am')
$EventQuery = #"
select
Logfile, RecordNumber, Timegenerated, TimeWritten, EventCode, EventType, Type, Category, CategoryString, SourceName, InsertionStrings, ComputerName, User, Message
from Win32_NTlogEvent
where timewritten >='$time'
and LogFile = 'system'
"# #this line must be un-recessed
gwmi -computername $server -Query $EventQuery
Instead, I get:
gwmi : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
At line:10 char:1
+ gwmi -computername "myserver" -Query $EventQuery
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
+ FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
Thanks!

Error handling - PowerShell script

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.