powershell takes a long time to close connection? - powershell

I'm trying to run this powershell script on several remote network servers, but it takes a long time to complete the task and move to the next one.
Here's a basic script that will query a single remote server and return the data I want in a fast manner, but takes a long time to complete the entire script.
Get-EventLog -ComputerName WebServer1 -LogName System -EntryType Error -After ((Get-Date).Date.AddDays(-1))
I was running it through the Powershell ISE and from the command line in Powershell and both have the same behavior.
Any help is appreciated!
Thanks

As for the reason: mjolinor outlined that - Get-EventLog parses the whole logfile, and then filters the output to meet your parameters. What we want to do right now is to parse the event log one by one from the newest entries while the condition is true.
$i = 0
$EventParser = do
{
Get-EventLog -ComputerName Localhost -LogName System -EntryType Error -Newest $i; $i++
}
while
(
(Get-EventLog -ComputerName Localhost -LogName System -EntryType Error -Newest $i | Select -Last 1).TimeWritten -ge ((Get-Date).Date.AddHours(-24))
)
$EventParser|Where-Object { $_.TimeWritten -ge ((Get-Date).Date.AddHours(-24)) } | Sort-Object -Property Index -Descending | Get-Unique -OnType
I have measured your command and the loop I have written - here is the output for my machine
For $EventParser:
TotalMilliseconds : 634,6669
For your command (I changed webserver1 to localhost)
TotalSeconds : 14,3049668
I hope the script above will do the trick to speed up log parsing.
PS.
I have ran into one thing that I couldn't figure out. As you see, I am actually filtering the output twice for, I believe, the same condition (!). If I remove the last-line Where-Object statement, I receive 35 entries for my machine and it lists output even from 4 days ago ?? (Normally I receive 19 entries both from mine and original command). I have had to, to my surprise, re-apply the filter to receive the desired scope. Can you assist with that in a comment or should I post a question on that?
EDIT:
Now the problem doesn't occur. Edit: I have tweaked the code a little bit, I noticed that in some cases it may return duplicated entries.
Best regards,
AlexP

Related

Is there a way to find which user run what application on a server using Powershell

I am trying to find a way to find out who has ran an application (for example SQL) on a server, just to get some idea.
I tried Get-Process but this doesn't give me historic information, I want to get historical information
Get-Process -IncludeUserName *
what I want the return resule is "name of application", "user who ran it" and the last datetime it was ran by that user'
As for ...
I am trying to find a way to find out who has ran an application (for
example SQL) on a server, just to get some idea.
What you are asking for here is software metering.
SQL is a service that is always running once it is installed, so, no individual user is ever going to be running it. So, that is a bad example. MS Word for example would be a better example.
Yet there is nothing native in PowerShell that does this, software metering, but of course PowerShell can look at event logs. Yet if your auditing is not setup correctly then it's moot. This is better for a software metering tool, and there are several out there. So, why try and reinvent the wheel.
As for ...
I tried Get-Process but this doesn't give me historic information, I
want to get historical information
That is not what a process is nor what Get-Process is for. It, Get-Process only checks for and lists whatever process is currently running, regardless of what/who launched it.
As for...
what I want the return resule is "name of application", "user who ran
it" and the last datetime it was ran by that user'
As long as the process is running, you can get this, with that cmdlet.
However, what are you trying to accomplish by this?
Again, there are purpose built tools to meter software use.
https://learn.microsoft.com/en-us/sccm/apps/deploy-use/monitor-app-usage-with-software-metering
If you must go down this reinvent the wheel road, using scripting, then you need a task watcher on the target machines, which watches for the WinWord process to appear.
Get-Process -IncludeUserName |
Where ProcessName -EQ 'Winword'
... you then write those results to a file or database or your own event log each time you see that process.
Use PowerShell to Create and to Use a New Event Log
New-EventLog -LogName ScriptingGuys -Source scripts
When the command runs, no output appears to the Windows PowerShell console. To ensure the command actually created a new event log, I use
the Get-EventLog cmdlet with the –List parameter. Here is the command
and the associated output.
Write-EventLog -LogName ScriptingGuys -Source scripts -Message “Dude, it works … COOL!” -EventId 0 -EntryType information
Or just to a file
Get-Process -IncludeUserName |
Where ProcessName -EQ 'Winword' |
Select-Object -Property Name, StartTime, Username |
Export-Csv -Path 'F:\Temp\AppLaunchLog.csv' -Append
Import-Csv -Path 'F:\Temp\AppLaunchLog.csv'
# Results
Name StartTime UserName
---- --------- --------
WINWORD 5/23/2019 9:02:53 PM WS01\LabUser001

Script uses a lot of Ram if it's running long

I have a PS Script (running all the time on a Powershell 3.0) and there is a loop, which consumes many RAM.
while(1)
{
$te = Get-Winevent -MaxEvents 1 -FilterHashtable #{logname='application';id=2}| select -expand properties
Sleep 1
}
I tried to delete the Object and call the GC explicit. But nothing works! The Script is consuming a lot of RAM
How can I solve this Issue?
Judging by your code, it seems that you want to find all events in the Application event log with the ID of 2. If so, you're going about it wrong. You should use the Get-EventLog cmdlet. Try this:
Get-EventLog -LogName Application -InstanceID 2

