My First Day as Microsoft CEO


First of all, thank you all for being here today, in my 800 bedroom cabin atop the humble foot hill called Mt. Everest. I hope your parachutes all provided a smooth arrival?  It is an honor having you here to listen to me pontificate about my vision for Microsoft, now that I’ve been voted Ultimate Excecutive Officer, or UEO. I plan to outline changes which I feel will help launch our fine organization to the “next level” (air quotes).

Before I continue, I’d like to take a moment to thank Satya for all his hard work.  He exemplifies all of the qualities and traits a CEO and leader should have, of which I have none.  But that’s beside the point.  Actually, he doesn’t yet know I’m the new CEO or UEO, he thinks the plane he’s on is taking him to meet Oprah for an interview, but I paid the pilot to fly in circles over some place near Antarctica, and I had all the door locks changed.  Please thank Satya, if you ever see him again, for the open bar.

So, first things first:

As of today, all former prefixes like “Active”, “Live”, “One”, “Visual” and so on are being changed to “Awesome”.  So it’s Awesome Directory, Awesome Studio, and Awesome Drive.  Get used to it.  And from now on, no product will have a name that takes more than 5 syllables to pronounce.

Licensing is going to change as well.  A new program called “4th grade review” is going live today.  We will randomly-select a 4th grade student in a random school in Kenya.  They will read the EULA to their classmates, and if even one student looks confused, they get to rewrite it.

Servicing channels are going to be renamed yet one more time.  They went from “Current Branch” to “Semi-Annual blah blah”.  But now we’ll have the following names:

  • “I hate change!” (formerly LTSB/LTSC) is now once every 5 years
  • “What’s the hurry?” (formerly CBB/Semi-Annual) is now once every year
  • “I kind of miss getting updates” (formerly CB/Semi-Annual Targeted) is now twice a year
  • and “Where the fuck are my updates?!” (formerly Insider Preview) is now every week

Changes to Windows

Windows 10 “Enterprise” SKU images will no longer include games or media services apps.  In fact, we won’t even allow those to be installed.  If you want them, buy the Home edition.  The Professional edition will offer it as an option, but not installed by default.

The Control Panel will be entirely migrated into Settings by the time I leave the stage and run out the back door.

We have a new edition called Windows “In-Your-Face” edition, which will be entirely FREE as long as you agree to so much telemetry and advertisements that you might forget what apps you were trying to launch.

All application installations will have to be MSI, C2R, App-V or portable .Exe only.  No more legacy garbage.  Stubborn app vendors can suck it.

Other Products

Office 365 is now going to be entirely browser-based.  No more installations.  Every single feature you had in the C2R and MSI packages will be in the new browser-app.  You’re welcome.

A new driver “service” (air quotes again) is being released.  The code name is Device Optimization Universal Configuration Hardware Emulation, or just DOUCHE for short.  All vendor drivers will have to check into our portal and we will manage a true PnP experience without any manual intervention required, ever.  As in never, or ever, or which ever never you ever never prefer.  Vendors can no longer install drivers without coming through us.  PnP is now going to work the way we envisioned it should work, back when we were eating mushrooms atop some mountain in Chile.  Good times (drifts off with a dazed look)…. Oh, yeah, it’ll be like a toaster.  Plug it in, and watch it burn the toast.


All versioning will be consistent across all products from now on.  No more 10 for this, 2017 for that, or 2.3.5550.0000.1000 for the other. There’s going to be one version format only.  We haven’t settled on it yet, but whoever wins the beer funnel challenge gets to pick it.

We signed a deal with Jeff B. to get Alexa installed on every Windows SKU.  We will be including an app that lets you pay to watch Alexa and Cortana fight in a 3D virtual cage of death, only with our Hololens product, obviously, and all proceeds going to charity.

SQL Server is now renamed to Awesome Database Server.

All external web portals like Fast Track, Partner, Azure, O365, and so on are being merged into one web portal and one credential set across all of them.  And speaking of credentials, you can now open multiple Azure instances in a single browser using separate credentials.  You’re welcome.

We will also start a new customer loyalty program next week.  The plan is simple.  Once a day, the first person to show up in front of a Microsoft store with a bullhorn, shouting “Java sucks and so does Flash” gets a t-shirt.

I’d like to continue with more, but I was just told that Satya’s plane is on the way back so I have to meet my Uber ride out back.  Sorry I don’t have time for questions. Thank you!


Finally! Dave’s Master’s Class on Programming Skills

You’ve waited years, in fact, decades, for this once-in-a-lifetime chance to peer inside the vast and empty space of my mind to gain invaluable insight to insightful and invaluable insights behind expert-level coding mastery! Say that ten times.

