PS Get-WinEvent throw 'The Handle is invalid' - powershell

I have a list of hostnames from which I'd like to extract all AppLocker related eventlogs, especially the ones with level warning and/or error.
I crafted this script:
$ComputersToCheck = Get-Content 'X:\ListWithTheNames.txt'
foreach($OneHost in $ComputersToCheck)
{
try
{
$EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL" -ComputerName $OneHost -Credential $CredentialFromUser
foreach ($SingelEvent in $EventCollection)
{
if($SingelEvent.LevelDisplayName -ne "Information")
{
$pathtosaveto = 'SomeFileName.txt'
$ResultString += $SingelEvent | Select Message,MachineName,UserId | Export-Csv -Path $pathtosaveto -Append
}
}
}
catch
{
//handling exceptions
}
}
This works for a while, but after a certain ammount of time I got an error:
Get-WinEvent : The remote procedure call failed
At X:\FileName.ps1:22 char:28
+ $EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The remote procedure call failed,Microsoft.PowerShell.Commands.GetWinEventCommand
And right after the script start giving errors like this:
Get-WinEvent : The handle is invalid
At X:\FileName.ps1:22 char:28
+ $EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EX ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-WinEvent], EventLogException
+ FullyQualifiedErrorId : The handle is invalid,Microsoft.PowerShell.Commands.GetWinEventCommand
My first thought was that it is related to the host the script try to reach, but the next in the list is the same type (Os, even the same model) as the previous.
I ran the script 3 times, and every time the output size was different (probably because not the same hosts were online with the same amount of logs).
The script should run against more than 700 hosts, to which a special account is needed which I prompt by the Get-Credential, store in a variable and pass it the the Get-WinEvent as a parameter.
To be honest I stuck with this issue, not really sure what cause this and why.
If anyone has an idea please share with me :)

Give this a try to attempt catching references to failed hosts and empty objects. You could write the exception received but I didn't include that in this to make the failedhosts file simple to read. Hope I got it right as I winged it and don't have a true case to test against.
$ComputersToCheck = Get-Content 'X:\ListWithTheNames.txt'
foreach($OneHost in $ComputersToCheck) {
try {
$EventCollection = Get-WinEvent -LogName "Microsoft-Windows-AppLocker/EXE and DLL" -ComputerName $OneHost -Credential $CredentialFromUser -ErrorAction Stop
if($EventCollection) {
foreach ($SingelEvent in $EventCollection) {
if($SingelEvent.LevelDisplayName -ne "Information") {
$pathtosaveto = 'SomeFileName.txt'
$ResultString += $SingelEvent | Select Message,MachineName,UserId | Export-Csv -Path $pathtosaveto -Append
}
}
} else {
Out-File -InputObject $($OneHost + " Empty Event Collection") -FilePath "C:\FailedHosts.txt" -Append -Encoding ascii
}
}
catch {
Out-File -InputObject $($OneHost + " Failed Connection") -FilePath "C:\FailedHosts.txt" -Append -Encoding ascii
}
}

Related

Powershell Error for Get-Service

Back when I had Windows 7 an a lower version of Powershell the following code use to work without any issues.
It checks each server in a text file for some services and dumps the results to a CSV.
Now that I'm on Windows 10 and with Powershell v5 I get this error message:
Get-Service : Cannot open Service Control Manager on computer 'tfsserver1'. This operation might require other privileges. At
C:\Users\Razon\Desktop\Patching\ServerServices_Checker_v2.ps1:48
char:4
+ (Get-Service -Name TFSJobAgent*,IIS*,World* -ComputerName $_) | Select Machine ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Service], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetServiceCommand
####System Varialbe to User's Deskotp
$filePath = [Environment]::GetFolderPath("Desktop")
Here is the code:
function tfsCheck
{
$Path = "$filePath\Patching\Servers\tfs_servers.txt"
Get-Content $Path | foreach {
(Get-Service -Name TFSJobAgent*,IIS*,World* -ComputerName $_) | Select MachineName, Status, DisplayName
}
}
#TFS Function Call and Write to CSV
tfsCheck|Select MachineName, Status, DisplayName |Export-Csv $filePath\Patching\Results\TFS_ServicesResults.csv -NoTypeInformation
To resolve this issue, elevate the user's network privileges to be able to access the Service Control Manager on the Server.
https://support.microsoft.com/en-in/help/964206/cannot-open-service-control-manager-on-computer-servername-.-this-operation-might-require-other-privileges