PowerShell: get-eventlog takes too long to complete

I am trying to script the review of the past 30 days of the Application and System Event Logs on remote servers, looking for only Warnings, Errors, or Critical entries.
Borrowing from what I have found here and in other forums, I have come up with:
$Date = Get-Date
$Range = $Date.AddDays(-30)
$Range = $range.ToShortDateString();
$LogName = Read-Host "Which Log? (Application, System)"
$Server = Read-Host "Please Enter Server Name"
get-eventlog $LogName -ComputerName $Server -After $range | where {$_.EntryType -eq "Error" -or $_.EntryType -eq "Warning" -or $_.EntryType -eq "Critical"}
This seems to run fairly quickly, but then hangs several (5-10+) minutes before returning to a prompt, if it does....
Note: if I remove the code:
-After $range
I can simply break the output with ctrl-c and get on with my day, but I'd rather it run as intended and then stop...
So: Any ideas on how to eliminate this hang?
I am also open to ideas on how to make the code more elegant (and faster)!
And I wouldn't mind the script checking both the Application and System logs without having to run twice....
Using the -EntryType string-array parameter on Get-EventLog is much faster than retrieving the entire event log and then filtering with Where-Object
Try get-eventlog -Logname System -EntryType ("Error", "Warning")
However... if I put "Critical" in the -EntryType array, I get: The argument "Critical" does not belong to the set "Error,Information,FailureAudit,SuccessAudit,Warning" specified by the ValidateSet attribute. which makes me wonder whether you should be heeding the advice as listed in Get-Help Get-EventLog:
The cmdlets that contain the EventLog noun (the EventLog cmdlets) work
only on classic event logs. To get events from logs that use the
Windows Event Log technology in Windows Vista and later versions of
Windows, use Get-WinEvent.
Using Get-WinEvent instead, I think this is what you want:
Get-Winevent -FilterHashtable #{LogName="System","Application"; Level=1,2,3; startTime=$range}
That will check for events of level 1, 2, or 3 (Critical, Error, Warning, respectively), and search both the Application and System logs in the same invocation.
I found that for remote systems, I could query several systems at once faster than I could individually, using the same command, if I wrapped it into an Invoke-Command. This is my solution. The more systems, the more time it saved. YMMV
$command = {Get-EventLog -LogName Application -After (Get-Date).AddHours("-24")}
Invoke-Command -ComputerName "foo1","foo2","foo3","foo4" -ScriptBlock $command

Retrieving real time info from VM's with PowerCLI

I have a couple of lines in a script that are giving me an issue:
Connect-VIServer "test-vcenter.test.com" -User user -Password pass
Get-VM -Name "test-vm" | Get-Stat -Stat cpu.ready.summation -Realtime | Select-Object -First 1 value | Format-List
When running this I receive this as output:
Operation is not valid due to the current state of the object.
At :line:0 char:0
If the second line is run a few seconds after the connection to vCenter is made I receive the output I expect. What I believe is happening is that my connection to vCenter hasn't completed before my second line has started. I am not sure of the best way to wait for or what to check for in a completed connection.
you might try using start-sleep command in PS
http://technet.microsoft.com/en-us/library/ee177002.aspx
however -- as with all "sleep" functions, this isn't necessarily the best way to fix a timing problem as your pushback never may never account for all possible latency issues.
a better solution would be to test for the completion of a command (and I'm not sure how to do that with the VMWare CLI)

How to pull a range of failed services from a remote server after a reboot

Caveat: Without spiking the cpu while a Get-WmiObject call parses the whole event log to match my specified filter.
Situation: I am working on a script that remotely runs some checks, then reboots a pc. I want it to check the health once the server reboots (after sleeping for some time) to make sure services that were supposed to start did. I've been running into "Automatic" services that start and then shut down (as intended) but then my current version picks them up as failed if they've already run. It was suggested that I check the event log for "Service Control Manager" errors, and report on those, the only problem now is that with the below script, we have servers who's event log can range anywhere from 20K to several hundred thousand events, and on a 2k server with 20K, this takes roughly 20 seconds to complete, and the cpu pegs near 100% while it's running.
I'm still learning powershell/wmi, so any advice would be appreciated.
function Check_Startup_Events {
BEGIN {
$time = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime((Get-Date).AddMinutes(-15))
}
PROCESS {
$results = Get-WmiObject Win32_NTLogEvent -computername $_ -Filter "LogFile='System' and SourceName='Service Control Manager' and TimeGenerated>='$time' and EventType=1" |
Format-Table -Autosize EventCode, Message
$results
}
}
$results = Get-EventLog -ComputerName w2kserver -LogName System -After $time
foreach ($result in $results){
if ($result.Source -eq "Service Control Manager" -and $result.EntryType -eq "Error"){
Write-Host $_.Description}}
I ran this against a 60k big event log on a W2K server in our environment. It takes a while to run but runs locally and does not tax the server. Not sure how you would want to output the data but I think Get-EventLog will do what you want.