Bloggy stuff, part 47

This week, I have accomplished a few things which may or may not be significant. Who knows.

  1. I turned 55
  2. I got a bottle of Glenn Fiddich 12-year old Scotch
  3. I got to shoot the same shotgun John Wick used in John Wick and I hit the paper target at 22 yards every time. It was awesome.
  4. I updated CMHealthCheck to 1.0.8
  5. I uploaded a video of me attempting to code with PowerShell after a few beers. It’s almost entertaining
  6. I built a “farm table” for one of my daughters. It’s stained and drying in my garage.
  7. I taught my 100lb goof-ball dog to catch squeaky alligator toys in the air
  8. I discovered that I really like whiskey sour drinks
  9. I agreed that when the farm table is done, and moved into my daughter’s dining room, we are going to “break it in” with a dinner and shots of our preferred beverage. For her: Tequila. For me: Scotch
  10. I’m flying out to Houston on Monday. Then back home, then to Chicago in early April, then home, then to New York in June, and very likely somewhere else in between.

Scripting, System Center, Technology

Captain’s Log: cmhealthcheck

I’ve consumed way way waaaaay too much coffee and tea today. Great for getting things done, not great for my future health.

CMHealthCheck 1.0.8 is in the midst of being waterboarded, kicked, beaten, tasered and pepper-sprayed to make it squeal. I’m close to a final release. Among the changes in testing:

  • Discovery Methods
  • Boundary Groups
  • Site Boundaries
  • Packages, Applications, Task Sequences (just summary), Boot Images (summary), etc.
  • User and Device Collections
  • SQL Memory allocation (max/pct)
  • Fixed “Local Groups” bug
  • Fixed “Local Users” bug
  • Enhanced Logical Disks report
  • Fixed “Installed Software” sorting issue
  • Fixed “Services” sorting issue
  • Fixed null-reference issues with “Installed Hotfixes”

Still in the works:

  • Sorting issue with ConfigMgr Roles installation table
  • Local Group Members listing
  • More details for Discovery Methods
  • Client Settings
  • ADR’s
  • Deployment Summary
  • Enhancements to the HTML reporting features

Stay tuned for more.

Note: The current posted version (as of 3/8/19) is 1.0.7, which is what will install if you use Install-Module.

To load the 1.0.8 test branch, go to the GitHub repo, change the branch drop-down from “master” to 1.0.8 (or whatever the other name happens to be at the time) and then use the Download option to get the .ZIP file. Then extract to a folder, and use Import-Module to import the .psd1 file and start playing.

business, Personal, Society, Technology

Working from Home: The Good. The Bad. The Weird.

This post is not intended to be funny, so if you’re looking for a better joke, watch C/SPAN.  Wait, that was technically a joke.  Oh well.

So, a little (snooze-fest) background to get you in the mood.  Some wine, some Barry White music, dim lights, and…

I’ve now been working remote for an employer since Spring of 2015.  I didn’t seek this, because I always thought of it as a unicorn job.  But I soon discovered how many others have been doing it (in IT) for a long time and how the practice is increasing in popularity.  This is particularly true for consulting more than full-time employment (FTE) or contracting.  Consulting for an employer on full W-2, etc. is more common than independent, but I see quite a few of those as well (mostly online, that is).

Since then, I’ve had many discussions with others who work from home and it seemed odd how little information exists on “best practices” and warning signals.  There are some books, some blogs, some whitepapers out there, but most appear to be focused on a specific area within the topic, rather than taking a holistic view.  I try to avoid using “holistic” because I’ve heard it used to death, but I couldn’t stop myself.

The Good

The advantages for the consultant are pretty obvious, but not always what you expect. I won’t bother with the advantages for employers, because they should already know that, or they’re on the wrong path.

Flexibility is high on the list. When you wake up, when you take lunch, etc. Dress code is optional (more on this later), and feeling more connected to your “home” are often benefits. For example, spending more time with your kids, pets, spouse (in that order, ha ha), etc.

