Scripting, System Center, Technology, windows

A Cheap Extensible PowerShell Pipeline for ConfigMgr Queryburgers and a Side of Fries

I’ve been knocked out all day on cold medicine and just woke up.  So, to be honest, I have no idea what year it is.  In fact, Configuration Manager and SQL Server might be long gone.  Microsoft may have been acquired by Walmart, and Kanye West is POTUS.  Who knows.  Anyhow…

Many of the ConfigMgr projects I have worked on over the last few years, I find customers trying to build processes off of information pulled from Configuration Manager.  Most often it’s something like:

  • Execute X on all machines which have Y installed
  • Notify <GROUP> for all machines which have condition Z = True

…and so on.  And no, “X”, “Y” and “Z” are not real things, just variables to replace with real things.  Kind of like how politicians are variables that get replaced with money.

In many cases, this is done in a silo.  Meaning – it’s built as a standalone script.  And then another is built separately for a different purpose, and so on.  But, in many cases, there’s an overlap in the area where data is pulled from Configuration Manager on which to base the scope of the operation or process.  Rather than “hard code” this part, I’ve been using a somewhat “open” approach that returns data from a query and passes it on via the PowerShell pipeline.  This makes it fit nicely into a tool model (credit to Don Jones), and thereby: reusable.

Some common scenarios this needs to adapt to:

  • No guarantee that the ConfigMgr admin console is installed where the script is executed, and therefore, no guarantee of a local .psd1 module to load.
  • No guarantee of SCCM admin rights, via the WMI/SMS provider channel, but….
  • Having SQL database read access (as a minimum)
  • At least PowerShell 3.0 (prefer 5.x or later)
  • Doesn’t matter how it’s invoked (Task Scheduler, SQL Job, Azure Automation, Jenkins, some kid on a bicycle, a Bird scooter, etc.)

I prefer they follow Microsoft guidelines with regards to SQL using Windows authentication for two (2) reasons:  First, it’s compliant with Microsoft recommendations, and Second: It complies with Microsoft guidelines with regards to SQL using Windows authentication for Configuration Manager.

The moving parts consist of:

  • A (PowerShell) script
  • One or more SQL query files (**)
  • An AD user account with read access to the CM_XXX database
  • Coffee (Wine will do)

The general process:

  1. Something kicks it off (manual invocation, scheduled job, event trigger, etc.)
  2. Script imports the desired query from file (**)
  3. Script executes query against CM_XXX database
  4. Results (dataset) returned to script
  5. Results output to PowerShell (pipeline)

(** doesn’t matter how you prefer to store the SQL statement content. I chose files because they’re the simplest and most portable form, and they’re easy to build and export from SSMS)

For those who prefer a visual representation…

Yeah, I know, 5 and 6 could be one thing but whatever.  And coffee is applied between steps 1 and 5.  Okay, so what does this look like?

#requires -version 3.0
This is for sample purposes only.  Actual horrific mess is posted on GitHub here.
Name: Get-CMSqlQueryData.ps1
Real, 100% gluten-free documentation headings are provided in the actual script on GitHub

