PSG2013 Advanced Event 0: System Uptime

This is the Advanced version of Event 0 for the 2013 PowerShell Scripting Games

Goal: A Script that reports system uptime for a collection of computers. It must accept one or more computers by parameter. May be either name or IP Address. The parameter must accept input from the pipeline by object or string array, or direct string input. The script must prompt for names if none are provided. The script must output an object that has the name of the machine (even if only IP was provided) as well as total hours, minutes, seconds of uptime as individual properties. It must optionally offer status/connection information as it runs. It must control for connection errors and report a suitable error message on the shell. It must have a switch that enables logging of failed connections to a file. Without the switch, there should be no logging. The output must be compatible with CSV/XML/HTML output from the shell.

Result: Success! This one took a little time. I went the extra mile to ensure I had help information, and make sure everything works just right. This script (.\Get-Uptime) can take string arrays, direct input, or piped input (with aliases for object ins) from the shell or pipeline, and puts out a timespan object. Most of the actual work is done by the same code from the beginner track with slight editing so I can do error handling, so I wont re-explain it here. I realized I made a mistake on the beginner track, as I alloted for days instead of total hours. This information was available to me I just didn’t grab it. It’s corrected here in the expression Hours expressed as {[int]$_.totalhours}. This script appropriate expresses total hours (as a rounded integer) along with minutes/seconds. This results in a table output by default (5 props defaults to a list).

Edit: Special thanks to mjolinor over at for pointing out the math error in my script. I cast total hours to integer, which rounds (sometimes up). What I should have done was either round down deliberately before casting, or otherwise truncate the number. This has been corrected in the script below by using the math::truncate. I also could have cast it as a string to correct it by simple discarding the decimal.

Here’s the script:

Get-Uptime collects and displays the uptime (hours, minutes, seconds) of a given collection of computers.  
This script utilizes the Get-WMIObject cmdlet to collect the Win32_OperatingSystem LastBootUpTime and 
CSName properties and returns a modified timespan object selected with Name, Hours, Minutes, and Seconds
of uptime properties.
.PARAMETER ComputerName 
This mandatory parameter indicates the computer(s) that should be queried for uptime. It is accepted as position 0
both IP Addresses or ComputerNames are valid.  The script will always return a name for an online host.
This optional parameter works in conjuction with the -LogFail switch.  If no value is specified, the log file 
is created locally as .\NoUptime.txt
This switch enables logging of machines that cannot be contacted to a file.  The file is configurable by the 
FailedFile parameter and defaults to .\NoUptime.txt
This script accepts input objects on the pipeline, or a string (or array of strings) from the pipeline in 
Position 0 or from the shell.  
This script supports the verbose switch, which will indicate connection progress
This script supports a -FailLog switch which will divert a list of failed computers to a specified text file.
Get-UpTime localhost
Collects the uptime of a single specified computer
Get-Uptime localhost,computer1,computer2 -LogFail -FailedFile .\UptimeFailed.txt
Collects the uptime of a specified list of computers, logs computers offline to the file .\UptimeFailed.txt
Get-Uptime (Get-Content file.txt)
Collects the uptime of a list of computers as specified in the file file.txt
Get-ADComputer -Filter * | Get-Uptime -verbose
Collects the uptime of every computer in the domain (could take a while...) and reports connection status
via Verbose as it goes.
Param (
	[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
	[Alias('Computer', 'CSName', 'Server', '__ServerName', '__Server')]
Process {
	ForEach ($computer in $ComputerName) {
		Write-Verbose "Trying to connect to $computer"
		$item = Get-WmiObject Win32_OperatingSystem -computer $computer -ErrorAction SilentlyContinue 
			if ($?) {
				Write-Verbose "Succesfully Connected to $computer"
				New-TimeSpan -start $item.ConvertToDateTime($item.LastBootUpTime) -End (Get-Date) | 
				Add-Member -MemberType NoteProperty -Name Computername -Value $item.CSName -passthru |
				Select ComputerName, @{Name='Hours';Expression={[system.math]::truncate($_.TotalHours)}}, Minutes, Seconds
				} #End if
			else {
			Write-Error "Couldn't Connect to $computer, offline or unavailable?" -Category OperationTimeout -RecommendedAction "Check if Online?" 
			if ($LogFail){ $computer | Out-File $FailedFile -Append } 
			} #End Else
	} #End ForEach
} #End Process

Jeff is a system administrator for an enterprise of over 4000 devices. He is comfortable on Windows and *nix and participates in everything from desktop to network support. In addition, he develops in PowerShell to aid in the automation of administrative tasks.

When not at work, Jeff is adjunct faculty at the University of Alaska Anchorage, where he teaches PC Architecture to first year students in the Computer and Networking Technology Program. He is also working on new curriculum in PowerShell and Virtualization as well as leading department technology deployments.

View Jeff Liford's profile on LinkedIn

Posted in Desktop, PowerShell, Server