Showing posts with label eventlog. Show all posts
Showing posts with label eventlog. Show all posts

Thursday, February 25, 2016

Getting an overview of reboots revisited

In my previous post I mentioned invoke-command using the -AsJob option. But then I saw a post from Tommy Maynard that made things even quicker and certainly a bit easier.

Instead of doing a "foreach server in serverlist" loop to run the invoke-command scriptblock, you can do an invoke-command on the entire serverlist in one go!

$ServerList = Get-Content C:\Scripts\ServerList.txt.txt

$block = {Get-EventLog System | Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"} | Select Machinename, TimeWritten, UserName, EventID, Message}

Invoke-Command -ComputerName $ServerList -ScriptBlock $block | ft -AutoSize -Wrap |Out-File C:\scripts\ServerRestart.txt

This certainly cuts down on scriptsize :-)

How much time you save depends on the amount of servers, but I tested it with 5 VM's, and saw some surprising things in my test: Invoke-command feeding the serverlist as described above actually took longer than invoke-command using the -Asjob option.

Usually I get 14 seconds for the old fashioned "foreach" test, then about 6 seconds for the invoke-command feeding the serverlist, and about 2 seconds for the invoke-command with -Asjob.

Here's the test I ran a few times after another:

$ServerList = Get-Content C:\Scripts\ServerList.txt.txt

# Test 1: Old fashioned way

Write-Host -ForegroundColor green "Foreach server in serverlist"
Measure-Command {foreach ($server in $ServerList){Get-EventLog System -ComputerName "$server" | Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"} | ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize}}|select Seconds|ft -AutoSize

# Test 2: Doing the test with invoke-command, feeding the serverlist in one go

$block = {Get-EventLog System | Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"}}

Write-Host -ForegroundColor green "invoke with serverlist"
Measure-Command {Invoke-Command -ComputerName $ServerList -ScriptBlock $block}|select Seconds|ft -AutoSize

# Test 3: Doing the test with "Job" functionality

Write-Host -ForegroundColor green "Job Functionality"
Measure-Command {
foreach ($Server in $ServerList){
Invoke-Command -ComputerName $Server -ScriptBlock $block -AsJob
}

While (Get-Job -State "Running") {
}    

Get-Job| Receive-Job |ft -AutoSize
Get-Job | Remove-Job
Write-Host -ForegroundColor Yellow "Done!"
}|select Seconds|ft -AutoSize

The weird thing however, is if I swap test 2 and 3 around, invoke-command using -Asjob consistently works slower than the invoke-command with serverlist.  The old fashioned test still took  14 seconds, but the invoke-command with -Asjob took 2 to 6 seconds, and invoke-command feeding the serverlist consistently took 1 second.

Last try:

So I wasn't sure why the last piece of the script went faster than the middle part, but swapping it consistently made the latter one faster. So I ran each of the two tests in a loop for about 10 times in a row, and lo and behold: The invoke-command using -Asjob was running at 1-2 seconds, and feeding the serverlist in one go ran consistently for 1 second. For both tests, the first run took about 6 seconds, and this could be the same delay that is apparent in the test I listed above.

I assume that somehow a connection is made using Invoke-Command, and this session somehow stays alive.

In the end: Feed invoke-command the serverlist as a whole. It's easier to manage. and a little bit faster consistently.

Friday, February 19, 2016

Getting an overview of server reboots

A quick one that I wanted to keep for reference, after a forum post on powershell.org. Someone wanted to have a list of reboot times from the eventlog and put it in a text file, so I commented:

$ServerList = Get-Content "C:\Scripts\ServerList.txt"

foreach ($i in $ServerList){
    Write-Output $i "`n"+"==========================" | Out-File -FilePath c:\scripts\ServerRestart.txt -Append

    $Output = Get-EventLog System -ComputerName "$i" | Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"} | ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize -Wrap

    $Output | Out-File -FilePath c:\scripts\ServerRestart.txt -Append
}

This obviously only works if you have enough credentials to access the remote server. This in itself should do the job for not too many servers, or lots in due time, because it runs on one server at a time.

If you want to kick things up a notch, and parallelize things, you can run it as a job with Invoke-Command with "-Asjob":

$ServerList = Get-Content "C:\Scripts\ServerList.txt"

$block = {Get-EventLog System | Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"} | ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize -Wrap }

foreach ($Server in $ServerList){
Invoke-Command -ComputerName $Server -ScriptBlock $block -AsJob
}

While (Get-Job -State "Running") {    
    Write-Host -ForegroundColor Yellow "Running..."
    Start-Sleep 1        
}    

Get-Job| Receive-Job |Out-File C:\scripts\ServerRestart.txt
Write-Host -ForegroundColor Yellow "Done!"


Which will give the following output:

Get-Job| Receive-Job |Out-File C:\scripts\ServerRestart.txt

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                  
--     ----            -------------   -----         -----------     --------             -------                  
35     Job35           RemoteJob       Running       True            localhost            Get-EventLog System | ...
37     Job37           RemoteJob       Running       True            127.0.0.1            Get-EventLog System | ...
Running...
Running...
Running...
Running...
Running...
Done!

This should speed things up a bit, as now all machines run it simultaneously. The only thing that doesn't get done that way is the divider-line at the top.

To be totally neat, you should clean up the jobs too:

Write-Host -ForegroundColor Yellow "Clearing Up completed jobs"
Get-Job -State "Completed" |Remove-Job

Now you should be able to do a Get-Job and see if there are any failed jobs. Yes yes, that could be automated too..