Well, here it is!

Open your favorite code editor and paste in whatever code you feel like working with right now.  Let’s get started!


  • It’s important to keep a can of compressed air nearby in order to cool down the keyboard, as it will likely reach unbearable temperatures
  • I also recommend a small bowl filled with ice cubes to cool your fingers down after each lesson.
  • Liquefied Caffeine
  • Sugary ingestibles
  • Ear buds or headphones
  • Ear plugs for anyone else in the room

Lesson 1 – Code Formatting

  1. Press SHIFT+CTRL+[>] and DEL
  2. Press SHIFT+CTRL+[>] and DEL
  3. Press SHIFT+CTRL+[>] and DEL
  4. Press SHIFT+CTRL+[>] and DEL
  5. Press SHIFT+CTRL+[>] and DEL
  6. Press SHIFT+CTRL+[>] and DEL
  7. Press SHIFT+CTRL+[>] and DEL
  8. Press SHIFT+CTRL+[>] and DEL
  9. Press SHIFT+CTRL+[>] and DEL
  10. Press SHIFT+CTRL+[>] and DEL
  11. Press SHIFT+CTRL+[>] and DEL
  12. Press SHIFT+CTRL+[>] and DEL
  13. Press SHIFT+CTRL+[>] and DEL
  14. Press SHIFT+CTRL+[>] and DEL
  15. Press SHIFT+CTRL+[>] and DEL
  16. Press SHIFT+CTRL+[>] and DEL
  17. Press SHIFT+CTRL+[>] and DEL
  18. Press SHIFT+CTRL+[>] and DEL
  19. Press SHIFT+CTRL+[>] and DEL
  20. Press SHIFT+CTRL+[>] and DEL
  21. Press SHIFT+CTRL+[>] and DEL
  22. Press SHIFT+CTRL+[>] and DEL
  23. Press SHIFT+CTRL+[>] and DEL
  24. Press SHIFT+CTRL+[>] and DEL
  25. Press SHIFT+CTRL+[>] and DEL
  26. Press SHIFT+CTRL+[>] and DEL
  27. Press SHIFT+CTRL+[>] and DEL
  28. Press SHIFT+CTRL+[>] and DEL
  29. Press SHIFT+CTRL+[>] and DEL
  30. Press SHIFT+CTRL+[>] and DEL
  31. Press SHIFT+CTRL+[>] and DEL
  32. Press SHIFT+CTRL+[>] and DEL
  33. Press SHIFT+CTRL+[>] and DEL
  34. Press SHIFT+CTRL+[>] and DEL
  35. Press SHIFT+CTRL+[>] and DEL
  36. Press SHIFT+CTRL+[>] and DEL
  37. Press SHIFT+CTRL+[>] and DEL
  38. Press SHIFT+CTRL+[>] and DEL
  39. Press SHIFT+CTRL+[>] and DEL
  40. Press SHIFT+CTRL+[>] and DEL
  41. Press SHIFT+CTRL+[>] and DEL
  42. Press SHIFT+CTRL+[>] and DEL
  43. Press SHIFT+CTRL+[>] and DEL
  44. Press SHIFT+CTRL+[>] and DEL
  45. Press SHIFT+CTRL+[>] and DEL
  46. Press SHIFT+CTRL+[>] and DEL
  47. Press SHIFT+CTRL+[>] and DEL
  48. Press SHIFT+CTRL+[>] and DEL
  49. Press SHIFT+CTRL+[>] and DEL
  50. Press SHIFT+CTRL+[>] and DEL

Lesson 2 – Refactoring

  1. Highlight a line of code
  2. Press CTRL+C
  3. Click on the next empty line
  4. Press CTRL+V and ENTER
  5. Press CTRL+V and ENTER
  6. Press CTRL+V and ENTER
  7. Press CTRL+V and ENTER
  8. Press CTRL+V and ENTER
  9. Press CTRL+V and ENTER
  10. Press CTRL+V and ENTER
  11. Press CTRL+V and ENTER
  12. Press CTRL+V and ENTER
  13. Press CTRL+V and ENTER
  14. Press CTRL+V and ENTER
  15. Press CTRL+V and ENTER
  16. Press CTRL+V and ENTER
  17. Press CTRL+V and ENTER
  18. Press CTRL+V and ENTER
  19. Press CTRL+V and ENTER
  20. Press CTRL+V and ENTER
  21. Press CTRL+V and ENTER
  22. Press CTRL+V and ENTER
  23. Press CTRL+V and ENTER
  24. Press CTRL+V and ENTER
  25. Press CTRL+V and ENTER
  26. Press CTRL+V and ENTER
  27. Press CTRL+V and ENTER
  28. Press CTRL+V and ENTER
  29. Press CTRL+V and ENTER
  30. Press CTRL+V and ENTER
  31. Press CTRL+V and ENTER
  32. Press CTRL+V and ENTER
  33. Press CTRL+V and ENTER
  34. Press CTRL+V and ENTER
  35. Press CTRL+V and ENTER
  36. Press CTRL+V and ENTER
  37. Press CTRL+V and ENTER
  38. Press CTRL+V and ENTER
  39. Press CTRL+V and ENTER
  40. Press CTRL+V and ENTER
  41. Press CTRL+V and ENTER
  42. Press CTRL+V and ENTER
  43. Press CTRL+V and ENTER
  44. Press CTRL+V and ENTER
  45. Press CTRL+V and ENTER
  46. Press CTRL+V and ENTER
  47. Press CTRL+V and ENTER
  48. Press CTRL+V and ENTER
  49. Press CTRL+V and ENTER
  50. Press CTRL+V and ENTER