Flexibility also allows you to step away from some conference calls to use the restroom, get coffee, snacks, fetch the mail, etc. as long as you have a wireless headset and a mute button. I can take care of dishes, laundry, feeding the pets, watering plants, all while discussing why Configuration Manager isn’t going to automatically wipe and re-image every machine in the company from the evil PXE-beast.

Another advantage is it’s easier to multi-task (which can also be a disadvantage). For example, while one conference call is droning on about something you’re not involved with, you can work on other tasks, chat with customers, engineers, etc. As for conference calls, it’s often easier to “back-channel” on separate chat sessions, with others on the same call, than when everyone is physically in a room together.

Yet another advantage with online conferencing is the ease of sharing links, documents, etc. via the chat application (Skype, WebEx, etc.) while the meeting is still going.

The Bad

Some of these will vary by your personality, home environment, and other personal factors.

Solitude. It’s not for everyone. If you don’t like working in isolation (like many programmers prefer), and rather have people around you, then working from home may not be ideal. If you suffer from mild to severe depression, even seasonal, it can be tough, but not impossible, to accommodate.

Background distractions/disruptions. Noisy pets. Leaf blowers outside. Fans. All of these can make you a master of the mute button, but if that gets too frequent, customers (and your boss) may become concerned about your ability to focus.

What to do?

None of the following recommendations imply 24/7 focus. It’s okay if you slip off the wagon once in a while. The important thing is to keep them in front of you and try to do them whenever possible. Make a checklist if you want, whatever works. This is aside from the technical side of things, like getting a wireless Bluetooth headset.

  1. Get outside!!! Walk, run, or even sit in a chair. But get outside at least twice a day. Even if the weather sucks. It’s important to mentally feel connected to the outside world. Sunshine, even indirect/cloudy, stimulates chemical balances in your mind and body (proven, go look it up, if you don’t believe me).
  2. Get away from your desk/chair at least once an hour. Walk to another room (or outside, even better). Just move.
  3. Watch your diet. Avoid sugary snacks or putting too much sweetener in your drinks (or drinking canned/bottled sweetened drinks). Being sedentary and consuming unhealthy foods/drinks is one of the fastest ways to lose control of your health. If you think it’s easy to slip on this when working in an office, it’s twice as easy when working from home. Also, keep snacks AWAY from reach. Put all your food, coffee, drinks, etc. in another room, or across the room you’re in. Make yourself have to get up to get them.
  4. Exercise. If you’re so inclined, do some resistance workout activities, or calisthenics to keep the blood flowing and improve your health. Sitting at home is worse than sitting in an office because you don’t even walk from the office entrance to your desk and back. You can easily lose weight doing this, which is a win-win. Nothing fancy. Even arm circles, squats, and so on are better than clicking a mouse all day.
  5. Set Boundaries. Pick a time to “knock off” work and leave it behind. It’s really really reeeeeeeaaaally easy to keep working long after you should quit for the day. It’s bad for your mind, health, and can affect your sleep pattern, mood, appetite, and family time (or pet time).
  6. Have lunch with a friend, colleague, family member, etc., at least once a week if you can. Nothing fancy or expensive, just coffee or a light lunch will do. Conversation is one of the best vaccines against feeling down from isolation. It also keeps your conversation chops sharp for when you go to meet customers.
  7. Go to local meet-ups. This is VERY important for three reasons: It gets you into groups and interacting with others, it gets you away from your home office, and you learn new things. Just watch out for junk food if they provide it.
  8. Change the Scenery. Work from a different location sometimes. A coffee shop, library, park, shopping mall, etc. Whatever fits your ability to focus on what you do for work. Some people prefer busy places, some prefer quiet places. But getting out of the house is important.
  9. Personal Stuff. Shower, shave, groom, like you’re going to the office. Every day.
  10. Dress up. Yes. One of the most common changes people incur when working from home is working in pajamas, sweats, even underwear. It’s easy and comfortable. It can also gradually affect how you feel and how you conduct yourself in conference calls. You don’t need to put on a suit, although that’s fine if you like. Just jeans and a button down shirt or polo, with socks and shoes. And a belt. Believe it or not, aside from getting away from my desk, this is the most challenging one for me.
  11. Avoid cages. If you listen to music or podcasts, news, or TV shows while working, change up your selection. Avoid patterns that subconsciously make your brain feel like you’re standing still.