Starting/Stopping AWS EC2 Instances using AWS Powershell Tools

I am attempting to write two separate scripts. One script determines which EC2 instances are stopped, it starts them and documents what it starts to a text file.
The second script will read the text file and stop those instances. For debugging/simplicty sake I am starting out by combining the two scripts into a single script.
Here's my script:
$Instances = (Get-EC2Instance).instances
$start_instances = #()
$Instances | foreach {
$state = Get-EC2InstanceStatus -InstanceId $_.InstanceId -IncludeAllInstance $true
$state = $state.InstanceState.Name
if ($state -eq "stopped"){
$start_instances += $_.InstanceId
}
}
[System.IO.File]::WriteAllText("C:\users\myusername\desktop\so.csv", $($start_instances -join ','))
$shutdown_instances = [System.IO.File]::ReadAllText("C:\users\myusername\desktop\so.csv")
Write-Host "Press any key to continue ..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Stop-EC2Instance -Instance $shutdown_instances
Starting and documenting what instances are running works fine. Its the stopping instances which is failing.
I'm getting the following error:
Stop-EC2Instance : Invalid id: "i-99edd755,i-8d647f58"
At C:\users\myusername\Desktop\aws-test.ps1:28 char:1
+ Stop-EC2Instance -Instance $shutdown_instances
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Stop-EC2Instance], AmazonEC2Exception
+ FullyQualifiedErrorId : Amazon.EC2.AmazonEC2Exception,Amazon.PowerShell.Cmdlets.EC2.StopEC2InstanceCmdl
Those instance IDs are indeed valid so I can't figure out why the heck its complaining. I was writing the instance IDs to a file via out-file and getting it via get-content but that seemed to have caused a different error.
I'm assuming the issue has something to do with the format of the data once i'm pulling it out of the text file.
Edit
So I've changed my script to:
$start_instances = $start_instances | Select-Object #{Name='Name';Expression={$_}}
$start_instances | Export-Csv -Delimiter ',' -NoTypeInformation -path C:\temp\instances.csv
$stop_instances = #(Import-Csv -path C:\temp\instances.csv)
$stop_instances | Stop-EC2Instance
But still get an error:
Stop-EC2Instance : No instances specified
At C:\temp\aws-test.ps1:22 char:19
+ $stop_instances | Stop-EC2Instance
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Stop-EC2Instance], AmazonEC2Exception
+ FullyQualifiedErrorId : Amazon.EC2.AmazonEC2Exception,Amazon.PowerShell.Cmdlets.EC2.StopEC2InstanceCmdlet
I've also tried:
Stop-EC2Instance -InstanceID $stop_instances
But that also dies:
Stop-EC2Instance : No instances specified
At C:\temp\aws-test.ps1:22 char:1
+ Stop-EC2Instance -InstanceId $stop_instances
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Stop-EC2Instance], AmazonEC2Exception
+ FullyQualifiedErrorId : Amazon.EC2.AmazonEC2Exception,Amazon.PowerShell.Cmdlets.EC2.StopEC2InstanceCmdlet
InstanceId parameter needs array.
You can declare an empty array first
$EC2Instance =#()
Then use Import-CSV and pipe it to append the empty array with each value from csv
Import-CSV C:\Temp\Instance.csv | Foreach-Object {$EC2Instance += $_.InstanceId}
echo $EC2Instance
$EC2instance will now have the required instance id's in an array
Then you can use it in the command
Stop-EC2instance -InstanceId $EC2instance
This worked for me.

Unexpected token error when I have the variable already defined

Simple script but can't figure out why I am getting the error : It should just write the machines that were successful to one text file and the failed to another.
Here is the error I am getting :
Unexpected token '$ip' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
$computers = Get-Content C:\temp\machines_no_rdp.txt
foreach($computer in $computers)
{
if((New-Object System.Net.NetworkInformation.Ping).Send("$computer",[int]1000).Address.IPAddressToString)
{
$computer
$ip = [System.Net.Dns]::GetHostByName($computer).AddressList.IPAddressToString
$computer + ";" $ip | Out-File C:\temp\Success.txt -Append
}
else{$computer + ";" + "Dead" | Out-File C:\temp\failure.txt -Append}
}
The error is trying to tell you it does know what to do with $ip. It does not care at this point whether it is a variable or not. It's a parsing error.
$computer + ";" $ip
should instead be the following ( in keeping with your coding practice.)
$computer + ";" + $ip

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')"
}

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