Lesson 3 – Expert Refactoring

  1. Place cursor at beginning of first line of code
  2. Press TAB
  3. Press [Down Arrow]+[Home]+TAB
  4. Press [Down Arrow]+[Home]+TAB
  5. Press [Down Arrow]+[Home]+TAB
  6. Press [Down Arrow]+[Home]+TAB
  7. Press [Down Arrow]+[Home]+TAB
  8. Press [Down Arrow]+[Home]+TAB
  9. Press [Down Arrow]+[Home]+TAB
  10. Press [Down Arrow]+[Home]+TAB
  11. Press [Down Arrow]+[Home]+TAB
  12. Press [Down Arrow]+[Home]+TAB
  13. Press [Down Arrow]+[Home]+TAB
  14. Press [Down Arrow]+[Home]+TAB
  15. Press [Down Arrow]+[Home]+TAB
  16. Press [Down Arrow]+[Home]+TAB
  17. Press [Down Arrow]+[Home]+TAB
  18. Press [Down Arrow]+[Home]+TAB
  19. Press [Down Arrow]+[Home]+TAB
  20. Press [Down Arrow]+[Home]+TAB
  21. Press [Down Arrow]+[Home]+TAB
  22. Press [Down Arrow]+[Home]+TAB
  23. Press [Down Arrow]+[Home]+TAB
  24. Press [Down Arrow]+[Home]+TAB
  25. Press [Down Arrow]+[Home]+TAB
  26. Press [Down Arrow]+[Home]+TAB
  27. Press [Down Arrow]+[Home]+TAB
  28. Press [Down Arrow]+[Home]+TAB
  29. Press [Down Arrow]+[Home]+TAB
  30. Press [Down Arrow]+[Home]+TAB
  31. Press [Down Arrow]+[Home]+TAB
  32. Press [Down Arrow]+[Home]+TAB
  33. Press [Down Arrow]+[Home]+TAB
  34. Press [Down Arrow]+[Home]+TAB
  35. Press [Down Arrow]+[Home]+TAB
  36. Press [Down Arrow]+[Home]+TAB
  37. Press [Down Arrow]+[Home]+TAB
  38. Press [Down Arrow]+[Home]+TAB
  39. Press [Down Arrow]+[Home]+TAB
  40. Press [Down Arrow]+[Home]+TAB
  41. Press [Down Arrow]+[Home]+TAB
  42. Press [Down Arrow]+[Home]+TAB
  43. Press [Down Arrow]+[Home]+TAB
  44. Press [Down Arrow]+[Home]+TAB
  45. Press [Down Arrow]+[Home]+TAB
  46. Press [Down Arrow]+[Home]+TAB
  47. Press [Down Arrow]+[Home]+TAB
  48. Press [Down Arrow]+[Home]+TAB
  49. Press [Down Arrow]+[Home]+TAB
  50. Press [Down Arrow]+[Home]+TAB

Lesson 4 – Super Expert Uber Refactoring

  1. Click the little [+] code-folding handle to collapse a bunch of code
  2. Click the tool icon to comment the entire block
  3. Press CTRL+N (new file)
  4. CTRL+V
  5. Repeat for every code block
  6. After every code block is in its own file, reverse the process and paste each file contents back into the original file
  7. Repeat steps 1 through 6 about 5,000 times


Repeat the above skill drills 5,000 times every day for the next 5,000 days and you’ll be ready to apply for that fantastic junior entry level programmer analyst position you’ve been waiting for!  Don’t wait!  Get started today!

Windows 10 Secrets: Undocumented Hotkeys