Anyhow, I hope this is helpful.

Projects, Scripting, System Center, windows



UPDATE: 1/14/2019 – version 1901.13.2 was posted to address a problem with the previous upload.  Apparently, I posted an out-of-date build initially, so I’ll call this the “had another cup of coffee build”.

Dove-tailing from the previous idiotic blog post, I’ve taken some time off to retool, rethink, redesign and regurgitate “skattertools” as a single PowerShell module.  The new version blends PoSHServer into the module and removes the need to perform a separate install for the local web listener.  The first version of this is 1901.13.1 (as in 2019, 01=January 13th, 1st release).

How to Install and Configure sktools

  • Open a PowerShell console using Run as Administrator
  • Type: Install-Module sktools
  • Type: Import-Module sktools
  • Type: Install-SkatterTools (this creates a default “sktools.txt” configuration file in your “Documents” folder)
  • Type: Start-SkatterTools
  • Open your browser and navigate to http://localhost:8080

This next part is only temporary, and will be improved upon soon:

  • Once the web console is open, expand “Support” and click “Settings” and modify to suit your Configuration Manager site environment.
  • Close and reopen the PowerShell console (still “Run as Administrator”)
  • Type: Start-SkatterTools
  • Refresh your web browser session

Work will continue until morale is eliminated.  Easter eggs are included, sort of.  Thoughts, feedback, bug reports, enhancement requests, angry snarky comments, are all welcome.  Enjoy!

Personal, Projects, Scripting, System Center, windows

And now for another stupid pet project

First, there was project number one. I called it “WWA”, which was a clever short name for “Windows Web Admin”. Even though I kept hearing it sounded like a name for a wrestling tournament.  Anyhow, it fell over and sank into a swamp.

Then there was project number two, or “AppAdmin”, which almost fell over and sank, but it was built inside a big shipyard, and they don’t let things sink there, so it floated for a while (I’m told it’s still afloat somehow).

Then, there was project number three, but I can’t state it’s name for legal reasons, or because I promised it might result in me delivering a flaming box of dog poo to a certain someone’s porch, after they ruined that project just as it was maturing, but that’s for another time and place.

Then there was project four, but I can’t talk about that one either, so I’ll skip to project five, CMWT.  But nobody cares about that one, so number six, was putting a hand-rubbed wax finish on someone else’s PowerShell script, and tossing it up on GitHub and PowerShell Gallery, along with projects seven, eight and nine.  And I’m surprised I still remember how to spell the number 8.  So anyhow…

Announcing SkatterTools

(imagine Morgan Freeman narrating from here on)

What is it?

Skatterbrainz Tools.  A really clever name.

It’s a portable web console app thing, for viewing and modifying things in your Active Directory and Configuration Manager environments, from the comfort of your beer-stained laptop.  Think of it like CMWT if it were (A) trying to copy the concept from Microsoft Windows Admin Center, and (B) didn’t require using a separate “server” or anything special**.  Yes, those are double-asterisks.  That means there’s some hidden footnote down below, but don’t look yet, I have to finish boring the shit out of you with this part first.

Why is it?

Because I needed a break from other things, like family matters during the holidays, a dog that loves chewing on furniture, and a 20 year old cat that wanders the house at 3am making really weird sounds.  And I just wanted to see if it was possible to…

  • Build a 100% web console UX to interface with AD and ConfigMgr using PowerShell
  • Not have to touch IIS or any web hosting mess
  • Make it customize-able, free, and open-source
  • Make it through the holidays once again

Where is it?

  • Like a lot of my stuff, it’s up on GitHub

