Power Shell server live ping status - powershell

Good Day!
I work with multiple clients and one of my clients have their own toll that displays live server ping stats and this is very helpful during patching activity because of followed reboots etc. I want to design a tool like this or any other tool or means where I can see live ping stats of servers in my Domain. Can I do it using Power Shell by any chance? Is there a way that I could refresh my Power Shell page or the output HTML page which updates the ping stats of respective servers please! I have no clue about programming languages but I want to do this as my pet project and I cannot ask my client about all these details. Help is very much appreciated!
Thanks guys, I have tried below two codes:
param(
[int]$waitseconds = 3
)
while($true) {
$servers = Get-Content .\servers.txt
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
if (Test-Connection $server -Count 1 -ea 0 -Quiet)
{
$status["Results"] = "Up"
}
else
{
$status["Results"] = "Down"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
$collection | out-gridview; sleep $waitseconds
}
This gives me output in a grid view and it also successfully refreshes the output but the new refreshed output is being presented in a new grid view window. I cannot afford opening numerous windows. So I have tried below code:
param(
[int]$waitseconds = 3
)
while($true) {
$servers = Get-Content .\servers.txt
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
if (Test-Connection $server -Count 1 -ea 0 -Quiet)
{
$status["Results"] = "Up"
}
else
{
$status["Results"] = "Down"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
Start-Process -FilePath powershell.exe -ArgumentList "-WindowStyle -NoNewWindow -Command &{ $collection | out-gridview; sleep $waitseconds; exit }" -Wait
}
This code is not at all giving gridview output, it simply displays ping stats in shell itself but able to refresh.
I have tried below code too with -NoNewWWindow at the end and this gives output one time and then closes:
param(
[int]$waitseconds = 3
)
while($true) {
$servers = Get-Content .\servers.txt
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
if (Test-Connection $server -Count 1 -ea 0 -Quiet)
{
$status["Results"] = "Up"
}
else
{
$status["Results"] = "Down"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
Start-Process -FilePath powershell.exe -ArgumentList "-WindowStyle -Command &{ $collection | out-gridview; sleep $waitseconds; exit }" -Wait -NoNewWindow
}
Help me with any modifications to my 1st code so that the grid view does not open for every refresh please!

Have you tried something like this:
$collection | out-gridview
sleep $waitseconds
(Get-Process -id $PID).CloseMainWindow()

Related

Making variables visible inside Powershell workflow

I have five variables defined before a workflow that need to be available to the workflow, but I can't find out how to do it.
Putting the variables inside the workflow makes them visible, but that causes an issue with the CSV import that means extra properties are added to the object relating to the workflow that I don't want.
Code as follows:
$source = 'C:\Users\Koozer\a place\'
$rotateParams = 90, 90, 270
$cropParams = #(64, 64), (32, 0)
$images = Import-Csv "${source}images.csv"
$colNames = $images[0].psobject.properties.Name
Workflow StitchCropWorkflow {
foreach -parallel ($imageSet in $images) {
$magickRotParams = ''
$n = 0
foreach ($image in $colNames) {
$magickRotParams += '`( '''+$source+$imageSet.($image)+''' -rotate '+$rotateParams[$n]+' `) '
$n++
}
$finfo = [io.fileinfo]$imagePathSets[0]
$command = 'magick '+$magickRotParams+' +append -crop '+$cropParams[0][0]+'x'+$cropParams[0][1]+'+'+$cropParams[1][0]+'+'+$cropParams[1][1]+' +repage '''+$finfo.DirectoryName+'\'+$finfo.BaseName+'_stitch_crop'+$finfo.Extension+''''
echo $command
Invoke-Expression $command
}
}
StitchCropWorkflow
You can pass parameters to a workflow like you would do it for a function:
$source = 'C:\Users\Koozer\a place\'
$rotateParams = 90, 90, 270
$cropParams = #(64, 64), (32, 0)
$images = Import-Csv "${source}images.csv"
$colNames = $images[0].psobject.properties.Name
Workflow StitchCropWorkflow {
param (
$source,
$rotateParams,
$cropParams,
$images,
$colNames
)
# your code here
}
StitchCropWorkflow $source $rotateParams $cropParams $images $colNames
If you define a variable in a script containing a workflow, to access the variable within the workflow the syntax is $using:variable
As an example, here is a powershell script containing a workflow with a single param.
param([string]$ComputerName)
$VerbosePreference = "Continue"
workflow Start-Reboot {
param($server)
Write-Verbose "Input server is $server"
InlineScript{
New-Item -Path C:\Scripts\Logging\Start-Reboot-Single.log -ItemType File -ErrorAction SilentlyContinue | Out-Null
}
Sequence{
InlineScript
{
Try
{
Get-WmiObject -ComputerName $using:server -Class Win32_Service -Filter "Name='HealthService'" | Invoke-WmiMethod -Name PauseService | Out-Null
$operatingSystem = Get-WmiObject Win32_OperatingSystem -ComputerName $using:server -ErrorAction stop
$LastReboot = [Management.ManagementDateTimeConverter]::ToDateTime($operatingSystem.LastBootUpTime).ToString().Trim()
Write-Verbose "Last reboot time for $using:server is $LastReboot"
Write-Verbose "Here we restart $using:server, for testing no reboot is done"
Restart-Computer -ComputerName $using:server -Wait -For Wmi -Force
$OSRecheck = Get-WmiObject Win32_OperatingSystem -ComputerName $using:server -ErrorAction stop
$CurrentReboot = [Management.ManagementDateTimeConverter]::ToDateTime($OSRecheck.LastBootUpTime).ToString().Trim()
$props = [Ordered]#{
Server=$using:server
LastReboot=$LastReboot
CurrentReboot=$CurrentReboot
}
} Catch {
Write-Verbose "Oh no, problem with $using:server"
$rnd = Get-Random -Minimum 1 -Maximum 5
Start-Sleep -Seconds $rnd
$err = $_.Exception.GetType().FullName
$props = [Ordered]#{
Server=$using:server
LastReboot=$err
CurrentReboot=$null
}
} Finally {
$object = New-Object -TypeName PSObject -Property $props
$random = Get-Random -Minimum 2 -Maximum 15
Start-Sleep -Seconds $random
Write-Output $object | Out-File -Append -FilePath C:\Scripts\Logging\Start-Reboot-Single.log
}
}#inline end
}#sequence end
}#end workflow block
Start-Reboot -server $ComputerName

Basic Output Redirection

I searched and put together a PowerShell script to check if a windows service (SNARE) is running or not in a list of servers. At the moment, the script prints "Snare is running" if it doesn't error and "Not installed/Powered off" if it meets an error. What I am also looking for is if the script doesn't end up in error, can I somehow take the output of Status (example below) and print "Snare is stopped"?
Status Name DisplayName
------ ---- -----------
Stopped SNARE SNARE
#Powershell
$serverList = gc Final.txt
$collection = $()
foreach ($server in $serverList) {
$status = #{
"ServerName" = $server
"TimeStamp" = (Get-Date -f s)
}
if (Get-Service -Name SNARE -ComputerName $server -EA SilentlyContinue) {
$status["Results"] = "Snare is running"
} else {
$status["Results"] = "Not installed/Powered off"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
}
Assign the output from Get-Service to a variable, and grab the Status property from that:
if (($snare = Get-Service -Name SNARE -ComputerName $server -EA SilentlyContinue))
{
$status["Results"] = "Snare is running"
$status["Status"] = $snare.Status
}
else
{
$status["Results"] = "Not installed/Powered off"
$status["Status"] = "Unknown"
}

Resolve-DnsName inside Test-Connection

I was wondering how I could return the Resolve-DnsName output from my Test-Connection script and add it to the CSV I created.
I like to capture the Name, Type, TTL, Section from that please.
Only invoke the Resolve-DnsName when the ping is not successful.
$servers = Get-Content "servers.txt"
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
$result = Test-Connection $server -Count 1 -ErrorAction SilentlyContinue
if ($result)
{
$status.Results = "Up"
$status.IP = ($result.IPV4Address).IPAddressToString
}
else
{
$status.Results = "Down"
$status.IP = "N/A"
$status.DNS = if (-not(Resolve-DnsName -Name $server -ErrorAction SilentlyContinue))
{
Write-Output -Verbose "$server -- Not Resolving"
}
else
{
"$server resolving"
}
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
$collection | Export-Csv -LiteralPath .\ServerStatus3.csv -NoTypeInformation
but nothing new is added to the CSV.
You ran into a PowerShell gotcha. PowerShell determines the columns displayed in tabular/CSV output from the first object processed. If that object doesn't have a property DNS that column won't be shown in the output, even if other objects in the list do have it. If other objects don't have properties that were present in the first object they will be displayed as empty values.
Demonstration:
PS C:\> $a = (New-Object -Type PSObject -Property #{'a'=1; 'b'=2}),
>> (New-Object -Type PSObject -Property #{'a'=3; 'b'=4; 'c'=5}),
>> (New-Object -Type PSObject -Property #{'b'=6; 'c'=7})
>>
PS C:\> $a | Format-Table -AutoSize
a b
- -
1 2
3 4
6
PS C:\> $a[1..2] | Format-Table -AutoSize
c b a
- - -
5 4 3
7 6
If you want to generate tabular output always create your objects uniformly with the same set of properties. Choosing sensible defaults even allows you to reduce your total codebase.
$collection = foreach ($server in $servers) {
$status = New-Object -Type PSObject -Property #{
'ServerName' = $server
'TimeStamp' = Get-Date -f s
'Results' = 'Down'
'IP' = 'N/A'
'HasDNS' = [bool](Resolve-DnsName -Name $server -EA SilentlyContinue)
}
$result = Test-Connection $server -Count 1 -EA SilentlyContinue
if ($result) {
$status.Results = 'Up'
$status.IP = ($result.IPV4Address).IPAddressToString
}
$status
}

Getting IP address while using Test-Connection

I am trying to add the IP address to this script, it would be perfect if I could get this to work. Any help is greatly appreciated.
The input files has host names, and I like to get the IP address into the csv please.
$servers = Get-content "servers.txt"
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s);"IP" = what to put here? }
if (Test-Connection $server -Count 1 -ea 0 -Quiet)
{
$status["Results"] = "Up"
}
else
{
$status["Results"] = "Down"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
$collection | Export-Csv -LiteralPath .\ServerStatus.csv -NoTypeInformation
Using -Quiet would suppress the information you are looking for. Remove the quiet and instead capture the results in a variable you can then query for both success and the ipaddress.
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s)}
$result = Test-Connection $server -Count 1 -ErrorAction SilentlyContinue
if ($result)
{
$status.Results = "Up"
$status.IP = ($result.IPV4Address).IPAddressToString
}
else
{
$status.Results = "Down"
$status.IP = "N/A"
}
I am unsure if this logic would produce misleading information but I am playing around with it just in case.
If you have already made the switch to IPv6 then you might be more interested in ($result.IPV6Address).IPAddressToString
Thank you, Matt, you helped me work through my issue.
I found that I wasn't able to use (.) in the new variables. Could be my own misunderstanding. I post this that it may help others with my same issue.
Based on your answer plus an example of how I had to adjust.
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s)}
$result = Test-Connection $server -Count 1 -ErrorAction SilentlyContinue
if ($result)
{
$StatusResult = "Up"
$statusIP = ($result.IPV4Address).IPAddressToString
}

I want this to run a Continous ping and give me the output

Two issues,
I want a constaint ping to the two servers, and output to a .csv file.
The script below only runs twice and the output doesn't work. I'm a power newbie so please go easy.
$servers = "server1","server2"
$collection = $()
foreach ($server in $servers)
{
$status = #{ "ServerName" = $server; "TimeStamp" = (Get-Date -f s) }
if (Test-Connection $server -Count 1 -ea 0 -Quiet)
{
$status["Results"] = "Up"
}
else
{
$status["Results"] = "Down"
}
New-Object -TypeName PSObject -Property $status -OutVariable serverStatus
$collection += $serverStatus
}
$collection | Export-Csv -LiteralPath .\ServerStatus.csv -NoTypeInformation
The output works fine. Just run the script and then Invoke-Item ServerStatus.csv
If you want it to run forever just wrap the whole thing in a while loop:
$servers = "server1","server2"
$collection = $()
while(1) {
foreach ($server in $servers)
{
...
}
$collection | Export-Csv -LiteralPath .\ServerStatus.csv -NoTypeInformation
}