The next time you want to impress someone at a social gathering, wait until they’ve finished rambling about how much they know about Windows 10. Then set your drink down calmly, smile and chuckle “That’s cute. I remember when I first learned those tricks. Years ago.  Before I became a man.” (tip: insert woman here, if appropriate)

Then hit them with these proven hotkey secrets:

Un-stick any frozen application

Press CTRL+ALT+Space+ smack the shit out of the keyboard. Any keys will do.

Recover a frozen web form

Press CTRL+ALT+DEL then grasp the keyboard in both hands and forcefully rip the USB connector loose.  Bonus tip: scream as loud as possible while removing the keyboard to speed up the recovery.

Automatically Rebuff an Annoying Facebook Comment

Press CTRL+ALT and press your face against the display screen and scream as loud as you can “you stupid MF-er!!!

Remember, computers don’t kill people.  People kill people… and their computers.

Discussion Points / FudgePop again


So I had a nice discussion about this FudgePop thing, which is starting to sound like a marketing ploy.  But trust me, it’s only a project, nothing being marketed.  I’m not sure if I’ll add any more stuff to it unless I get really bored or some sort of revenue scheme hatches from it.  Again, that’s unlikely at this point.  As with CMWT, GPODoc, and CMBuild, these are just for fun and exercise.  I’m pretty sure some of you are tired of hearing about this thing with a childish name attached to it, and that’s fine. But keep in mind, the same could be said about the U.S. government, but I digress. 🙂

In case you can’t tell already, I’m slowly getting back to blogging after a brief hiatus.  I still don’t know where this is going to go, or for how long, etc.  One day at a time.

So, given that this is all open source and available on GitHub, here’s some thoughts for anyone feeling bored enough to fork or branch this for a future pull, or just to run off and get rich while I toil for table scraps, here’s some roadmap thoughts…

Mighta, Oughta, Woulda, Coulda, Shoulda…


Inventory collection and reporting would be fairly simple to add.  I already built a proof-of-concept branch to collect data and upload it to a SQL database in Azure.  Anyone can do that.  What I would do differently is store a local copy of the payload with a checksum, maybe store the checksum and timestamp in the Registry, along with a timestamp of “LastInventoryUpload”.  Then subsequent inventory cycles would compare the new output checksum against that previous and only upload if the values are different.  Sound familiar?

Offline Mode

Rather than reading the control XML in real-time on each execution cycle, it could download the latest version to a local cache.  Then continue to enforce that on subsequent execution cycles if there are no available Internet connections.

Smaller Stuff

Other suggestions for possible consideration:

  • Download caching for either (or both) the Files and Win32 Apps control groups (fairly simple)
  • Manage local Group Policy for workgroup computers (ideas) (somewhat complex and limited, but promising)
  • Add, modify local user accounts (easy)

What it can do now

As of build 1.0.16, FudgePop can do the following on remote computers which are configured with the agent service:

  • Chocolatey Packages
    • Install, Update, Remove
  • Win32 Application Packages
    • Install, Uninstall
  •  Files
    • Copy, Move, Rename, Delete, Download
  • Folders
    • Create, Delete, Empty
  • Windows Services
    • Modify/Configure, Start, Stop, Restart
  • Registry
    • Create, Delete (keys, values)
  • Permissions (ACLs)
    • Files/Folders: Modify
    • Registry: Not implemented
  • PowerShell Modules
    • Install, Update
  • Shortcuts
    • Create, Delete
  • AppX Applications
    • Remove
  • Windows Update
    • Force Scan/Download/Installation
  • Inventory
    • Basic HTML reporting
  • Targeting
    • Device = comma-delimited list of device names (NetBIOS names)
    • Collection = arbitrary name which is then assigned a comma-delimited list of device names.
    • Enable = true/false (per setting or group, or per control file)
    • Central authority = deploy changes from central XML file, even redirect to new XML files without touching remote device by hand.
  • Ingredients
    • PowerShell and XML, and a sprinkle of cloud storage (to host control files)
  • Tools
    • Visual Studio Code, Notepad++, Paint.Net (for the spiffy icon)

The Future

Who knows.  I don’t even know what my 401-k is doing tomorrow.

My Favorite Things: 2017

My Favorite Tech Web Sites / Tools

My Favorite Tech Web Sites / Blogs

My Favorite Tech Web Sites / References

My Favorite Podcasts (iTunes, Google Play, PodCast Addict, etc.)

  • Freakonomics Radio
  • NPR Fresh Air
  • Malcolm Gladwell – Revisionist History
  • The Joe Rogan Experience
  • Invisibilia
  • 60 Minutes
  • The Tim Ferriss Show
  • Planet Money
  • Star Talk with Neil deGrasse Tyson

