It's been a while, but I'm back. I decided to tackle this month's Scripting Games puzzle, and I found that it's basically something I've previously written with some modifications. So, I used that, made the necessary tweaks to fit their guidelines, and made some improvements over what I'd done at the time (it was a couple of years ago, and I'd like to think I've gotten at least a little better since then...)
Anyway, here are the requirements for this month's puzzle:
“Requirements:
1. Support pipeline input so that you can pipe computer names directly to it.
2. Process multiple computer names at once time and output each computer’s stats with each one being a single object.
3. It should not try to query computers that are offline. If an offline computer is found, it should write a warning to the console yet still output an object but with Status of OFFLINE.
4. If the function is not able to find the uptime it should show ERROR in the Status field.
5. If the function is able to get the uptime, it should show ‘OK’ in the Status field.
6. It should include the time the server started up and the uptime in days (rounded to 1/10 of a day)
7. If no ComputerName is passed, it should default to the local computer.
Bonus:
1. The function should show a MightNeedPatched property of $true ONLY if it has been up for more than 30 days (rounded to 1/10 of a month). If it has been up for less than 30 days, MightNeedPatched should be $false.”
And here is my solution:
EDIT: It looks like I found the time, so here's some more details on my solution:
As mentioned previously, I wrote this about a year and a half ago (and posted it on this site), but what I wrote was almost everything I needed. Why reinvent the wheel? This challenge had different goals than I did when I wrote it, though, and different expectations of what the output would look like, so I had some work to do.
I'm not going to detail the changes I made, but I will walk through the requirements and where I resolved each one.
First, as a fully formed advanced function, I've included comment based help, pipeline support, and proper object output, all of which are good practices when writing a function.
Lines #20 and #22 do a surprising amount of heavy lifting in this challenge, as it takes care of requirements #1 and #7 all by themselves (technically, they're the same line), and lays important ground work for supporting requirement #2: it sets the ComputerName parameter to accept pipeline output, defines the parameter as a string array, and it even sets the default property if none is given.
Requirement #3 is addressed with lines #28 and #62 through #72, by checking to see if it can reach the computer over the network, and defining a different output set if it can't (although it still maintains the same set of property names so display will not be affected).
Requirements #4 and #5 are handled by using the try/catch block at lines #29 and #42, and sets the Status property differently depending on if there was an error or not.
#6 is handled on lines #34 and #35. This was a difficult one to get, and one of the biggest improvements over my original function. The start time is stored in the returned WMI property LastBootUpTime, but it's in an unusual format that is somewhat human readable, but which PowerShell doesn't have a way to properly parse. Thankfully, the Win32_OperatingSystem object has a method that can convert this to a type that PowerShell can read and understand. Then, it's just a matter of subtracting the current time from the start time, and rounding the TotalDays field down to 1 decimal position. Easy! ...-ish.
At that point, I had everything I needed to take care of the bonus requirement, by simply checking to see if DaysUpTime was more than 30. This was handled at lines #39, #40, and #59.
Beyond that, I handled the output in a pretty standard way, by creating a new object and assigning it a hashtable for the properties, then writing it to output. I did give it a type name, which might be useful later if I decide to make it a part of a module with defined formatting or where other functions make use of the objects directly.
That's it for this month's challenge!