What can it do?

  • View and cross-link:
    • AD users, computers, groups, sites, sitelinks, domain controllers, OUs
    • ConfigMgr users, devices, collections, applications, packages, boot images, task sequences, updates, and scripts
    • ConfigMgr site status, queries, discovery methods, certificates, Forest publishing, boundary groups and boundaries
    • Software inventory, software files
  • Manage:
    • Add/remove AD group members
    • View computers by AD user profile paths
    • Add/remove ConfigMgr collection members **
    • Those damned double-asterisks again, hmm.

Installation and Setup

  • Download PoSH Server here and install it (don’t worry, I checked it and it seems safe, you can trust me, I worked for the government once, sort of)
  • Download the GitHub repo (big green button – top right – zip option)
  • Extract the “poshserver” folder from the GitHub download into a local path like C:\ThisIsTheDumbestShitEver
  • Open the “config.txt” file and edit the settings to suit your needs
  • It is now ready to blow your mind, almost

Starting it Up

  • Add some gasoline and finely-crushed road flares, oh, wait, wrong stuff…
  • Create a desktop shortcut named “Start SkatterTools”…
Target: powershell.exe Start-PoshServer -HomeDirectory "c:\ThisIsTheDumbestShitEver" -CustomConfig "c:\ThisIsTheDumbestShitEver\sktools.ps1"
  • Create another desktop shortcut, named “Open SkatterTools” or “Coolest Shit Ever!”…
Target: http://localhost:8080/
  • Right-click the first shortcut, select “Run as Administrator”, and wait for it to open and say something like this…
  • Double-click the second shortcut and have your Kleenex box nearby
  • Click on one of the sidebar headings and watch the slick CSS stylings ooze all over your eyeballs and onto the floor.  Compliments of some sample code I found on W3Schools.  What a great site.

If you need to shut it down, just close the browser and close the PowerShell console.  There’s instructions on the PoSH Server site for how to configure it like a service, so it runs as a background job. You don’t have to do that though.

Is there any official support?

  • Are you kidding?
  • You can submit bug reports and enhancement requests using the “Issues” link on the GitHub repo.
  • Work comes first.  I have to keep my customers happy and my bills paid
  • I’m still adding things to it frequently, but work may cause some delays getting around to it
  • You can submit your own changes via GitHub (pull requests, etc.) or just submit Issues if you prefer

Is there a roadmap?  Where is it going next?

  • Real (stupid) men don’t use maps!  The journey is the dream, man.
  • Where are any of us really going?  You ever ask that question?
  • Don’t ask that question, it’s depressing.  Enjoy the now.
  • Seriously, yes, I have a metric butt-ton of things I plan to add or improve

Double Asterisk-o-rama

  • Double-asterisks denote two things here:
    • Features are not yet complete.  Things will change.  Oceans dry up. Mountains wear down. Regimes are toppled.  Keith Richards is forever.
    • This is free stuff, and it comes without any strings attached.  No warranties, or guarantees.  No promises (other than it might possibly entertain you if you’re bored), and poor you gets to assume any and all liability, risk and responsibility for anything bad if you use it improperly or in a production environment of some kind, or any environment where alleged (love that word) damages may have occurred or been coerced by tertiary incidental hereinafters forthwith and notwithstanding, that are void where prohibited, taxed or regulated. Batteries not included.
    • Whatever that means


humor, Personal, Scripting, Technology

$HoHoHo = ($HoList | Do-HoHos -Days 12) version 1812.18.01


UPDATE: 2018.12.18 (1812.18.01) = Thanks to Jim Bezdan (@jimbezdan) for adding the speech synthesizer coolness!  I also fixed the counter in the internal loop.  Now it sounds like HAL 9000 but without getting your pod locked out of the mother ship. 😀

I’m feeling festive today.  And stupid.  But they’re not mutually exclusive, and neither am I, and so can you!   Let’s have some fun…

Paste all of this sticky mess into a file and save it with a .ps1 extension.  Then put on your Bing Crosby MP3 list and run it.