My Favorite Wife

  • My first and only wife: Kathy

My Favorite Children

  • Our four: Rachel, Sarah, Gabrielle and Zachary

My Favorite Cat

  • Oreo (our only cat)

My Favorite Dog

  • Dory and Emily (tied for first place)

My Favorite Drinks

  • Coffee
  • The Glenlivet
  • The Glenfiddich
  • A good Root Beer Float
  • Water

My Favorite Musicians / Bands (new to me only)

My Favorite Laptops

  • HP Elitebook 9470m Folio

My Favorite Pet Supply

My Favorite Tools

  • Snap-On
  • DeWalt

My Favorite Beers

  • Sam Adams Utopia
  • Dogfish Head 120, Palo Santo Maron, and Three Philosophers
  • St. Bernardus Abt. 12

My Favorite Wines

  • Merlot
  • Malbec
  • Pinot Noir
  • Tempranillo

This is a very VERY short list.  I could add much more.

Quick Rundown on FudgePop and why the Silly Name

The name comes from a wine-infused discussion around Chocolatey, which was around Nuget, which was around Brooklyn Brewery’s Black Chocolatey Stout, which was bout $9 per bottle.  This post however, was sponsored by half a bottle of Pinot Noir, by an unnamed winery somewhere in Wineville.  FudgePop itself was contrived from a casual “bet” over a bottle of Dogfish Head 120 IPA that it’s possible to use nothing but free tools and features included with Windows 10 to manage a “group” of such devices from a central location, regardless of where those other devices are located.

Btw, I just uploaded 1.0.16 to the PowerShell gallery


Install-Module FudgePop
Import-Module FudgePop

Note: .NET framework 3.5 is recommended for some Chocolatey packages.  FudgePop does not install .NET 3.5 by default.

Use the following to confirm/verify the latest version…


Once the module has been installed on each subsequent victim, er, I mean “device”, scaling out is just a matter of replicating the same steps as the previous device.  On domain-joined devices, you can use Group Policy to deploy it as well as via PowerShell deployment from Intune for devices joined to Azure AD Premium.  Workgroup computers require manual intervention (hands-on, remote connection, etc.)



Creates a new XML control file using the default (sample) provided with the module.  Other samples are posted on the project GitHub site.  Note that all settings are disabled by default, and filled in with sample/example information only.

New-FudgePopTemplate -OutputFile "c:\devtest\control.xml"


Configures default options such as control file location, enable/disable recurring scheduled execution, and hourly interval between scheduled executions.



Executes the FudgePop agent.  If you configured it correctly, magical things happen before your drunken eyes.  If you goofed up the configuration, it forces you to watch The View until your eyeballs bleed.  That last feature is not yet enabled.  Note that this function is what is called by the RunFudgePop.bat script during each scheduled execution (if scheduled execution is enabled).

Invoke-FudgePop -TestMode -Verbose
Invoke-FudgePop -Verbose


Disables and uninstalls FudgePop from a client device.  It then applies 440 volts of taser current to your genitals until you reinstall it.  jk

Remove-FudgePop -Complete


Displays information about current configuration, last runtime status and rectal thermometer temperature of your cat or dog.  That last feature is not yet enabled.



Bonus, low-calorie, gluten-free, and totally vegan function to export basic inventory data from your meth-addicted Windows device.  It was a proof-of-concept to export a basic set of juicy and utterly useless data into an Azure SQL database so I could win a bet and enjoy a free sushi lunch.  The Azure SQL interface is planned for a future version, but will ultimately depend on user feedback (i.e. does anyone really want that capability?) and how badly I want more sushi.

Get-FudgePopInventory -Computer d001,d002,d003
Get-FudgePopInventory -FilePath "c:\reports\"
Get-FudgePopInventory -StyleSheet "c:\reports\custom.css"


The markdown files were cranked out by a team of recovering caffeine addicts fresh from the Port Authority bus terminal.  Actually, they were cranked out with PlatyPs, which is pretty cool, and doesn’t come from the bus terminal.  You can find them in the “docs” folder beneath the module path (e.g. “c:\program files\WindowsPowerShell\Modules\fudgepop\1.0.16\docs”).

Use FudgePop in a Sentence

Hey man.  I just took a FudgePop on your mattress.”

Sample Scenario

You’re drunk.  But that’s not unusual with your day job as an airline pilot.  You staggered out of an airport terminal, and fell face-first into a random Uber vehicle with the doors open.  You wake up the next morning at your apartment, in a bathtub filled with ice, and a clear plastic aquarium tube attached to where your left kidney used to be.  You get up carefully, and drag the tube with you to the kitchen and make some fresh ramen with Srirachi sauce and a cup of coffee.  The entire time you keep thinking that of all his pranks, your roommate did a fantastic job of making these sutures look and feel authentic.