param (
  [parameter(Mandatory=$False, HelpMessage="SQL Server ADO Connection Object")]
  [parameter(Mandatory=$True, HelpMessage="SQL Query Statement")]
    [string] $Query,
  [parameter(Mandatory=$False, HelpMessage="ConfigMgr SQL Server Host Name")]
    [string] $SQLServerName,
  [parameter(Mandatory=$True, HelpMessage="ConfigMgr Site Code")]
    [string] $SiteCode
$DatabaseName = "CM_$SiteCode"
if (!$AdoConnection) {
  Write-Verbose "opening new connection"
  $AdoConnection = .\Get-CMAdoConnection.ps1 -SQLServerName $SQLServerName -DatabaseName $DatabaseName
  if (!$AdoConnection) {
    Write-Warning "failed to open SQL connection!"
$cmd = New-Object System.Data.SqlClient.SqlCommand($Query,$AdoConnection)
$cmd.CommandTimeout = $QueryTimeout
$ds = New-Object System.Data.DataSet
$da = New-Object System.Data.SqlClient.SqlDataAdapter($cmd)
if ($IsOpen) { 
  Write-Verbose "closing connection"
$rows = $($ds.Tables).Rows.Count
Write-Output $($ds.Tables).Rows

The trainwreck above is available on my GitHub trainwreck site here.  The Get-CMAdoConnection.ps1 script referenced above, is also available on my tragic GitHub site here.

A sample query (cm-all-systems.sql):

  v_R_System.Name0 AS ComputerName, 
  v_R_System.AD_Site_Name0 AS ADSite, 
  v_GS_COMPUTER_SYSTEM.Model0 AS Model, 
  v_GS_OPERATING_SYSTEM.BuildNumber0 AS OSBuild, 
    v_R_System.ResourceID = v_GS_OPERATING_SYSTEM.ResourceID 
    v_R_System.ResourceID = v_GS_COMPUTER_SYSTEM.ResourceID 
    vWorkstationStatus ON 
    v_R_System.ResourceID = vWorkstationStatus.ResourceID

The reason for the optional -AdoConnection parameter is that it allows some control and flexibility around how/when connections are opened against the SQL database.  When running a batch of queries, it’s typically best to open one connection, execute the (multiple) queries, and close the connection at the end, rather than opening an explicit connection for each query.  However, if you only need to run a single query, I didn’t want the user (you) to have to think about an explicit connection (and subsequent connection-close) around the process, so it’s implicit.  See how considerate I can be? Like omg.

That said, let’s see how this looks in action.

For this example, I will assume there’s another script which will be invoked with the results of a query against ConfigMgr (e.g. “Do-Something.ps1”).  In this case, I want to isolate all ConfigMgr devices which are found to be in the Active Directory site named “Seattle”, and send those to a script to do something with their names, hence the genius name: Do-Something.ps1.

Example 1 – Single query

$query = Get-Content -Path "x:\stuff\queries\cm-all-systems.sql"
$result = .\Get-CMSqlQueryData.ps1 -SQLServerName "" -SiteCode "P01" -Query $query |
  Where-Object {$_.ADSite -eq 'Seattle'} | Sort-Object ComputerName | 
    Select-Object -ExpandProperty ComputerName
if ($result.Count -gt 0) { .\Do-Something.ps1 -ComputerName $result }

In this example, I don’t use the -AdoConnection parameter, so the Get-CMSqlQueryData.ps1 script explicitly opens a new connection by calling out to Get-CMAdoConnection.ps1, and then closes the connection at the end.  The last line simply checks if any rows were returned and then passes them to the Do-Something.ps1 script.

Example 2 – Batch queries

$SqlHost = ""
$SiteCode = "P01"
$DBname = "CM_$SiteCode"
$ReportPath = "y:\reports"
$queryFiles = Get-ChildItem -path "x:\stuff\queries" -Filter "*.sql"

if ($queryFiles.Count -gt 0) {
  # open a database connection
  $conn = .\Get-AdoConnection -SQLServerName $SqlHost -DatabaseName $DBName
  # iterate the query files and run each query in a loop
  foreach ($qfile in $queryFiles) {
    # import the query statement and define the output .CSV file name
    $query = Get-Content -Path $($qfile.FullName)
    $csvFile = Join-Path -Path $ReportPath -ChildPath "$($qfile.BaseName).csv"
    # run the query and dump it into the .CSV file
    .\Get-CMSqlQueryData.ps1 -AdoConnection $conn -SQLServerName $ServerName -SiteCode $SiteCode -Query $query | 
      Export-Csv -Path $csvFile -NoTypeInformation
  # close the database connection
Write-Host "like, omg! I can't believe I just did all that amazing stuff.  And it must have been amazing because YOU did it!" -ForegroundColor Green

As you can see, the second example gets all of the query files in a given folder path, then opens a SQL connection and iterates the queries and outputs each to its own .CSV file, and then closes the connection.  You can also pass in an explicit list of query filenames, rather than churning through an entire folder.

You could (and probably should) wrap the internals of the foreach() block inside of a try/catch/finally envelop, to insure $conn.Close() gets called if one of the iterations chokes to death on an egg roll or something.  But hopefully this is easy to understand.


So, this let’s me get data from Configuration Manager, from any computer on the network which has PowerShell 3.0 or later, whether or not it has the ConfigMgr admin console installed, and I can post-process the results however I want.  In addition, I don’t have to make any PowerShell code changes in order to add new queries to the library.  I also do not use an explicit username and password, since my SQL Server instance is configured for Windows authentication only.

Thank you for reading!  Please post comments or questions?  Let me know someone is still reading this stuff.  If you read to this point and you’re the first to tweet me the phrase “a correction to a bug in my code example”, you MIGHT win an Amazon gift card.  Just sayin. 🙂

Cloud, System Center, Technology

ConfigMgr – 2 Minute Microwave Style

Genesis – I posted a tweet about someone I know getting stressed at learning Configuration Manager in order to manage 50 Windows devices.  All desktops.  The background is basically that his company had planned on 1000 devices running Windows.  But the end-users, who wield more purchasing power, opted to buy mostly Macbooks.  So the total Windows device count was capped at 50, BUT…. they already approved the purchase of ConfigMgr.  It’s worth noting that the end-users also purchases JAMF (formerly Casper) and set it up in their own secret underground lab, complete with a diabolical German scientist in a white lab coat.  Ok.  That last part isn’t really true, but the JAMF part is true.

So, the “discussion” slid into “okay mr. smarty-pants skatter-turd-brainz, what would you want in a ‘perfect’ ConfigMgr world to address such a scenario?” (again, I’m paraphrasing a bit here)

MC DJam, aka DJammer, aka David the Master ConfigMaster Meister of ConfigMgr, popped some thermal verbals in front of the house and the room went Helen Keller (that means quiet and dark, but please don’t be offended, just stay with me I promise this will make sense soon…)

Yes, I’ve had a few beers.  Full disclosure.  I had to switch to water and allow time for the electric shock paddles to bring my puny brain back online.  That was followed by a brief gasp,”oh shit?! what have I started now?”  Then some breathing exercises and knuckle crackings and now, back to the program…

So, Ryan Ephgrave (aka @EphingPosh) stepped in and dropped some mic bombs of his own.

And just like having kids, the whole thing got out ahead of me way too quick.

So, I agree with Ryan, who also added a few other suggestions like IIS logs, Chocolatey package deployments (dammit – I was hoping to beat him to that one).

So the main thing about this was that this person (no names) is entirely new to ConfigMgr.  Never seen it before, and only gets to spend a small portion of their daily/weekly time with it, due to concurrent job functions.  This is becoming more and more common everywhere I go, and I’ve blogged ad nauseum about it many times (e.g. “role compression”)

What do most small shop admins complain about?

  1. Inventory reporting
  2. Remote management tools
  3. Deploy applications
  4. Deploy updates
  5. Imaging
  6. Customizable / Extendable

These are the top (6) regardless of being ConfigMgr, LANdesk, Kace, Altiris, Solarwinds, or any other product.  All of them seem to handle most of the first 4 pretty well, with varying levels of learning and effort.  But Imaging is entirely more flexible and capable with ConfigMgr (or MDT) than any of the others I’ve seen (Acronis, Ghost, etc. etc. etc.)

ConfigMgr does an outstanding job of all 6 (even though I might bitch about number 6 in private sometimes, it is improving).  ConfigMgr is also old as dirt and battle-tested.  It scales to very large demands, and has a strong community base to back it up in all kinds of ways.  In some respects it reminds me of the years I spent with AutoCAD and Autodesk communities and the ecosystems that developed around that, but that’s another story for another time.

The challenge tends to come from just a few areas:

  1. Cost and Licensing – ConfigMgr is still aimed at medium-to-large scale customers.  The EA folks with Software Assurance, are most often interested and courted into buying it.  Some would disagree, but I set my beer mug down and calmly say “Walk into any major corporate IT office and ask who knows about ConfigMgr.  Then walk into a dentist office, car dealership, or small school system and ask that same question.”  I bet you get a different response.
  2. Complexity – ConfigMgr makes no bones about what it aims to do.  The product sprung from years of “Microsoft never lets me do what I want to manage my devices” (say that with a nasally whiny tone for optimum effect).  Microsoft responded “Here you go bitch.  A million miles of rope to hang yourself.  Enjoy!”  It’s an adjustable wrench filled with adjustable wrenches, because it was designed to be the go-to toolset for almost any environment.  And it’s still evolving today (faster than ever by the way)
  3. Administration – Anyone who’s worked with ConfigMgr knows it’s not really a “part-time” job.  But that’s okay.  It’s part of the “complexity” side-effect.  And rarely are two environments identical enough to make it cookie cutter.  That’s okay too.  Microsoft didn’t try to shoehorn us into “one way”, but said “here’s fifty ways, you choose“.  The more devices you manage with it, the more time and staff it often demands in order to do it justice.  I know plenty of environments that have scaled to the point of having dedicated staff for parts of it like App deployments, Patch Management, Imaging and even Reporting.

None of these are noted with the intention of being negative.  They are realities.  It’s like saying an NHRA dragster is loud and fast.  It’s supposed to be.

Now, add those three areas up and it makes that small office budget person lose control of their bowels and start munching bottles of Xanax.  So they start searching Google for “deploy apps to small office computers” or “patching small office computers cheap as hell” and things like that.

So, ConfigMgr already does the top 6 functions pretty darn well.  So what could be done to spin off a new sitcom version of this hit TV show for the younger generation?

  1. Simpler – It needs to be stupid-simple to install/deploy and manage.  This reaches into the UI as well.  Let’s face it, as much as I love the product, the console needs a makeover.  Simplify age-old cumbersome tasks like making queries and Collections, ADRs and so on.
  2. Lightweight – Less on-prem infrastructure requirements: DPs, MPs, SUPs, RPs, etc.  Move that into cloud roles if possible.
  3. Integrate/Refactor – Move anything which is mature (and I mean really mature) in Intune, out of ConfigMgr.  Get rid of Packages AND Applications, make a hybrid out of both.  Consider splitting some features off as premium add-ons or extensions, like Compliance Rules (or move that to Intune), OSD, Custom Reporting, Endpoint Protection, Metering, etc.
  4. Cheaper – Offer a per-node pricing model that scales down as well as up.  Users should be able to get onboard within the cost range of Office 365 models, or lower.

Basically, this sounds like Intune 3.0, which I’ve also blabbered about like some Kevin Kelly wanna-be futurist guy, but without the real ability to predict anything.

Some of the other responses on Twitter focused on ways to streamline the current “enterprise” realm, with things like automating many of the (currently) manual tasks involved with installation and initial configuration (SQL, AD, service accounts, IIS, WSUS, dependencies, etc. etc.), all of which are extremely valid points.  I’m still trying to focus on this “small shop” challenge though.

It’s really easy to stare at the ConfigMgr console and start extrapolating “what would the most basic features I could live with really come down to?” and end up picking the entire feature set in the end.  But pragmatically, it’s built to go 500 mph and slow down to push a baby stroller.  That’s a lot of range for a small shop to deal with, and they really shouldn’t.  That would be like complaining that the Gravedigger 4×4 monster truck makes for a terrible family vehicle, but it’s not supposed to be that.  And ConfigMgr really isn’t supposed to be the go-to solution for a group of 10-20 machines on a small budget.  Intune COULD be, but it’s still not there yet.  And even it is already wandering off the mud trail of simplicity.  It needs to be designed with a different mindset, but borrowing from the engine parts under the ConfigMgr hood.

Maybe, like how App-V was boiled down and strained into a bowl of Windows 10 component insertions for Office 365 enablement, and dayam that was a weird string of nouns and verbs, they could do something similar with a baked-in “device management client” in a future build of Windows 10.  Why not?  Why have to deploy anything?  They have the target product AND the management tool under the same umbrella (sort of, but I heard someone unnamed recently moved from the MDT world into the Windows 10 dev world, so I’m not that far off).

Does any of this make sense?  Let me know.



Windows 10 Soup Sandwiches

Version 2.1 (I lost Version 1.0 somehow, from the old blog, but it was focused on Windows 7, 8.1 anyway)

An ad hoc collection of wine-infused recipes to help smoosh Windows 10 like a ball of clay, or like a soggy sandwich.

Disable Windows Firewall (MDT, SCCM)

Disable Windows Firewall (GPO)

Disable Windows Defender (GPO)

Deploy .NET Framework 3.5 with Feature on Demand (GPO)

Enable Controlled Folder Access (GPO)

Create Shortcuts on Desktop, Start Menu (GPO)

Disable IPv6 (GPO)

Configure, Start, Stop Windows Services (GPO)

Block and Disable Cortana (GPO)

Set default Web Browser (GPO)

Waste Time Customizing the Start Menu and Taskbar (GPO, Script, MDT, SCCM)

Configure OEM Support info and Company Logo on Support page (GPO)

Block Windows Store and Store Apps (GPO)

Remove Store Apps during Imaging (MDT, SCCM, etc.)

Remove OneDrive from File Explorer (GPO)

Show File Extensions in File Explorer (GPO)

Show Hidden Folders and Files in File Explorer (GPO)

Show File Explorer Menu Bar (GPO)

Expand to Current Folder in File Explorer (GPO)

Customize and Push BGInfo to Desktops (script)

Customize and Push BGInfo to Desktops (GPO)

Destroy and Annihilate SMBv1 by any means necessary

TLS Configuration Guidelines (hotfix, registry, GPO)

Create and Configure a Group Policy Central Store

Updates 2.1

Add Domain User to Local Administrators Group (GPO)

Add Domain Users to Remote Desktop Users on Servers (GPO)

Modify Registry Key Permissions on Domain Computers (GPO)

Create Scheduled Tasks using Group Policy (script, GPO)

Configure PowerShell Settings using Group Policy (GPO)

Prompt for Computer Name / OSD Variable in Task Sequence (script)

Mass Upgrade Windows 10 using PowerShell (script)

Replicate MDT Boot Images to multiple WDS/PXE servers (script)

Set Google Chrome as Default Browser (GPO)

More to be added (version will be updated too)

Cloud, Projects, Scripting, System Center, Technology

CMHealthCheck is now a PowerShell Module

What is it

CMHealthCheck is a PowerShell module filled with bubble wrap, Styrofoam peanuts, and 2 possibly useful functions, aimed at collecting a bunch of data from a System Center Configuration Manager site server, and making a pretty report using Microsoft Word.  But doing so without needing to manually download and store a bunch of script files and so on.

It’s still based on the foundations laid by Rafael Perez, with quite a bit of modification, prognostication, prestidigitation, and some coffee.  Special thanks to Kevin (@thenextdotnet) for helping point me in the right direction to move it all from scripts into a module.

Why is it

I get asked (okay, told) to help customers find out why their site servers are running slow, showing red or yellow stuff, or just to get them ready to upgrade from whatever they’re on to whatever is the latest and greatest version of ConfigMgr.  They also like a pretty Word document with a spiffy cover page.

How to use it

  1. Install the module on the ConfigMgr CAS or Primary server you wish to audit –> Import-Module CMHealthCheck
  2. Run the Get-CMHealthCheck function (see documentation on Github – linked below)
  3. Install the module on a Windows computer which has Office 2013 or 2016 installed (hopefully NOT the same computer which was audited)
  4. Run the Export-CMHealthCheck function (see documentation on Github – linked below)
  5. Save the Word document and mark it up.

Where to Get it

How to Complain About it

Because I know some of you will, but that’s okay.  Without complaints, we have no way of identifying targets.  Just kidding.  I need feedback and suggestions (or winning lottery numbers and free food coupons).  Please use the “issues” link on the GitHub repository to submit your thoughts, gripes and so on.

Personal, Projects, Scripting, System Center, Technology

cm_siteconfig 1.2

I’ve been busy this Labor Day weekend. Besides vacuuming up water from a broken water heater at 4am, mowing a ridiculously big lawn with a ridiculously small lawnmower, and avoiding the oceanfront tourist freakshow (or almost), I spent a fair amount of time on cm_build and cm_siteconfig.  Needless to say, I’m not feeling very funny right now, but I assure you that I will return to my usual tasteless, dry, ill-timed humor after a word from these sponsors.  Even though I don’t have any yet.  Actually, if you blink, you might miss some hidden jestering below.

I’ve already discussed these two PowerShell scripts in a previous blog post, but to update things: cm_build is still at 1.2.02 from 9/2/2017, and cm_siteconfig is now at 1.2.22 from 9/2/2017.  That’s a lot of 2’s.  Anyhow, here’s what each does as of the latest versions:

Note: The version numbers are in parenthesis to indicate lab configuration.  The XML allows *YOU* to configure the installation ANY WAY YOU DESIRE, and to reference ANY VERSION you desire.  The versions below are just what I used to test this thing (so far) about 84 times.

LAB TEST NOTE: Prior to running this script, build the server, assign a name, static IP address, and join to an Active Directory domain.  Then take a snapshot (VMware) or checkpoint (Hyper-V) to roll back if anything spews chunks along the way.

Prep Work

cm_build.ps1 / cm_build.xml

  • Install Windows Server roles and features (except for WSUS)
  • Install Windows 10 ADK (1703)
  • Install Microsoft Deployment Toolkit (MDT) (8443)
  • Install SQL Server (2016)
  • Install SQL Server Management Studio (2017)
  • Configure SQL Server maximum memory allocation
  • Configure SQL Server ReportServer DB recovery model
  • Install WSUS server role
  • Run the WSUS post-install configuration
  • Install System Center Configuration Manager 1702
  • Install ConfigMgr Toolkit 2012 R2
  • Install Recast Right-Click Tools

GENERAL NOTES:  The cm_build.xml structure starts with the “packages” section, which dictates what gets executed and in what order.  The “name” element establishes the package code link used by all of the other sections, such as payloads, detections, files, and features. Note that the files section only requires the pkg key value for SQLSERVER and CONFIGMGR.  Other files can be created without using a matching pkg key if desired.

LAB TEST NOTE: I strongly recommend taking another snapshot (VMware) or checkpoint (Hyper-V) at this point, prior to running cm_siteconfig.ps1.  This will help avoid angst and loss of temper while making iterative changes to cm_siteconfig.xml and retesting.

cm_siteconfig.ps1 / cm_siteconfig.xml

  • Create SCCM accounts
  • Configure the AD Forest connection
  • Configure Server Settings
    • Software Deployment Network Access Account
  • Configure Discovery Methods
    • The template AD User Discovery Method adds AD attributes: department, division, title.
    • The template AD User and System Discovery Methods add filtering for password set and login periods of 90 days each
  • Configure Boundary Groups
    • The template creates 4 sample boundary groups
    • You can enable creating Site Boundaries as well, but the default is to allow the AD Discovery to create subnet/IP range boundaries
  • Configure Site Roles
    • Management Point
    • Service Connection Point
    • Distribution Point (with PXE)
    • Cloud Management Gateway (still in development)
    • Software Update Point
    • Reporting Services Point
    • Application Catalog Web Service Point
    • Application Catalog Website Point
    • Asset Intelligence Synchronization Point
    • (more to come)
  • Client Settings
    • Still in development, but…
    • The template creates two (2) sample device policies: Servers and Workstations
  • Client Push Installation Settings
    • Still in development
  • Create DP groups
    • The template creates 4 sample DP groups
  • Create console Folders
    • The template creates sample folders beneath: Applications, Device Collections, User Collections, Boot Images, Task Sequences, and Driver Packages
  • Create Custom Queries
    • The template creates two (2) sample device queries
  • Create Custom Device Collections
    • The template creates three (3) sample user query-rule collections, and 15 sample device query-rule collections
  • Create Custom User Collections
  • Import OS Images
    • The template imports two (2) OS images: Windows 10 1703 and Windows Server 2016
    • Source media is not included.  Batteries not included.  Just add hot water and stir.
  • Import OS Upgrade Installers
    • The template imports two (2) OS upgrade packages
  • Configure Site Maintenance Tasks
    • Excludes Site Backup, and Database Reindex tasks for now.  I plan to have these enabled soon.
  • Create Application Categories
    • The template includes (5) sample categories: IT, Developer, Engineering, Finance, General and Sales
    • For now, the detection rules are implemented using a chunk of freshly-cut, carefully seasoned, and slow-roasted PowerShell code, because it’s easier to shoe-horn into this process and provide flexibility and adaptability.  And besides, all those syllables sound kind of impressive after a few mixed drinks.
  • Create Applications
    • The template includes examples for 7-Zip, Notepad++, VLC Player, and Microsoft RDC Manager

What’s Next?

  • I’m still working on this, so more changes/improvements will be coming.

Q & A

  • Is it really “open source”?
    • Yes! Go ahead and pinch yourself.
  • Did you write all this code yourself?
    • Yes, sort of.  Some of the pieces were adapted from, or inspired by, the outstanding work done by other amazing people like Niall Brady, Nickolaj Andersen, Johan Arwidmark, Mikael Nystrom, Maurice Daly, Stephen Owen, Anders Rodland, Raphael Perez, Chrissie LeMaire, Jason Sandys, Sherry Kissinger, and many others I can’t think of right now.  Thanks to Kevin B. and Chris D. for helping me find better ways to solve key areas of the overall project.  The XML constructs and process model are my own hallucinatory work.
  • Can I Make Suggestions / Request Changes?
    • Please use the “Issues” feature in Github to submit bugs, feature changes and enhancements, etc.  I will make every effort to review, assess, feebly attempt, fail to satisfy, cry over insecurities of self-doubt, angrily assign blame, throw objects across room while swearing like a drunk sailor, solemnly accept defeat, and ultimately: try to make it work as requested.
    • Note that creating a Github account is required for submitting Issues.  Github accounts are free and they make you feel warm and fuzzy inside.
  • Does cm_build also download required installation media?
    • No.  I’m too lazy.
    • 99.999999% of my customer engagements involve a ‘kick-off’ call in which we discuss prerequisite action-items prior to beginning work. This typically includes requesting the customer to have all installation media and licensing information ready to go.  Which they typically do, so I didn’t feel the need to bother with that aspect (not to mention, try to keep up with version changes and new URL’s over time)
  • Can cm_build be used to install a Central Administration Site?
    • Yes.
  • Can cm_build be used to install a Secondary Site?
    • Yes.
  • Can cm_build be used to destroy alien civilizations?
    • Probably not.
  • How was this thing Tested?
    • In a small dungeon beneath a floating castle in a lake atop a tall mountain.  Okay, in my home lab, next to the dog’s sofa.
    • It’s been tested about 84 times as of 9/4/2017.  That’s about 55 times for cm_build and 29 times for cm_siteconfig.  But by the time you’ve read this, it’ll have increased again.
  • What was/is your Test Environment like?
    • Windows Server 2016 (Dell R710) server with Hyper-V
    • 3 virtual machines: DC1 (domain controller), FS1 (file server) and CM01 (configuration manager server)
    • CM01:
      • 16 GB memory, 4 disks (C: for OS, E: for apps, F: for content, G: for logs, etc.), 2 vCPUs
      • Windows Server 2016 Standard
    • Me:
      • Coffee cups falling off the desk, on ever flat surface, in the trash can, on top of one of my dogs, and a few more in the kitchen sink
      • Empty snack bar wrappers strewn across the room
      • A tattered doggie toy-squirrel hanging on a door knob for some strange reason.
  • What’s the point?
    • It’s been challenging, and fun, to work on.  It saves me time and headache at work and in my home lab.
    • It opens up potential secondary capabilities, like automating installation documentation and building an extract/build process to close the circle of life, open a wormhole, fill it with black holes and jump in for a ride.  I really need to stop listening to so many podcasts.
  • Why should I care?
    • You shouldn’t.  You can go do something fun now instead.
  • Why XML?
    • Because I &^%$ing hate JSON, and INI is too limited.  I thought about YAML, which looks a little bit like JSON, but not like it was punched in the face with a meat tenderizer mallet, but then I had to mow the lawn, and completely forgot why.
  • What have been (or continued to be) the biggest Challenges?
    • Time
    • Sleep
    • Deciding where to draw logical boundaries between automating and leaving out for manual work later
    • Refactoring, refactoring, re-refactoring, and re-re-refactoring before refactoring some more
    • More refactoring
    • Incomplete Microsoft ConfigMgr PowerShell cmdlet reference documentation*
    • Incomplete/inconsistent Microsoft ConfigMgr PowerShell cmdlet features*
    • Incomplete/inconsistent mental capacity (mine)
    • Occasional power and Internet service outages and lack of a power backup system (budget, weather, drunk drivers)
  • Does humor belong in IT?
    • Yeah.  It has to. Over 35 years in this field of work, I’ve seen what happens to people who forget that. It doesn’t end well.

*  I’m not going to beat them up on this, since they are already making Herculean efforts towards modernizing and cleaning up ConfigMgr, so the gravy should have a few lumps.

Projects, Scripting, System Center, Technology

cm_siteconfig updates and my humor tank is running empty

I finally got some sleep. And immediately thereafter, I discovered a bug in the script. It’s in the detection method part of the Add-CMDeploymentType mess. The nested PowerShell code inside the @”…”@ stuff was expanded and caused it to wipe out the $reg and $val variables, so the result was like our Federal government today: useless.

Anyhow, upon discovering that, I went to work fixing it, and decided to go ahead and add detection methods for “file:” and “folder:” to add to the existing “registry:” option. This required an additional sample application in the XML file, which I chose VLC player, because, well, why not? VLC is like a lobbyist in DC, it’s everywhere. And yes, you can tell I’m a little perturbed at our ongoing temperamental governmental dysfunctionality reality.

Other changes: added a new -Detailed switch, to display “verbose” output, without using -Verbose, and makes the verbose output much MUCH prettier to read than using -Verbose, which is pretty ugly.

So, after testing is completed, I will upload to the branch “1.2.02” in the Github repo.  Hopefully in the next few hours.  First, I have to take my dog Dory (aka “butt brain” aka “turd beast” aka “no! you can’t eat the cat!”) for a walk.

Projects, Scripting, System Center, Technology

What is this, cm_build and cm_siteconfig stuff?

UPDATE 8/29/17 – Corrected a mistaken attribution for Driver Automation Tool to Maurice Daly.

I’ve been kind of quiet lately.  Quiet, as compared to how normally chatty I tend to be online, that is.  It’s been a mix of personal life, work life and hobby life.  Personal aside, work life has been a little quiet this week, which is fantastic for catching up on things, and spending a little time with my hobby life: wordworking and coding.  I don’t have a Yankee Home Workshop space or anything, but I get by okay.  If I ever win a massive PowerBall lottery payout, my neighbors will have to relocate, as I will need their spaces for expanded hobby capabilities.

Anyhow, on to the meat and potatoes:  I’ve been toying with this for quite a few years, but could never align the right perception, time allocation and initiative, to make it gel.  This past week and weekend they just happened to align at the right place and the right time.


I wanted to devise a different approach to specifying the configuration rules in advance and then executing them with limited (or zero) human interaction.  The rules should be the design document.  Or at least the basis of such.  It shouldn’t be difficult to derive the XML data into a readable document, such as Microsoft Word or HTML.  And the code should be reusable and resilient.  Run it as many times as desired (or needed) on a given server and it should ignore what is already done, and only work on what hasn’t been done yet.

The Bundle

cm_build and cm_siteconfig are two (2) pieces of a bundle of scripts aimed at simplifying and streamlining the building and configuration (respectively) of a System Center Configuration Manager site server.  Actually, either a Central Administration or a Standalone Primary, site server.  It’s flexible enough, in theory, to contend with other roles and purposes.


cm_build.ps1 is a PowerShell script that reads from cm_build.xml, which contains the logic (configuration data) to take a “vanilla” Windows Server host (virtual or physical) up to having ADK, MDT, WSUS, SQL Server, SQL Server Management Studio, Configuration Manager, ConfigMgr Toolkit and Right-Click Tools (optionally) all ready to go.  The baseline server only needs to be prepared for general purpose server capability (assigned name, static IP address, domain-joined, etc.) and have the proper resources allocated (memory, processors, disks, etc.).  The only other requirement is having the installation media accessible.

The default configuration of the cm_build.xml file refers to a set of UNC shares on a common network, but you could reference a local disk, removable media, or any other source which can be read from using PowerShell.

cm_build is farther along in development and testing than cm_siteconfig.


cm_siteconfig.ps1 works very much like cm_build, in that it reads from cm_siteconfig.xml in order to configure a “vanilla” Configuration Manager Primary or Central Admin site server to whatever you prefer.  This will include:

  • AD Forest
  • Discovery Methods
  • Boundary Groups
  • Client Settings
  • Client Push Installation
  • Queries
  • Collections
  • Applications and Deployment Methods
  • Site Roles: Asset Intelligence, Software Updates, etc.
  • Distribution Point Groups
  • Operating System Images
  • Operating System Installers (upgrades)
  • Console Folders
  • Maintenance Tasks

Of these, the items in blue are ready to test.  The others are in development and moving as quickly as my coffee intake can allow.

What about Other Features?

Software Updates, Endpoint Protection, Windows 10 Servicing, Task Sequences, and so on, are all up for consideration.  However, each of these has some unique aspects that may change whether I try to incorporate them sooner, later or never.  For example, Task Sequences can be exported and imported, and with each new ConfigMgr build, the PowerShell interfaces get more robust, which delves into version impacts and compatibility aspects.  I need to start small and work upward, and start with the more mature stack of tools, which helps insure the broadest platform support.

I’m getting ahead of myself here.  Much of this is obviously predicated on time, initiative, and my own, limited abilities.  Some might call this “pie in the sky” thinking, and it may very well be just that.  Whatever, it’s a nice hobby for me that doesn’t cost a lot of money and I can do it indoors.

What about Drivers?

I’m leaving drivers out of this for now, because Maurice Daly basically blew the doors off of that with this, and I don’t even want to think about reinventing that wheel.  Kudos for that one.  One of many amazing tools he has produced.

Is it done?

No.  But cm_build is fairly stable and tested as of now.  cm_siteconfig is still in development, but there’s enough to kick the tires and see if it leaks transmission fluid on your rug.  It’s free, and it’s open, so that makes it sort of freeopen.  But that could likely be an offensive word in another language.

Where is it?


What’s Next?

Who knows.  That’s what makes it fun to mess with.  Kind of like a blind, drunk guy poking at a rattle snake with a pencil.