While scanning the PowerShell forums this evening I ran accross this question. Cruisader03 had already answered the question. The solution.. just…. looked too complicated. After three years of using PowerShell everyday as my primary means of administration… I offer this simple mantra.
If it looks complex your doing it wrong!… And you’re the second person to read it.
I just made that up, but I like it! Seriously though, this is something I’ve started to notice in my own code. I believe it is an interesting side effect of the Admin Development Model.
We cut and paste, one line at a time. Until we get it to work. By the time we finish a script we know that code not as a script, but as a series of lines. (Pay attention, I bet you still read it like a series of one liners). In that context it looks fine, but wait 24hr’s and look again… not the same is it. Now that you’re looking at a finished script. You will start to find all sorts of inefficiencies and poor grammar usage. So you polish it up a little… rinse and repeat 100 times, and post to PoshCode! So goes the Admin Development Model. With that in mind I offer this simple snip it, more a refactor of Cruisader03 post than a solution.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<span style="color: #ff4500;">$name</span> <span style="color: #a9a9a9;">=</span> <span style="color: #8b0000;">'.'</span> <span style="color: #0000ff;">Get-WmiObject</span> <span style="color: #8a2be2;">Win32_NetworkLoginProfile</span> <span style="color: #000080;">-ComputerName</span> <span style="color: #ff4500;">$name</span><span style="color: #a9a9a9;">|</span> <span style="color: #006400;">#Filter out any non valid DTG</span> <span style="color: #0000ff;">Where-Object</span> <span style="color: #000000;">{</span><span style="color: #ff4500;">$_</span><span style="color: #a9a9a9;">.</span><span style="color: #000000;">LastLogon</span> <span style="color: #a9a9a9;">-match</span> <span style="color: #8b0000;">"(?<dtg>d{14}.d{6}S)(?<offset>d+)$"</span><span style="color: #000000;">}</span><span style="color: #a9a9a9;">|</span> <span style="color: #006400;">#Foreach valid entry find the last logon dtg</span> <span style="color: #0000ff;">ForEach-Object</span> <span style="color: #000000;">{</span> <span style="color: #006400;"># Win32_NetworkLoginProfile formats the utc offset in seconds this</span> <span style="color: #006400;"># Breaks the DateTime parser. We reformat the string converting</span> <span style="color: #006400;"># the offset back to hours</span> <span style="color: #ff4500;">$CorrectedDTG</span> <span style="color: #a9a9a9;">=</span> <span style="color: #8b0000;">"{0}{1:00}"</span> <span style="color: #a9a9a9;">-f</span> <span style="color: #ff4500;">$matches</span><span style="color: #a9a9a9;">.</span><span style="color: #000000;">dtg</span><span style="color: #a9a9a9;">,</span> <span style="color: #000000;">(</span><span style="color: #ff4500;">$matches</span><span style="color: #a9a9a9;">.</span><span style="color: #000000;">offset</span><span style="color: #a9a9a9;">/</span><span style="color: #800080;">60</span><span style="color: #000000;">)</span> <span style="color: #0000ff;">New-Object</span> <span style="color: #8a2be2;">PSObject</span> <span style="color: #000080;">-Property</span> <span style="color: #000000;">@{</span> <span style="color: #000000;">Name</span><span style="color: #a9a9a9;">=</span><span style="color: #ff4500;">$_</span><span style="color: #a9a9a9;">.</span><span style="color: #000000;">Name</span> <span style="color: #000000;">LogonTime</span><span style="color: #a9a9a9;">=</span><span style="color: #008080;">[datetime]</span><span style="color: #a9a9a9;">::</span><span style="color: #000000;">ParseExact</span><span style="color: #000000;">(</span><span style="color: #ff4500;">$CorrectedDTG</span><span style="color: #a9a9a9;">,</span> <span style="color: #8b0000;">"yyyyMMddhhmmss.ffffffzz"</span><span style="color: #a9a9a9;">,</span> <span style="color: #ff4500;">$null</span><span style="color: #000000;">)</span> <span style="color: #000000;">}</span> <span style="color: #000000;">}</span> <span style="color: #a9a9a9;">|</span> <span style="color: #0000ff;">Sort-Object</span> <span style="color: #000080;">-Descending</span> <span style="color: #8a2be2;">LogonTime</span> <span style="color: #a9a9a9;">|</span> <span style="color: #0000ff;">Select-Object</span> <span style="color: #000080;">-First</span> <span style="color: #800080;">1</span> |
~Glenn
Great post. I like the use of the Admin Development Model in your description. Its sounds classier than REPL (read, evaluate, print, loop). 😉
Great post but I can’t get the script to work, and not sure why. The error response line number would indicate it’s this line:
LogonTime=[datetime]::ParseExact($CorrectedDTG, “yyyyMMddhhmmss.ffffffzz”, $null)
Exception calling “ParseExact” with “3” argument(s): “String was not recognized as a valid DateTime.”
At line:15 char:45
+ LogonTime=[datetime]::ParseExact <<<< ($CorrectedDTG, "yyyyMMddhhmmss.ffffffzz", $null)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
JKavanagh58, Your system is returning a dtg format that my parser doesn’t understand. I would suggest looking at the raw dtg, and go from there.
Sorry, I couldn’t be more help, but this is the problem with text. It is just too unpredictable to get 100%.
~Glenn