You grab your roommate’s laptop which has Windows 10 1709 installed, and you logon as a local administrator account and open a PowerShell console using “Run as Administrator”

You set the execution policy to Unrestricted, while staring at the PowerShell book with Don Jones’ picture on it, and say to yourself, “I know, this is very very bad, but I live on the edge baby.”

Set-ExecutionPolicy Unrestricted

You then use one finger on each hand to type:

Install-Module FudgePop

…and press Enter.

(example only. actual results may vary, depending upon your alcohol intake and criminal record)

Then, you can’t help it, but you hurl directly onto your cat, who returns the favor by urinating in your snow boots.  You use the cat to wipe your face off, and return back to the keyboard and type:

Import-Module FudgePop

…and press Enter.

After an IV drip of Death From Above coffee, and a Cat Shampoo enema, you type:

New-FudgePopTemplate -OutputFile wtfisthis.xml

…and make a new control XML file.  You edit it to suit your test environment (computer names, collection names, apps, etc.) and copy the XML file to your GitHub Gist.  You get the “raw” Gist URL and copy the address to your clipboard.

You make some breakfast from whatever isn’t fuzzy in the fridge and then go back to the keyboard, where you cat fell asleep, causing the letter “zzzzzz” to overflow the buffer and make a machine gun beep sound.  You realize that wasn’t Cat Shampoo, but Drano that your poured into the Cat Shampoo bottle because the Drano bottle leaked after you dropped while trying to light your vaporizer with a match.  You scoot the kitty off the keyboard, brush off the hair balls and type…


You answer the prompts with one hand, choosing to enable the scheduled run option for 3 hour intervals, while the other hand is manipulating a pair of greasy chopsticks you found in the trashcan because you couldn’t find a fork, spoon, or plastic spork anywhere.

You look around for the mouse, but it’s gone.  After scouring the entire house/apartment, you find it buried in the kitty litter box.  You recover it, wipe it off on your pants and set it back on the desk and use it to poke around to see what all this FudgePop mess did to your roommate’s computer…

  • It created a registry hive under HKLM:Software\FudgePop
  • It created a PowerShell module folder under $env:PSModulePath
  • It created a Scheduled Task named “FudgePop Agent” under the root folder
  • It added $100 to your bank account (not really)

You go back to the PowerShell console, pause, look around for the cat, and think “what in the **** am I doing anyway?” and after 30 seconds of staring into space you remember that you were using your roommate’s laptop for an important experiment, and you continue on.

You type in…

Invoke-FudgePop -TestMode -Verbose

…so you can see everything it would have done if it weren’t using that stupid -TestMode switch.  It prompts you to trust some mysterious thing called an “untrusted repository”, but you’ve got 55 gallons of testosterone coursing through your veins, and no stupid sissy warnings are going to scare you off.  And besides, you can’t spell “untrusted” without the word “trust” so how could it be bad?  Just like your cousin who kept whining about putting that safety “on” when you were shooting at tin cans and you ignored him and shoot him in the foot.  Like that’s any excuse to use safety stuff.  Yeah.  But it’s okay, because FudgePop is only asking you to trust the PowerShell Gallery, so it can install some needed tools.

You toss back another glass of liquor, notice the cat staring at you, making you wonder if she spiked your glass with something special.  You ignore that feeling and type…

Invoke-FudgePop -Verbose

…just to see what it’s doing to diabolically reconfigure your roommate’s laptop into a tactical nuclear toilet flushing device.  Not really, but it’s likely that it’s creating a desktop shortcut for Internet Explorer, installed a bunch of Chocolatey packages like 7-Zip, Visual Studio Code, Office 365 ProPlus, and Putty, added some folders, files and registry keys, reconfigured some services, and installed a custom .MSI or .EXE from an on-premises server share (you know, the “Chris Hansen Kiddy Porn Undercover Arrest Me Kit 2015 Premium Edition.exe” with the important /S switch).

Everything looks great.

But, being that you don’t trust anyone who’s birth certificate says their name is really ‘skatterbrainz’ you decide to look under C:\Windows\Temp and find a “fudgepop.log” file and open it up.  Your skull falls in pieces on the floor due to the overload of retinal bombardment of verbosity and quantum-level granularity, and because you’re still hung over AF.  But that’s beside the point.  You make some tweaks to the control XML file, rub your hands together while nodding and grinning, laughing like a German lab scientist in a WWII movie, not realizing your cat is going to the bathroom on something else you value on the other side of the room.  You install FudgePop on another device and repeat the process.