Download from GitHub: https://raw.githubusercontent.com/Skatterbrainz/Utilities/master/Invoke-HoHoHo.ps1

The function…

function Write-ProperCounter {
    param (
      [int] $Number
    if ($Number -gt 3) {
        return $([string]$Number+'th')
    else {
        switch ($Number) {
            1 { return '1st'; break; }
            2 { return '2nd'; break; }
            3 { return '3rd'; break; }

The bag-o-gifts…

$gifts = (
    'a partridge in a Pear tree',
    'Turtle doves, and',
    'French hens',
    'Colly birds',
    'gold rings',
    'geese a-laying',
    'swans a-swimming',
    'maids a-milking',
    'ladies dancing',
    'lords a-leaping',
    'pipers piping',
    'drummers drumming'
# the sleigh ride...
Add-Type -AssemblyName System.Speech
$Speak = New-Object System.Speech.Synthesis.SpeechSynthesizer

for ($i = 0; $i -lt $gifts.Count; $i++) {
    Write-Host "On the $(Write-ProperCounter $($i + 1)) day of Christmas, my true love gave to me:"
    $speak.speak(“On the $(Write-ProperCounter $($i + 1)) day of Christmas, my true love gave to me,”)
    $mygifts = [string[]]$gifts[0..$i]
    $x = $i + 1
    foreach ($gift in $mygifts) {
        if ($x -eq 1) {
            $thisGift = $gift
        else {
            $thisGift = "$x $gift"
        Write-Host "...$thisGift"


Projects, Scripting, Technology

The Little (Code) Stuff That (Sometimes) Matters

As a follow-up to the post about tuning PowerShell scripts, this is going to be more general (language neutral).  I’d like to run through some of the “efficiency” or optimization techniques that apply to all program/script languages, due to how they’re parsed, and executed at the lowest layer of a conventional x86/x64 system.

Why?  Good question.  I’ve been digging into some of the MIT OpenCourseware content and it brought back (good) memories from college studies.  So I figured, why not.

Condition Prioritization

Performance isn’t mentioned as much these days outside of gaming or content streaming topics.  But processing any iterative or selective tasks that deals with larger volumes of data can still benefit greatly from some very simple techniques.

Place the most-common case higher in the condition tests.  This is also a part of heuristics, which is basically intuition or educated guessing, etc.  Using pseudo-code, here’s an example:

while ($rownum -lt $total) {
  switch ($dataset[$rownum].SomeProperty) {
    value1 { Do-Something; break; }
    value2 { Do-SomethingElse; break; }
    default { Fuck-It; break; }

Let’s assume that “value2” is found in 90% of the $dataset rows.  In this basic while-loop with a switch-case condition test, a small data set (chewed up into $dataset), won’t reveal much in terms of prioritizing the switch() tests.  Remember, that mess above is “pseudo-code” so don’t yell at me if it blows up if you try to run it.

Anyhow, what happens when you’re chewing through 400 billion rows of terabytes of data? The difference between putting “value2” above “value1” can be significant.

This is most commonly found with initialization loops.  Those are when you start with a blank or unassigned value, and as the loops continue, the starting value is incremented or modified.  There is often a test within the iteration that checks if the value has been modified from the original.  Since the initial (null) value may only exist until the first cycle of the iteration, it would make sense to move the condition [is modified] above [is not modified] since it skip an unnecessary test on each subsequent iteration cycle.

Make sense?  Geez.  I ran out of coffee 3 hours ago, and it almost makes sense to me.  Just kidding.

Sorted Conditions / Re-Filtering

Another pattern that you may run across is when you need to check if a value is contained within an Array of values.  For most situations, you can just grab the array and check if the value is contained within it and all is good.  But when the search array contains thousands or more elements, and you’re also looping another array to check for elements, you may find that sorting both arrays first reduces the overall runtime.  That’s not all, however.

What happens when the search value begins with “Z” and your search array contains a million records starting with “A”?  You will waste condition testing on A-Y.

What if you instead add a step within the iteration (loop) to essentially “pop” the previously checked items off of the search array?  So, after getting to search value “M”, the search array only contains elements which begin with “M” and on to “Z”, etc.

Figure 1 – Static Target Search Array


Figure 2 – Reduction Target Search Array


To help explain the quasi-mathematical gibberish above: S = Search Time, R = Array Reduction Overhead Time, N = Elements in Search Set.  So R+1 denotes the time incurred by calculating the positional offset, and moving the search array starting index to the calculated value.  Whereas, S alone indicates just starting each iteration on the first element of the (static) target array and incrementing until the matching value is found.

So, what does this look like with PowerShell?  Here’s *one* example…

Figure 3 – PowerShell sample code

param (
  [parameter(Mandatory=$False, HelpMessage="Pretty progressbar, but slower to run!")]
  [switch] $PrettyProgress
# build an array of ("A1","A2",...,"A100","B1","B2",...) up to 26 x 100 = 2600 elements

$searchArray = @()
$elementCount = 1000
$tcount = $elementCount * 26
$charArray = @()


Write-Host "building search array..."
for ($i = 65; $i -le (65+25); $i++) {
  $c = [char]$i
  $charArray += $c
  for ($x = 1; $x -le $elementCount; $x++) {
     $cc = "$c$x"
     $searchArray += $cc
     if ($PrettyProgress) { Write-Progress -Activity "$($charArray -join ' ')" -Status "Building array set" -CurrentOperation "$c $x" -PercentComplete $(($m / $tcount) * 100) }
# define list of search values...
$elementList = @("A50","C99","D75","K400","M500","T600","Z900")
$randomList  = @("T505","C99","J755","K400","A55","U401","Z960")

Write-Host "`nStatic search array"
foreach ($v in $elementList) {
  $t1 = Get-Date
  $test = ($v -in $searchArray)
  $t2 = Get-Date
  Write-Output "$v = $((New-TimeSpan -Start $t1 -End $t2).TotalSeconds)"

# protect the original target array for possible future use...
$tempArray = $searchArray

Write-Host "`nReduction search array"
foreach ($v in $elementList) {
  $t1 = Get-Date
  $test = ($v -in $tempArray)
  $t2 = Get-Date
  # this is the real "R"...
  $pos = [array]::IndexOf($tempArray, $v)
  $tempArray = $tempArray[$pos..$tempArray.GetUpperBound(0)]
  Write-Output "$v = $((New-TimeSpan -Start $t1 -End $t2).TotalSeconds)"

Figure 4 – PowerShell example process output


The time values are in seconds, and will vary with each run depending upon thread processing overhead incurred by the host background processes.  But in general, the delta between the matched values in each iteration will be roughly the same.  To see this visually, here’s an Excel version…

Figure 4 – Spreadsheet table and Graph result


It’s worth noting that the impact of R may vary by language, as well as processing platform (hardware, operating system, etc.) along a different vector than others, but that within the iteration tests, the differences should be roughly similar.

There are other methods to reduce the target array as well, which may depend upon the software language used to process the tasks.  For example, whether the interpreter or compiler makes a complete copy of the search array in the background in order to provide the index offset starting point to the script.

Again, this is all relatively meaningless for smaller data sets, or less complex data structures.  And it really only provides significant value for sequential (ordered) search operations, not for random search operations.

So, some questions might arise from this:

  1. If the source array is not sorted, does the sorting operation itself wipe out the aggregate time savings of the reduction approach?
  2. Where is the “tipping point” that would cause this approach to be of value?

These are difficult to answer.  The nature of the data within the array will have an impact I’m sure, as might the nature by which the array is provided (on demand or static storage, etc.) . To paraphrase a Don Jones statement: “try it and see.”

Now that I’m done pretending to be smart, I’m going to grab a beer and go back to being stupid.  As always – I welcome your feedback.  – Enjoy your weekend!