You carefully tie that plastic kidney tube closed using the twisty-tie from the plastic bag you use for the litter box.

Later, your room mate returns, sees what you’ve done and pounds your face into the sofa and leaves.

I hope to return in 2018.  Until then: Happy New Year!

Rants about Configuration Manager and PowerShell

Note: Although I’m still on hiatus, I was reminded about a few blog posts sitting in my drafts queue that need to get posted before they get stale like me.  There may be a few more.  Until then – cheers!

How many times have you seen PowerShell code that looks similar to the following?

param (
  [parameter(Mandatory = $True, HelpMessage = "Site Server Name", ValueFromPipeline = $True)]
  [string] $ServerName, 
  [parameter(Mandatory = $True, HelpMessage = "Site Code")]
  [string] $SiteCode
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" -Verbose:$False

Notice how this is expecting the user to (manually) provide the name of the server, the site code, and so on?  What bothers me most about this is that these two pieces of information are easy to obtain directly from the local computer.  Even when running on a workstation or member server which is not a ConfigMgr site system, you can easily obtain the site server name and the site code.  So why ask a user to key this in manually?

I’ve blogged about this general topic a few times before, but I still see most snippets posted online today doing this exact same approach to setting up the most basic, albeit “core” aspects, on which the rest of the script depends.  Bad idea!  So 1990’s.

Think of this in alternate contextual forms:

  • We expect to drop AD computers and users into Organizational Units (OUs) to automate Group Policy management processes.
  • We expect to drop ConfigMgr resources into Collections to automate policy and content deployment processes.
  • We expect to place AD domain controllers into Sites to automate replication optimization processes.
  • We expect to place AD users into security groups to automate permissions inheritance processes.
  • So why don’t we expect our scripts to drop into execution environments and inherit and automate processes as well?

Reiterating one of the lectures from my CS days in college, “every program needs to start with stated assumptions“.  Other great bits of advice: “If it can be automated, then automate the shit out of it.”, and, “If you automate a broken process, you can only get an automated broken process.” (that was from a manager, not a professor, but still top of my list).  I could go on much longer, but maybe that would be best for an in-person discussion or speaking event.  God help you.

So, the questions should be:  what then are the expectations when executing a program (or script)?  I realize this is 100-level stuff right here, but so-often I see people dive into writing code before they pause to answer some basic questions about how it will be used.  The most basic questions should be…

Where will it be used?

When will it be used?

How will it be used?

and… Who, will use it?

Let’s define some base assumptions:

  • Where?  On the ConfigMgr site server (locally or via PSRemoting, WSMAN/Rexec/WinRS/PsExec, etc.)
  • When?  On demand, or via scheduled job
  • How?  PowerShell + ConfigMgr Admin Console framework
  • Who?  A user or process-owner account which has local Administrator rights

Assuming this is going to be invoked on a Central Administration Server (CAS) or Primary Site Server (PSS), we can also assume that the ConfigMgr admin console will be installed.  And along with that, it will have the PowerShell cmdlet library available as well.

In this scenario, we can easily obtain the name of the server, as well as the Configuration Manager site code.  There’s no need to ask a user to manually input this information, because, as we’ve seen many times, manual intervention causes cars to crash, trains to derail, and space shuttles to explode.  Humans are bad.

There are several ways to get the site server name (locally):

# environment
$ServerName = ($env:COMPUTERNAME+'.'+$env:USERDNSDOMAIN)

$ServerName = Get-WmiObject -Class Win32_ComputerSystem | Foreach {$_.Name+'.'+$_.Domain}

# registry
$ServerName = (Get-Item -Path HKLM:SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName).GetValue('ComputerName')

You get the idea.  The easiest (and fastest) may be the environment variable option.  So, we can also use this to set a default value even when using input parameters…

param (
  [parameter(Mandatory = $False, HelpMessage = "Site Server Name", ValueFromPipeline = $True)]
  [string] $ServerName = $($env:COMPUTERNAME+'.'+$env:USERDNSDOMAIN)
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" -Verbose:$False

We can also fetch the ConfigMgr Site Code using the Registry…

$SiteCode = (Get-Item -Path HKLM:\SOFTWARE\Microsoft\SMS\Identification).GetValue('Site Code')
$OldLoc = (Get-Location).Path
Set-Location "$($SiteCode):\" -Verbose:$False

So, that works fine when the assumption is that the script will be invoked directly on a ConfigMgr site server.

As a side note, there’s plenty of other useful information exposed in the Registry location HKLM:SOFTWARE\Microsoft\SMS

Going Remote

Now, let’s change the assumptions a bit.  Now the script will be invoked on a workstation, which is joined to the same AD domain as the ConfigMgr site.  Assuming the workstation is also a ConfigMgr client, and the desired Site Server is also the Management Point (MP) for this workstation, we can fetch the server name from the local machine as well, but it resides under the client Registry tree, rather than the site system Registry tree…

$mp = ((Get-Item -Path HKLM:SOFTWARE\Microsoft\CCMSetup).GetValue('LastValidMP') -split '//')[1]

Even if the MP is not the Primary we wish to connect to, we can use the MP information and perform additional queries against its Registry to “walk-up” the hierarchy to find the Primary we wish to connect with (if necessary).

Note: The actual value of “LastValidMP” is stored in URI format… example…


So if we split the string into a 2-element array on the instance of double slashes, we can then grab the index=1 value (2nd element), which is the FQDN of the MP.  You could also use .Substring() or .Replace() to manipulate the string in order to remove the http:// prefix.

$mp = (Get-Item -Path HKLM:SOFTWARE\Microsoft\CCMSetup).GetValue('LastValidMP')
$mp = $mp.Substring(7)
# or
$mp = $mp.Replace('http://', '') # or -replace 'http://', ''

So, now we have the ConfigMgr site server (again, assuming this is a small site and the MP is the primary), we can still fetch the site code either from the local client environment, or from the remote registry.  Either will work…

$SiteCode = (Get-Item -Path HKLM:SOFTWARE\Microsoft\CCM\CcmEval).GetValue('LastSiteCode')

You may be thinking (or saying aloud) right about now “so what? what can I do with this from a workstation?”  Well, if the ConfigMgr Admin console is installed, you have access to the same PowerShell module that is available on the site server.  So, if you intend to run your script locally on a workstation (or member server) which has the ConfigMgr Admin console installed, you can automate the site server name, and site code parts of your script very easily…

$mp = ((Get-Item -Path HKLM:SOFTWARE\Microsoft\CCMSetup).GetValue('LastValidMP') -split '//')[1]
$SiteCode = (Get-Item -Path HKLM:SOFTWARE\Microsoft\CCM\CcmEval).GetValue('LastSiteCode')
Import-Module "$($ENV:SMS_ADMIN_UI_PATH)\..\ConfigurationManager.psd1" -Verbose:$False
$OldLoc = (Get-Location).Path
Set-Location "$($SiteCode):\" -Verbose:$False

Keep in mind that no matter where you execute your script code, it will only be able to access resources which are allowed for the user context under which it is running.  So, if you run the script under your own domain account, and that account has limited rights in ConfigMgr, it’s going to be limited in what it can do against the site system environment as well.  I know many of you will shake your heads when reading this, but it is very often overlooked.

Speaking of the ConfigMgr Registry (SMS) tree

Beneath the HKLM:SOFTWARE\Microsoft\SMS registry tree, there are plenty of other useful pieces of information.

  • Server
  • Full Version
  • Domain
  • Parent Site Code (useful for Secondary sites and CAS environments)
  • Parent Server (ditto)
  • Site Name
  • Installation Directory
  • DatabaseMachineName
  • DatabaseName

So, even if your script needs to make some database connections to SQL Server (ADO, etc.) you can fetch the site database server and site database name, to automate the connection setup and continue onward.

Okay, so now what?  Well, there’s more.  Another thing I see way too-often is reinventing the wheel.  And not just any wheel, but octagonal wheels.  Here’s a few examples, and corresponding suggestions to avoid unnecessary work:

  • Writing elaborate ACL manipulation code, or invoking a blob of .NET reflection mess.
  • Writing elaborate code to manipulate local user permisions, like “logon as a service”
    • Use the Carbon PowerShell module – done (thank you Rob!)
  • Writing elaborate code to query or manipulate SQL Server settings
    • Use dbatools or SQLServer PowerShell modules
    • You can configure server memory and recovery model settings this way also (example)
  • Writing elaborate code to check if script is being executed via “run as administrator”
  • Manually writing help documentation
    • Enforce consistent commenting
    • Use PlatyPs to generate markdown files automatically (thank you Kevin!)
  • And finally…

Some final bits of advice:  NEVER test your scripts on a live Configuration Manager environment.  If you don’t have a test environment, build one, and test everything there BEFORE introducing into the production environment.  Also, when you are testing scripts against Configuration Manager and/or SQL Server, always keep the Task Manager window open and watch the Performance tab closely.


Am I some sort of “expert” when it comes to PowerShell or Configuration Manager?  Only when I’m around people who can’t spell “computer” and they’re serving alcohol.   I’ve just spent too many years soaking up what others have shared.  You are free to disregard everything I’ve said.  In fact, in America, it’s expected. But that’s okay too.