databases, Scripting, System Center, Technology

What Not to Do With ConfigMgr, 1.0.1

[note: this post has been sitting in my drafts folder for over a year, but recent events reminded me to dust it off and post it]

One of my colleagues, the infamous @chadstech, sent a link to our team, to the slide deck from the Channel9 session (MS04) “30 Things you should never do with System Center Configuration Manager” by @orinthomas and @maccaoz. If you haven’t seen (or read) it already, I strongly recommend doing so first.

It’s from 2016, so even though it’s a few years old now, it still holds up very well in mid 2019. However, everyone who’s ever worked with that product knows that the list could become a Netflix series.

This blog post is not going to repeat the above; instead, append the list with some things I still see in a variety of environments today. Things which really should be nipped in the bud, so to speak. Baby steps.

Using a Site Server like a Desktop

Don’t do it. Install the console on your crappy little desktop or laptop and use that. Leave your poor server alone. Avoid logging into servers (in general) unless you REALLY need to perform local tasks, and that’s it. Anything you CAN do remotely, should be done remotely.

If installing/maintaining the ConfigMgr console is your concern: forget that. The days of having to build and deploy console packages are gone. Install it once, and let it update itself when new versions are available. Kind of like Notepad++. Nice and easy.

Why? Because…

  • Using a server as a daily desktop workspace not only drags on resources and performance.
  • It creates a greater security and stability risk to the environment.
  • The more casual you are with your servers, the sloppier you’ll get and eventually you’ll do something you’ll regret

Whatever your excuse has been thus far, stop it.

Anti-Virus Over-Protection

Even in 2019, with so many tools floating about like Symantec, McAfee, Sophos, CrowdStrike, and so on, when I ask if the “exclusions” are configured to support Configuration Manager, I often get a confused look or an embarrassing chuckle. Gah!!! Chalkboard scratch!

There are several lists of things to exclude from “real-time” or “on-demand” scanning, like this one, and this one. Pick one. Failing to do this VERY often leads to breaks in processes like application deployments, software updates deployments, and policy updates.

Also important: with each new release of Configuration Manager, read the release notes and look for new folders, log files, services or processes that may be introduced. Be sure to adjust your exclusions to suit.

Ignoring Group Policy Conflicts

Whatever you’re doing with regards to GPO settings, make damned sure you’re not also doing the same things with Configuration Manager. The two “can” be combined (in rare cases) to address a configuration control requirement, and you can sew two heads on a cow, but that doesn’t mean it’s the best approach.

Pick one, or the other, only. If you have WSUS settings deployed by GPO, and are getting ready to roll out Software Updates Management via Configuration Manager, stop and carefully review what the GPO’s are doing and make adjustments to remove any possible conflicts.

And, for the sake of caffeine: DOCUMENT your settings wherever they live. GPO’s, CI’s or CB’s in ConfigMgr, scheduled tasks, whatever. DOCUMENT THEM! Use the “Comments” or “Description” fields to your advantage. They can be mined and analyzed easily (take a look at PowerShell module GPODOC for example / shameless plug).

One-Site-Fits-All Deployments

I’ve seen places that only use packages, or only use Task Sequences, or only use script wrapping, or only repackage with AdminStudio (or some alternative). That’s like doing every repair job in your house or apartment with a crowbar.

There’s nothing wrong with ANY means of deploying software as long as it’s the most efficient and reliable option for the situation. Just don’t knee-jerk into using one hammer for every nail, screw, and bolt you come across.

Pick the right tool or method for each situation/application. Doing everything “only” one way is ridiculously inefficient and time-wasting.

Sharing SQL Instances

The SQL licensing that comes with a System Center license does not permit hosting third-party products. Not even your own in-house projects, technically speaking. You “can” do it, but you’re not supposed to.

What that means is, when you run into a problem with the SQL Server side of things, and you call Microsoft, and they look at it and see you have added a bunch of unsupported things to it, you’ll likely get the polite scripted response, “Thank you for being a customer. You appear to be running in an unsupported configuration. Unfortunately, we can’t provide assistance unless you are running in a supported configuration. Please address this first and re-open your case, if needed, for us to help? Thank you. Have a nice day. Bye bye now.

And, now, you’re facing an extended duration of what could have been a simple problem (or no problem at all, since your third-party app might be the problem).

Configuration Manager is extremely demanding of it’s SQL resources. Careful tuning and maintenance is VERY VERY VERY often the difference between a smooth-running site, and an absolute piece of shit site. I can’t stress that enough.

Leeching SQL Resources

Some 3rd party products, who I’m advised not to name for various legal reasons, provide “connection” services into the Configuration Manager database (or SMS provider). Attaching things to any system incurs a performance cost.

Before you consider installing a “trial” copy of one of those in your production environment, do it in a test environment first. Benchmark your environment before installing it, then again after. Pay particularly close attention to what controls that product provides over connection tuning (polling frequency, types of batch operations, etc.).

And, for God’s sake (if you’re an atheist, just replace that with whatever cheeseburger or vegan deity you prefer), if you did install some connected product, do some diagnostic checking to see what it’s really doing under the hood.

And just as important: if you let go of the trial (or didn’t renew a purchased license) – UNINSTALL that product and make sure it’s sticky little tentacles are also removed.

Ignoring Backups

Make sure backups are configured and working properly. If you haven’t done a site restore/recovery before, or it’s been a while, try it out in an isolated test environment. Make sure you understand how it works, and how it behaves (duration, results, options, etc. )

Ignoring the Logs

Every single time I get a question from a customer or colleague about some “problem” or “issue” with anything ConfigMgr (or Windows/Office) related, I usually ask “what do the logs show?” I’d say, on average, that around 80% of the time, I get silence or “hold on, I’ll check”.

If you ask me for help with any Microsoft product or technology, the first thing I will do is ask questions. The second thing I will do is look at the appropriate logs (or the Windows Event Logs).

So, when the log says “unable to connect to <insert URL here>” and I read that, and try to connect to same URL and can’t, I will say “Looks like the site isn’t responding. Here’s my invoice for $40,000 and an Amazon gift card”. And then you say “but I could’ve done that for free?!” I will just smile, and hold out my greedy little hand.

Keep in mind that the server and client logs may change with new releases. New features often add new log files to look at.

Check the logs first.

Ignoring AD: Cleanups

Managers: “How accurate is Configuration Manager?”

Answer: “How clean is your environment?”

Managers: (confused look)

If you don’t have a process in place to insure your environment is maintained to remove invalid objects and data, any system that depends on that will also be inaccurate. It’s just a basic law of nature.

Step 1 – Clean up Active Directory. Remove accounts that no longer exist. Move unconfirmed accounts to a designated OU until verified or removed. This process is EASY to automate, by the way.

Step 2 – Adjust ConfigMgr discovery method settings to suit your environment. Don’t poll for changes every hour if things really only change monthly. And don’t poll once a month if things really changes weekly. You get the idea. Just don’t be stupid. Drink more coffee and think it through.

Step 3 – I don’t have a step 3, but the fact that you actually read to this point brings a tear to my eyes. Thank you!

Ignoring AD: Structural Changes

But wait – there’s more! Don’t forget to pay attention to these sneaky little turds:

  • Additions and changes to subnets, but forgetting to update Sites and Services
  • Changes to domain controllers, but not updating DNS, Sites and Services or DHCP
  • Changes to OUs, but forgetting to update GPO links
  • All the above + forgetting to adjust ConfigMgr discovery methods to suit.

Ignoring DNS and DHCP

It’s never DNS!“, is really not that funny, because it’s very often DNS. Or the refusal to admit there might be a problem with DNS. For whatever reason, many admins treat DNS like it’s their child. If you suggest there might be something wrong with it, it’s like a teacher suggesting their child might be a brat, or stupid, or worse: a politician. The other source of weirdness is DHCP and its interaction with DNS.

Take some time to review your environment and see if you should make adjustments to DHCP lease durations, DNS scavenging, and so on. Sometimes a little tweak here and there (with CAREFUL planning) can clean things up and remove a lot of client issues as well.

Check DHCP lease settings and DNS scavenging to make sure they are closely aligned to how often clients move around the environment (physically). This is especially relevant with multi-building campus environments with wi-fi and roaming devices.

Task Sequence Repetition

A few releases back, Microsoft added child Task Sequence features to ConfigMgr. If you’re unaware of this, read on.

Basically, you can insert steps which call other Task Sequences. In Orchestrator or Azure Automation parlance this is very much like Runbooks calling other Runbooks. Why is this important? Because it allows you to refactor your task sequences to make things simpler and easier to manage.

How so?

Let’s say you have a dozen Task Sequences, and many (or all) of them contain identical steps, like bundles of applications, configuration tasks, or driver installations. And each time something needs updating, like a new application version, or a new device driver, you have to edit each Task Sequence where you “recall” it being used. Eventually, you’ll miss one.

That’s how 737 Max planes fall out of the sky.

At the very least, it’s time wasted which could be better spent on other things, like drinking, gambling and shooting guns at things.

Create a new Task Sequence for each redundant step (or group of steps) used in other Task Sequences. Then replace those chunks of goo with a link to the new “child” Task Sequence. Now you can easily update things in one place and be done with it. Easy. Efficient.

Ignoring Staffing

Last, but certainly not least is staffing. Typically, this refers to not having enough of it. In a few cases, it’s too many. If your organization expects you to cover Configuration Manager, and it’s SQL Server aspects, along with clients, deployments, imaging, updates, and configuration policies, AND maintain other systems or processes, it’s time for some discussion, or a new job.

If you are an IT manager, and allow your organization to end up with one person being critical to a critical business operation, that’s foolish. You are one drunk driver away from a massive problem.

An over-burdened employee won’t have time to create or maintain accurate documentation, so forget the crazy idea of finding a quick replacement and zero downtime.

In team situations, it’s important to encourage everyone to do their own learning, rather than depend on the lead “guru” all the time. This is another single point of failure situation you can avoid.

If there’s anyone who knows every single feature, process and quirk within Configuration Manager, I haven’t met them yet. I’ve been on calls with PFE’s and senior support folks and heard them say “Oh, I didn’t know that” at times. It doesn’t make sense to expect all of your knowledge to flow out of one person. Twitter, blogs, user groups, books, video tutorials, and more can help you gain a huge amount of awareness of features and best practices.

That’s all for now. Happy configuring! 🙂

System Center, Technology

7 SCCM Task Sequence Tips

I purposely left out “OSD” in the title, because I see a significant increase in non-OSD tasks being performed with Task Sequences. This includes application deployments, complex configuration sequences, and so on. Whether those could be done more efficiently/effectively using other tools is a topic for another beer-infused, knife-slinging, baseball bat-swinging discussion. Just let me know early-on, so I can sneak out the back door.

Anyhow, this is just a short list of “tips” I find to be useful when it comes to planning, designing, building, testing, deploying and maintaining Task Sequences in a production environment. Why 7? Because it’s supposed to be lucky.


Are you sitting down? Good. This might be a big shock to you, but I am *not* the world’s foremost expert on Task Sequences, or Configuration Manager. And some (maybe all) of these “tips” may be eye-rolling old news to you. But hopefully, some of this will be helpful to you.

Start Simple!

So often, I see someone jump in and start piling everything into a new Task Sequence at once, and THEN trying it out. This can make the troubleshooting process much more painful and time-consuming than it needs to be. Start with what developers call a “scaffold”, and gradually build on that.

I usually start with the primary task at hand: such as “install Windows 10 bare metal“, test that with only the absolute bare minimum steps required to get a successful deployment. Then add the next-most-important steps in layers and continue on.

However you decide to start, just be sure to test each change before adding the next. It might feel tedious and time-wasting, but it can save you 10 times the hassle later on.

Divide and Conquer

Don’t forget that the latest few builds of ConfigMgr (and MDT btw) support “child”, or nested, Task Sequences. In situations where you have multiple Task Sequences which share common steps, or groups of steps, consider pulling those out to a dedicated Task Sequence and link it where needed. Much MUCH easier to maintain when changes are needed.

Some common examples where this has been effective (there are many more I assure you) include Application Installations, Drivers, Conditional blocks of steps (group has a condition, which controls sub-level steps within it, etc.), and setup steps (detection steps with task sequence variable assignments at the very top of the sequence, etc.)

I’m also surprised how many people are not aware that you can open two Task Sequence editors at the same time, side-by-side, and copy/paste between them. No need to re-create things, when you can simply copy them.

Organize and Label

If you are going to have multiple phases for build/test/deploy for your Task Sequences, it may help to do one (or both) of the following:

  • Use console folders to organize them by phase (e.g. Dev, Test, Prod, and so on)
  • Use a consistent naming convention which clearly identifies the state of the Task Sequence (e.g. “… – Prod – 1.2”)

This is especially helpful with team environments where communications aren’t always optimal (multiple locations, language barriers, time zones, etc.)

Establish a policy and communicate it to everyone, then let the process manage itself. For example: “All you drunken idiots, listen up! From now on, only use Task Sequences with ‘Prod’ in the name, unless you know it’s for internal testing only! Any exceptions to this require you eating a can of bug spray.”


Wherever you can use a comment, description, or note, field in anything, you should. This applies to more than ConfigMgr as well. Group Policy Objects and GP settings are rife with not having any explanation about why the setting exists or who created it. Don’t let this mine field creep into your ConfigMgr environment too.

Shameless plug: For help with identifying GPOs and settings (including preferences) which do or don’t have comments, take a look at the GpoDoc PowerShell module, available in the PowerShell Gallery, and wherever crackheads can be found.

The examples below show some common places that seem to be left blank in many (most) organizations I run across.

Other places where documentation (comments) can be helpful are the “Scripts” items, especially the Approval comment box.

Side note: You can query the SQL database view vSMS_Scripts, and check the “Comment” column values to determine what approval comments have been added to each item (or not). Then use the “Approver” column values to identify who to terminate.

Access Control

This is aimed at larger ConfigMgr teams. I’ve seen environments with a dozen “admins” working in the console, all with Full Administrator rights. If you can’t reign that wild-west show in a bit, at least sit down and agree who will maintain Task Sequences. Everyone else should stay out of them!

This is especially important if the team is not co-located. One customer I know was going through a merger (M&A) and, apparently, one group in another country, didn’t like some of the steps in their Windows 10 task sequence, so they deleted the steps. No notifications were sent. It was discovered when the first group started hearing about things missing from newly-imaged devices.

In that case, the things needed were (A) better communications between the two groups, and (B) proper security controls. After a few meetings it was agreed that the steps in question would get some condition tests to control where and when they were enabled.

Make Backups!!!!

Holy cow, do I see a lot of environments where the Backup site maintenance task isn’t enabled. That’s like walking into a biker bar wearing a “Bikers are all sissies!” t-shirt. You’re just asking for trouble.

Besides a (highly recommended) site backup, however, it often pays dividends to make what I call “tactical backups”. This includes such SUPER-BASIC things as:

  • Make a copy of your production task sequences (in the console) – This is often crucial for reverting a bunch of changes that somehow jacks-up your task sequence and you could spend hours/days figuring out which change caused it. Having a copy makes it really easy (and fast) to recover and avoid lengthy impact to production
  • Export your product task sequences – Whether this is part of a change management process (vaulting, etc.) or just as a CYA step, it can also make it easy to recover a broken Task Sequence quickly.

Either of these are usually much less painful than pulling from a site backup.

As a double-added precaution, I highly/strongly recommend that anytime you intend to make a change to a production task sequence, that you make a copy of it first. Then if your edits don’t work, instead of spending hours troubleshooting why a revert attempt isn’t actually reverting, you can *really* revert back to a working version.

Don’t Overdo It

One finally piece of advice is this: Just because you get comfortable using a particular hammer, don’t let this fool you into thinking everything is a nail. Task Sequences are great, and often incredibly useful, but they’re not always the optimal solution to ever challenge. Sometimes it’s best to stick with a very basic approach, like a Package, Application, or even a Script.

I’ve worked with customers who prefer to do *everything* via a Task Sequence. Even when it was obvious that it wasn’t necessary. The reason given was that it was what they were most familiar with at the time. They have since relaxed that default a bit, and saved themselves quite a bit of time. That said, Task Sequences are nice and should always be on your short list of options to solve a deployment need.


I hope this was helpful. If not, you can also print this out, and use it as a toilet bombing target. Just be sure to load up on a good Mexican lunch before you do. Cheers!

business, databases, Devices, Scripting, System Center, Technology

Asset Inventory, It’s not just for breakfast anymore

For those of you that read my blog this will probably sound familiar.  But for those not yet dunked in the stupid tank of my pontification gyrations, I hope you find this post useful in some way.  Maybe print it out and use it for a toilet bombing target.

Last night I was grilling some sort of roadkill and having a beer and my thumbs went out of control on Twitter.  It was a spur of the moment reflection on how this topic seems to repeat over and over.  For some reason, I assume “asset inventory” is important enough for most organizations to make it a priority.  But, more often than not, it seems not to be the case.

Why Asset Inventory Sucks

I explained why it sucks back in 2014 on my old blog, here.  It still sucks, because humans suck at keeping track of things.  However, recently I received a few requests to digress into this a bit more on the recommendation side, which is what this post is aimed at doing.  The biggest and most important piece is process. In fact, more than one process, but at least start there.

I must emphasize here the following:

There is no such thing as “perfect asset inventory”.  Whether you’re Wal-Mart or the US Department of Defense, shit gets lost.  And somewhere, somehow, that piece of shit has a record sitting in some shitty place that still says that shit is real shit and it exists somewhere.  But, if you try to put your hands on that shit, you find you’re shit out of luck.  But the goal should always be to get as close to “perfect” as you can, without inflicting harm on your business, your employees, or your customers.

Side Note: If you get bored, Google “US military missing inventory” and pull up a chair.  You’ll be reading for awhile.

Nuts and Bolts

When you look at how a device can be tracked throughout its lifetime, it’s actually not that different from how humans are tracked.

For either column, each row relates to a distinct system which maintains relevant information for that category.  And for either humans or devices, it’s not uncommon that each of those systems belongs to a different department, and they end up building silos of information.  It’s also not uncommon that each silo maintains redundant, and often inconsistent, information about the same asset/person.  Many of these systems have been developed independently for years before anyone thought to link them for various business needs.

For humans, there’s the hospital, the IRS, SSA, DMV, DHS, DOD, state and municipal government, as well as insurance companies, banks, web sites, schools, clubs, retailers, and so on.  Few of these entities routinely share the same information about the same people, and even then, still maintain their own data.  In this respect, devices aren’t that different from humans.

For devices, there’s a Purchase Order, Active Directory and Azure AD, EMS, Configuration Manager, SQL Server (behind multiple systems), HelpDesk systems, Logging systems, and disposal records.  In between, there are tons of home-grown apps/systems as well.

Finding the Wounds

The first thing to do is identify each tool (system, service, etc.) you already have, and identify what it tracks.  Document or diagram what each system tracks (types of information, attributes, etc.) and what pieces of information they have in common.  Common examples include Asset Tags, BIOS serial numbers, as well as manufacturer, model, etc.  For software-based systems, it may also be a GUID, SID or an LDAP cn, etc.

If you’re not primarily a DBA, kidnap one (they can be bribed with food, caffeine and Amazon gift cards).  Design a solution to extract ONLY the information you need to confirm the existence of an asset in each system.  In this design, determine what you need to compare across each system to insure consistency and find missing pieces (gaps).

Note: Be careful with data extraction (or queries) that you don’t over-burden the systems themselves.  This is particularly true for things like Configuration Manager, which are sensitive to SQL performance.

Get some reports to show assets which are not found in all systems, then use that to determine how the information is missing.  This often points to a process that needs to be updated.

For example, you determine that Jimmy, in the Purchasing Department, doesn’t capture some key pieces of information when a shipment arrives.  So you decorate Jimmy’s car with shaving cream and cat litter during lunch time, with a note warning him to pick up the slack.  And Debbie, ignores the weekly email report of machines which haven’t logged into AD in more than 180 days.  So, you sign Debbie up for every porn site mailing list using her personal email address, and cover her desk with cat litter, and Post-It notes with reminders to fill that information in soon.

WARNING: These are simply ridiculous suggestions made by random imaginary homeless people.  The author of this blog does not condone shaving cream, porn sites or Post-It notes.  In fact, the author doesn’t condone this blog.  Any similarity to real persons is unintentional. Batteries not included.  Void where prohibited.


Some of these may look familiar, as they are EXTREMELY common in most organizations.

  • Computer accounts left in Active Directory, long after a device has been disposed
  • Computer objects missing in ConfigMgr due to restrictive Discovery settings, limited user account, etc.
  • Asset management systems that rely on human data entry to identify assets
  • Lack of documented procedures for new hires to follow, especially in IT
  • Allowing people to “borrow” devices back from the disposal pile after they’ve been retired
  • Failing to update records when assigning an existing device to a different user
  • Relying on device names or descriptions in AD to identify user assignments

Control the Bleeding

  • Use scripting to manage orphaned AD computer accounts.
    • Search by LDAP attributes like PwdLastSet, Last-Logon, etc. (read the “remarks” section of Last-Logon for a general heads-up on using this)  You can modify the GC replication flag for these attributes (be very careful) or make your script query all domain controllers and compare results.
    • Machines which haven’t touched the network in a long time (usually more than 30 days, but it depends on the nature of your business) can be disabled and moved to a special OU using PowerShell (or whatever)
    • If nobody whines after X days, delete the accounts.  If they show-up the next day angry, just rejoin them to the domain and apply liberal amounts of pepper spray to the user. (just kidding, don’t do that)
    • For any automation you concoct, be sure it includes logging and reporting/notification throughout.  And be sure to include some “what-if” support to test without accidentally deleting the CEO’s laptop.  Think PowerShell [CmdletBinding(SupportsShouldProcess=$True)] , and $WhatIfPreference for things that don’t natively support -WhatIf, etc.
  • If you find inconsistencies between your inventory-related systems, determine why.  Then look for ways to replace human input with some sort of automation (PowerShell, PowerShell, PowerShell, a few table spoons of SQL and more PowerShell)
  • Establish (or update) your policies and procedures.  Seek advice from other organizations, books, and blogs.  Ask questions on forums like Slack, Reddit, StackOverflow, etc. as well.  Take your time, but get it right.
  • Be careful to not reinvent any wheels.  Don’t replicate more information than you really need, as it adds risk of creating yet another pool of information that could become isolated later on.

Notice that I lean towards PowerShell and building things.  You may prefer to use a third-party (free or retail) product or service, which is fine.  I come from the era before vendors bought up all the land for corporate software farming.  We had to grow our own goodies from scratch.  That’s not a binary choice however.  You can mix the two, such as using things like Sysinternals, SQL Express, and so on, along with scripting.  You have options.  Options are good.

Connecting the Dots

One final thought, and this crosses a lot of different aspects of IT operations.  This has to do with management support.  So often, the IT folks bemoan not having enough resources, training, or budgeted time, to get out front of the problems and fix them before they continue to grow out of control.  The biggest challenge in this is communication.

Management reads, writes and speaks in terms of money.  Saved or spent, it’s all about money.  A business exists to make money, after all.  IT folks read, write and speak operational efficiency.  It often ends up being like a singles bar, and Stevie Wonder is trying to hit on Helen Keller, but the bartender is just watching the train-wreck while drying glasses with a towel.  Consultants are often the bartender in this scene.

If you want to sell your idea to get support, you need to translate what you want into dollars.  Your idea HAS to either save or earn more money than any other option available to them.  This commercial was cute in its day, but it’s actually more true than anyone expected.

  • For every procedural change you want to make, be sure to identify how much money it will save (or new revenue it earns)
  • Talk to your vendors/suppliers about cost implications (licensing, terms, etc.)
  • Double-check your numbers and have someone in Finance review as well
  • Try to avoid solutions that increase costs to acquire or operate, IF you can find or build an equally capable solution for free.  Remember, you want to save your company money (or find new revenue streams).  If it comes down to one retail solution vs. another, so be it
  • Make your proposal clear enough for your grandfather to understand, even if he’s been dead for years
  • Don’t get too immersed in your solution.  There may be a better one, and ego is the devil

Good luck!


Cloud, System Center, Technology

Deploy Office 365 ProPlus with Visio and Project using Configuration Manager 1807 with fries and a soft drink


Update: 2018-08-27

I meant to post this a few weeks ago, but anyhow… Microsoft released an updated ODT which removes the “Match Current OS” option from the language options list.  That seems to work fine.  However, the Project Online client has an issue with the Detection Rule being the same as Office 365 ProPlus.  So the install (deployment) on a machine with O365 Pro Plus (latest/same version) causes the Project deployment to think it’s already installed.  Just change the detection rule and it works.  The Visio Pro deployment uses a different detection rule and seems to work fine.

As for Shared Computer Activation deployments, there are at least two (2) ways to go.  One is supported, the other is unknown (at this point).  The first is to simply build a new deployment, which sounds like a waste of storage space (compared with traditional O365 ProPlus deployment builds using ODT and XML files) but if you have deduplication turned on for the content source location it shouldn’t be a concern.  The other (semi/un-supported) way is to manually copy the “configuration.xml” and make a Shared Activation flavor of it, then add a new deployment type, set some sort of condition to control the scope of that deployment type, and go that route.  A little more convoluted, but possible.

Update: 2018-08-08

While working with a customer to deploy Office 365 ProPlus, with SCCM 1806, we discovered a bug in the OCT that has been confirmed by Microsoft and hopefully fixed soon.  The bug is related to the language selection “Match the Current OS” with respect to (English-US) platforms.  That selection, for some reason, does not download the required language pack files for the deployment source, and causes the deployments to fail with an error that mentions “missing files”.

The catch here is it won’t return an error when it fails via SCCM.  The deployment fails but still returns “success” (exit code 0), and writes the registry key which is shown in the Detection Method configuration.  To see the error, we had to execute the setup.exe with /configure and the relevant .xml file from the client cache folder.  This is actually two (2) “bugs” as far as I can tell.

The fix/workaround is to simply select the actual language (e.g. “English (United States)”) rather than use the default “Match the Current OS”.


Someone asked if that surgeon on the left is Johan.  I cannot confirm, but it wouldn’t surprise me.


  • System Center Configuration Manager current branch 1807+
  • Basic knowledge about how to use ConfigMgr
  • Office 365 / ProPlus licensing
  • Coffee
  • A really bad attitude

Process Overview

  1. Create an Application and Deployment in ConfigMgr
  2. Target a Collection (devices or users)
  3. Drink coffee
  4. Punch someone in the face and go home (no, don’t do that)

Quick Notes

  • During the process of building and deploying the Office configuration, the ConfigMgr console will be locked out from making changes. You can still make it visible, but no scrolling/selecting is allowed.  Therefore, if you intend to deploy the configuration at the end of the procedure below, you should prepare the target collection in advance.
  • This will require access to the Internet in order to download the content for building the O365 deployment source.  If you don’t have access to the internet, you may want to look for a new job.
  • I posted a summary version of this using ConfigMgr 1806 on another blog here.  But this one has french fries.

Procedural Stuff

  1. Open the ConfigMgr admin console.  This is important.
  2. Navigate to Software Library > Office 365 Client Management
  3. On the Office 365 Client Management dashboard, scroll over to the far right until you see that high-quality uglyaficon icon with “Office 365 Client Installer” caption.  Click on it like you mean it.  (Just kidding about the icon, it really is nice)
  4. Give the Application a name (e.g. “Office 365 ProPlus with Visio and Project and Fries – 64-bit”)
  5. Enter a Description (optional)
  6. Enter the UNC source location path (the folder must exist, but the content will be populated at the end of this exercise).  It must be a UNC path. Drive letters are for losers.
  7. On the “Office Settings” page, click “Go to the Office Customization Tool” (or “Office Customisation Tool” for you non-American folks).  NOTE: If you do not already have the latest version of OCT installed, it will prompt you to download and extract it somewhere.  Then it will continue on.  Otherwise, it will just continue on.
  8. The OCT home page uses a layout designed by Stevie Wonder.  It’s very spread out, so, on a low-res display, expect some finger exercise workouts on your mouse or trackpad.  Anyhow, look for “To create or update a configuration file, click Next” and click on (you guessed it:) Next.
  9. The Software and Languages page will open first.
    1. Enter the Organization Name and select the Version (32 or 64 bit), then click Add.  IMPORTANT: Pay attention to the ADD and UPDATE buttons throughout this exciting journey, there is a reward at the end.  I’m just kidding, there is no reward, and no Santa Claus either.  Note also that while you’re making selections and changes, the information is being updated along the right-most column of the OCT form.
    2. Select the Software Suite or Product “Office 365 ProPlus” from the drop-down menu, and click Add
    3. Select the drop-down again, and choose “Visio Pro for Office” and click Add again.
    4. Select the drop-down again, and choose “Project Online Desktop Client” and click Add one more time.
    5. The Software section on the right-hand settings column should show all three selections.6
    6. Scroll down to Languages.  You HAVE to select an option here.  It is not optional.  The default choice for most situations will be “Match Operating System“, however, you can add more languages if you like, or just to have some fun with users by dropping unfamiliar languages on them.
    7. Scroll back up so you can view the navigation menu at top-left again.  Then select “Licensing and display settings
      1. For most situations, the KMS or MAK options will be disabled, with KMS automatically selected.  If yours is different, who cares, I’m writing this crappy blog post, not you.  So there.
      2. Under “Additional Properties“, you can select options to enable Shared Computer Activation, Automatically accept the EULA, and Pin Icons to Taskbar.  It’s worth noting that there is no longer a warning label about the taskbar icons, so it would appear to work on Windows 10.
      3. There is no “Add” or “Update” button to click for this part, so calm down, we’re almost there.
    8. Scroll up to the navigation menu again and select “Preferences“. This is where you may spend the rest of your life clicking on things, because there’s a lot to click on.  Or you may choose to ignore all of it and instead blame configuration issues on whoever handles GPO and MDM settings.  If that’s you, well, it sucks to be you.  Choose wisely.
    9. Take a moment to review your settings along the right-hand “Configured Settings” column.  Take a moment also to reflect on your poor choices in life, those missed opportunities, that last vacation trip, and how dysfunctional your family is (or could be).  Now, when you’re done with that, and put the loaded gun and liquor bottle back in the bottom drawer, and…
    10. Click “Submit” at the very top right.
    11. After you click Submit, you will be returned to the Application wizard.  Click Next.
    12. On the Deployment page, it will ask if you want to deploy the application now.  If you have a target collection ready to go, you can go for it. YOLO.
      If you choose Yes, you will be prompted for typical deployment configuration settings, otherwise, you’ll click Next two more times and then…
    13. Wait for the content to download and the deployment source to be prepared.
    14. Don’t forget to distribute the content to your DPs.
    15. Don’t forget to populate the target collection.
    16. Don’t forget to allow time for policy updates, etc.
    17. You can also modify Office 365 Client Installations by using the “Import” feature at the top-right of the OCT form.

I’d ask for feedback/comments on this, but nobody ever posts feedback or comments.


System Center, Technology

ConfigMgr Anxieties


This is a sampling of the most common situations I run into with customer engagements.  I haven’t followed-up my older “what I learned this week” articles, so this is sort of catch-up.

The following is intended for an immature audience.  Mature people will likely fall asleep before completing this, and may require physical or electrical stimulation to regain consciousness.  I am not mature, so I may fall asleep before you do.

1 – Software and Update Deployments with Maintenance Windows and Overrides


  • You can deploy Applications and Packages to Device Collections and User Collections
  • The Deployment itself has properties (attributes) assigned to stipulate the behavior (schedule, target, restrictions, exceptions, etc.)
  • User and Device Collections can have Maintenance Windows assigned, which provide guard rails for drunken, passed-out, deployments
  • Deployments can be assigned to respect or ignore Maintenance Windows, like a politician at a press conference


  • Machines which end up in multiple collections with maintenance windows can easily become unpredictable
  • Machines that end up in multiple non-contiguous maintenance windows can become a reason to drink
  • People who place machines into multiple collections with unique maintenance windows may end up duct taped to a urinal at a bus station
  • It’s easy to forget Maintenance Windows, or how they overlap and pile up on devices which end up in multiple collections


  • Use maintenance windows sparingly
  • Plan all of your maintenance window needs before you apply the first one
  • Consider naming Collections to indicate maintenance window involvement (as well as the window itself: example = “Crappy Machines – MW – Fridays 5p-11p”)
  • Consider custom Device Client Settings for roaming devices, versus stationary devices

2 – Operating System Deployments and PXE Panic


  • You can target PXE deployments of OSD Task Sequences to Collections
  • You can restrict the Deployments to recognize only existing ConfigMgr Clients, or “unknown” Computers (never been on your network or AD or ConfigMgr), or allow anything (both known and unknown)
  • Targeting PXE OSD deployments to both known and unknown can be risky


  • It is actually not easy to accidentally image production machines via PXE using SCCM OSD
  • In order to “accidentally” re-image existing/known computers, you’d have to:
    • Target the wrong Collection(s) with a…
    • Zero-Touch (ZTI) task sequence, and…
    • Select the wrong availability, such as allowing ConfigMgr clients, and…
    • Set the Deployment purpose option to “Required”, and…
    • Not have a PXE password enabled, and…
    • Have the devices boot configuration set to boot from the Network first, and…
    • Not know what you’re doing
    • Not ask for help when you realize you don’t know what you’re doing
    • Getting ready to quit your job out of anger at your employer


  • Be careful with Deployment targeting
  • Clearly name your Task Sequences so your worst technicians can still understand which ones to select
  • Restrict access to Deploying Task Sequences (and anything else) if you work within a large team (tip: roles and scopes are your friend)
  • Consider using a central or regional workbench process, with a local PXE responder (DP, etc.) on the same subnet, isolated from the production network on a common switch.  The network team doesn’t need to be bothered
  • Use a controlled password on your PXE responder (DP, etc.)
  • Slip Xanax into the coffee pot near the network team (just kidding, don’t do that)

3 – Collection Limiting and Refresh Scheduling


  • Collections with Query Rules are “limited” to being a subset of a parent Collection, called (queue the dramatic music) a “limiting collection”
  • A limiting Collection restricts the scope from which the dependent Collection can see resources to consider as members.  If the limiting Collection doesn’t contain a resource, the dependent Collection won’t be able to add it as a member


  • A Query-Rule Collection will only refresh membership results as often as its limiting Collection.  In other words, if the limiting Collection refreshes every 7 days, the dependent Collection can be set to 1 day, but will only update when the limiting Collection hits its 7 day cycle
  • Query-rule Membership Collections with very short refresh cycles may impact site server performance, and may cause ripple effects which can further impact performance
  • Avoid using a lot of incremental updates for collections.
  • Be careful with Direct-rule Membership Collections and assigning refresh schedules


  • Pay attention to Limiting Collections and their membership rules and refresh schedules.
  • Consider tuning query rule collection refresh schedules during and after major changes to the environment only.  For example, during OS migrations/upgrades, reduce the interval to get faster reporting updates, but after the bulk of activity dies down, increase the interval back to reasonable values
  • If you’re not a DBA or DBD, go talk to one and ask for advice on query optimization techniques.  They may look at you like an Ebola patient when you show them WQL, but free doughnuts or Empanadas, and coffee should calm them down again

4 – Accounts and Security


  • ConfigMgr uses several security (user-type) accounts for various features.  Each account is used in a unique and different way, for a unique purpose.  Some are mandatory, and some are optional:
    • Site Installation and Initial Configuration (Windows, SQL Server, AD)
    • Client Push Installation (Workstations, Servers, Domain Controllers, Classified/Sensitive systems, etc.)
    • Network Access / Software Distribution and OSD
    • Domain-Join / OSD
    • Build and Capture / OSD
    • Remote Tools / Client Settings
    • Roles / Accounts / Administration
    • Discovery Methods / Administration
    • Cloud Services / Administration
  • Each account has unique access/privilege needs


  • Accounts which are used by multiple (unrelated) systems often add risk of unexpected interruption by other users (password changes, account lock-outs, etc.)
  • You can often control team access from application-level groups, or via AD security groups.  Trying to manage it both ways often leads to unwanted results.


  • Avoid using SCCM-related accounts for multiple purposes, even within SCCM
  • Aim for dedicated, purpose-driven accounts, exclusive to what they’re intended for
  • Grant each account only the bare minimum permissions it needs
  • Choose a consistent manner by which to manage team access to tools and features
  • NEVER share the use of a ConfigMgr service account with an unrelated system or process
  • NEVER use a person’s own login account for a service account
  • Avoid using a person’s own login account for building site systems
  • Document everything, and track changes always

5 – Device Imaging, Naming and Provisioning


  • If you don’t provide an explicit name for each device during imaging, the default name will suck
  • Sucky device names make for a sucky day at work
  • You can assign a unique device name to a bare metal imaging process using a variety of means within ConfigMgr:
    • Collection Variables
    • UDI form input, or tools like UI++
    • Custom (script) form input
    • Semi-Automated using external systems / third-party tools or custom development
    • Completely Automated using internal data
  • You can spend hours, days, even weeks on the perfect naming process


  • There is no 200 level.  Don’t listen to that other guy


  • Strive for fully-automated, zero-input processes
  • Watch out for forgetting Collection Variables while trying to implement other options at the same time
  • Count the time you spend on device naming (if you’re not already fully-automated) and assign a dollar figure to that, tally it up weekly, monthly and annually.  Then see if it saves you more than that somewhere else, and by how much.  I bet it’s not saving you anything at all (dollar-wise)

6 – Guard Dogs and Anti-Malware Fences


  • Anti-Virus / Anti-Malware is intended to protect your computer from malicious code
  • Most AV/AM products are general in nature, rather than specifically-tuned for every other product you may have installed.
  • Some products step on common parts of a computer which cause AV/AM products to react as if it is malware.
  • System Center Configuration steps on a lot of those parts.
  • Most AV/AM products do not know what Configuration Manager is.
  • Many Windows 10 migration projects are derailed or delayed by AV/AM interference
  • The less consistent your AV/AM environment, the greater the interference risk and scale of impact to migration projects


  • One of the most common interference issues is having unsupported (outdated) AV/AM client versions installed on machines
  • Another common problem are rogue AV tools installed inconsistently throughout the environment
  • Most AV/AM products like McAfee, Symantec, Sophos, provide administrator consoles for managing their own environments.
  • Most AV/AM admin consoles are in front of dedicated AV admins
  • Most AV/AM admins have some sort of favorite food or drink.  Leverage that.


  • Make sure all AV/AM clients are on a consistent, and Windows 10 supported, version.  Refer to vendor docs like McAfee, Symantec and Sophos or whatever you use, for more details.
  • Grant exclusions for ConfigMgr client footprints, such as files/folders, registry paths, services, processes, etc.
  • Don’t forget the firewall exceptions
  • Don’t forget the exclusions for the ConfigMgr site servers too
  • Don’t forget food bribery works wonders on cross-team collaboration

7 – Failing to Keep Up


  • Many customers are still on ConfigMgr 2007, 2012, 2012 R2, as well as Windows Server 2003, 2008, 2008 R2, and SQL 2008, 2012
  • Many customers are still on Windows 7, Office 2010 or 2013
  • Many customers have moved up to ConfigMgr Current Branch, but are still behind on site updates/upgrades.
  • Many customers upgraded in-place but didn’t spend time on the underlying infrastructure (Windows Server OS, SQL Server, physical and virtual resource allocations, etc.)
  • Current levels are Windows Server 2016, SQL Server 2017, SCCM 1802, ADK 1803, MDT 8450, and Windows 10 1803


  • Many sites haven’t been diligent on keeping 3rd party apps updated consistently
  • Many customers haven’t kept their AV and disk encryption installs consistently up to date


  • Focus on bringing all of your platforms up to date
  • Consider a new stack and clean cut-over if possible
  • Double-check your licensing and resource constraints (VM hosts, storage, etc.)
  • Update or replace peripheral processes, like backups, monitoring, etc.
  • Consider third-party tools to augment things like patching, backups, automation, etc.

Did I miss anything?  Let me know in the comments below.

Thank you!

System Center, Technology

Deploying the ConfigMgr 1802 Admin Console with Recast Right-Click Tools

I’ll spare you a long back story, rationale and explanation behind this, and just jump right into the “how”.  I’m guessing you already know “why”, or just think this is a stupid waste of time.  Either way, life is good.

Deploy the Admin Console

1) Copy the ConsoleSetup folder from \\<servername>\SMS_<sitecode>\Tools over to your Sources location (e.g. “\\<fileserver>\sources$\apps\microsoft\ConsoleSetup”).

2) Create a new Application:

3) Add a Deployment Type…

4) Set the Content (Install/Uninstall) options…

Content Location: \\<servername>\sources\apps\ConsoleSetup
Installation Program: “ConsoleSetup.exe” /q DefaultSiteServerName=cm01.contoso.local TargetDir=”C:\ConfigMgrConsole
Uninstall Program: “ConsoleSetup.exe” /q /uninstall

Locate a reliable detection type.  I chose the Registry.  Keep in mind it is a 32-bit application…

5) Set the User Experience options…

6) Set Requirements if you wish…

7) Click Next on Dependencies, and continue to the finish.  Return to the Application properties form.

8) Click Next and continue until finish.

Note: You can bundle the latest console updates into the deployment, leveraging the same background process that AdminUI.ExtensionInstaller.exe uses: installing the most-recent .msp patch file(s).  But that can add more work for you keeping up with the .msp files, deployment types and detection methods.  Being lazy, I prefer just deploying the most-recent base version and let the user click “Yes” to the prompt to update it after the first launch.  Less work for you, and it annoys them, so it’s a win-win.

Deploy the Right-Click Tools

If you are wondering “why bother with RCT anymore?” that’s a fair question.  While the iterative console improvements are very nice, and the newer “Run Scripts” feature can do many of the same chores, there are still some nice features in RCT that make it nice to keep around.  If you don’t care about RCT, just skip this section and go to step 16.

If you haven’t downloaded the Right-Click Tools by now, go here, fill-out their registration form, wait for the email with the download link, and download the .msi package (e.g. Recast_RCT_Latest.msi)

9) Place the RCT installer .msi file into a new source location for importing into ConfigMgr.  Example “\\<server>\<share>\<folder>\Recast_RCT_Latest.msi”

10) Create a new Application for the Right Click Tools using the MSI package

Wait for the progress bar…

11) Modify the properties as you see fit…

Review the Summary and continue (or go back and drink more coffee)…

Modify the Deployment Type on the Right-Click Tools Application

12) Edit the Deployment Type

13) Select the Dependencies tab, and click Add

14) for the Dependency group name, enter “required”, then click Add

15) Select the ConfigMgr Console Application, and select the Console Setup Deployment Type and click OK

Click OK again, and confirm that the Automatic Installation option shows “Yes”.  If it doesn’t, you have failed, and you must slap yourself in the face.  Otherwise, continue on…

16) Distribute the Content to your DP servers

17) Deploy the Right-Click Tools so it will launch the dependent installation for the Console first.


Scripting, System Center, Technology

A Windows 10 Imaging 2-Step Boogaloo

It’s a new dance, and it goes like this…

Step 1 – Left foot forward: Image the device with a generic name, unplug, place on a shelf

Step 2 – Right foot to the side: Fetch from shelf, run script to assign to a user, hand device to user, go back to surfing Twitter

What could possibly go wrong?

Caveat Stuff

This “procedure”, if you will, is predicated on a scenario where the devices are NOT going to retain the auto-generated name when going into production.  They will instead use a unique name based on whomever they are assigned to (e.g. SAMaccountName, etc.).  If you can, I strongly recommend NOT doing this, which would seem strange that I’m essentially negating all of the remainder of this stupid blog post and telling you to just follow step 1, sort of.  However, if you insist on using “JSMITH”, or some other ad hoc data entry value, for the device name, then by all means, drink up, snort up, shoot up, and continue reading.  Thank you!

Errata / Disclaimer / Legal Stuff

At no point in any time in inter-galactic history, for any purpose or interstellar war or planetary conflict, shall anything mentioned herein be provided with any semblance of a warranty, guarantee, or promise that it will be error-free or suitable for your needs.  Nor shall this brainless author assume any liability, or responsibility for any direct, indirect, or alleged damages or loss of productivity, possibly attributed to the direct or indirect use of any information provided herein, for any purpose, explicit or implied, notwithstanding hereinafter for any jurisdiction of human societal or governmental law, or any group of suits on a golf course, related therein.  Golf carts and Martinis are not included.

…and One More Thing

Many blog posts / articles tend to portray a tone of “this is how it’s done”.  This blog post is different for two reason: (a) It’s just ONE example of dealing with ONE common scenario, out of quadrillions of bazillions and kadrillions of possible scenarios, and (b) it’s likely to be the dumbest article you’ve read today.

Step 1 – Image and Stage Device

This step is all about imaging a new device (or wipe/reload an existing device) whereby it isn’t immediately assigned to some whiney complainer, oops, I mean user.  It goes on a shelf, gathering dust, while it awaits being assigned to someone.

  1. Create / Copy / Hallucinate a PowerShell script:
    > It derives a name using available data (ex. Serial number, MAC, etc.).
    > Save the script in a shared location to allow for making a Configuration Manager Package.
    > Refer to horrifically inept script example further below.
  2. Create a new Package in Configuration Manager
    > Note: if you already have a OSD-related package for bundling your script goodies, just toss it in with the rest and they’ll play like over-caffeinated kids in one of those gooey McDonald’s Playland ball pits.
    > Distribute or Update Distribution on the Package
  3. Add a step to your OSD Task Sequence
    > Insert just before “Apply Operating System”
    > Run PowerShell Script –> Choose the Package, and enter the script name and parameters/arguments, select “ByPass”
    > Note: If you want to assign a common OU just assign it in the Task Sequence “Apply Network Settings” step, or add your own “Join Domain or Workgroup” step.
  4. Deploy the Task Sequence
    > If you target “All Unknown Computers”, make sure the collection does not have the “OSDComputerName” Collection Variable attached

Step 2 – Provision and Assign to Hapless User

This step is all about getting up from your desk, grunting and complaining the entire way, maybe knocking over your cup of cold coffee, to shuffle slowly over to the dust-covered shelf, fetching a pre-imaged device, and doing some doodling on it so it can be handed to a bitchy customer, oops, again, I mean user.  Okay, in all seriousness, you may be lucky today, and the user is actually a cool person.  But you’re reading my blog, which means you’re probably not that lucky.

  1. Plug device into your network
  2. Find something to talk about while you wait for it to boot up
  3. Log in using your magical omniscient IT wizard power account
  4. Run a crappy half-baked PowerShell script which renames the device and moves it to a special AD Organizational Unit (OU) to suit the user’s department, etc.
  5. Wait for the reboot
  6. Unplug the device
  7. Throw at the user as hard as you can
  8. Go back to reading Facebook and Twitter
  9. Wait for Security to arrive and escort you out of the building

Horrifically Inept Script Examples

I told you they were going to be horrific and inept, but you didn’t think I was serious.

Script 1 – Assign a “Temporary” Device Name during OSD Task Sequence

Save this mess to a file named “Set-DeviceName.ps1”

param (
  [string] $Prefix = "TMP"
$SerialNum = Get-WmiObject -Class Win32_SystemEnclosure | Select-Object -ExpandProperty SerialNumber
$NewName = "$Prefix-$SerialNum"
# in case you're imaging a VM with a stupid-long serial number...
if ($NewName.Length -gt 15) {
  $SerialNum = $SerialNum.Substring(0,15-($Prefix.Length+1))
$NewName = "$Prefix-$SerialNum"
try {
  Write-Verbose "new device name = $NewName"
  $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment
  $tsenv.Value("OSDComputerName") = $NewName
  Write-Verbose "OSDComputerName = $NewName"
catch {
  Write-Verbose "not running in a task sequence environment"
  Write-Host "new device name = $NewName"

Script 2 – Provision Device for Assigned User

Note: The following chunk of PowerShell code might look impressive, but that’s because I didn’t create all of it.  I just modified original examples shared by John Warnken and Stephen Owen.  Save this mess to a file named “Assign-UserDevice.ps1”.  This script relies on the “Locations.csv” file to provide the list of locations and department codes for the popup form.

param (
  [parameter(Mandatory=$False, HelpMessage="CSV input file path")]
    [string] $CsvFile = "",
  [parameter(Mandatory=$False, HelpMessage="Form Title")]
    [string] $FormTitle = "Contoso - Provision Device",
  [parameter(Mandatory=$False, HelpMessage="Maximum UserName character length")]
    [int] $MaxUserNameLength = 11,
  [parameter(Mandatory=$False, HelpMessage="Force Upper Case username")]
    [switch] $IgnoreCase,
  [parameter(Mandatory=$False, HelpMessage="Keep existing OU location")]
    [switch] $KeepOuLocation,
  [parameter(Mandatory=$False, HelpMessage="Apply Changes")]
    [switch] $Apply,
  [parameter(Mandatory=$False, HelpMessage="Do not force a restart")]
    [switch] $NoRestart

$ScriptPath = Split-Path -Parent $PSCommandPath
if ($CsvFile -eq "") {
  $CsvFile = Join-Path -Path $ScriptPath -ChildPath "Locations.csv"

function Move-ComputerOU {
  param (
    [string] $TargetOU
  $ComputerName = $env:COMPUTERNAME
  $adssearch = New-Object DirectoryServices.DirectorySearcher
  $adssearch.searchroot = $ads
  $adc1 = $adssearch.findall() | Where-Object {$"cn") -like $ComputerName}
  $ComputerDN = $"distinguishedname")
  Write-Verbose "distinguishedName = $ComputerDN"
  $adc = [adsi]"LDAP://$ComputerDN"
  Write-Verbose "target path = $targetOU"

if ($MaxUserNameLength -gt 9) {
  Write-Warning "UserName portion cannot be longer than 9 characters when the prefix is 6 characters long"

if (!(Test-Path $CsvFile)) {
  Write-Warning "CSV Input file not found: $CsvFile"
$LocData = Import-Csv -Path $CsvFile

[xml]$XAML = @' 
  Height="200" Width="320" Topmost="True" WindowStyle="ToolWindow" 
  WindowStartupLocation="Manual" Top="200" Left="200" 
  FocusManager.FocusedElement="{Binding ElementName=ComputerName_text}"> 
    <Label Name="Label_Warn" Content="" HorizontalAlignment="Left" Foreground="#ff0000" Height="27" Margin="15,0,0,0" VerticalAlignment="Top" Width="300" />
    <Label Name="Label_Loc" Content="Loc+Dept" Foreground="#000000" HorizontalAlignment="Left" Height="27" Margin="15,20,0,0" VerticalAlignment="Top" /> 
    <Label Name="Label_Dlm" Content="-" Foreground="#000000" HorizontalAlignment="Left" Height="27" Margin="125,50,0,0" VerticalAlignment="Top" />
    <Label Name="Label_Num" Content="UserName" Foreground="#000000" HorizontalAlignment="Left" Height="27" Margin="150,20,0,0" VerticalAlignment="Top" />
    <ComboBox Name="Combo_Loc" Margin="20,50,0,0" Height="27" Width="90" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalContentAlignment="Center">
    <TextBox Name="Text_User" Margin="150,50,0,0" Height="27" Width="90" HorizontalAlignment="Left" VerticalAlignment="Top" VerticalContentAlignment="Center" Text="" MaxLength="20" CharacterCasing="Lower" />
    <Button Name="Button_Continue" Content="Continue" Margin="90,100,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Height="27" Width="100"/> 

# Read XAML string and convert into a form object
$reader = (New-Object System.Xml.XmlNodeReader $xaml) 
$Form = [Windows.Markup.XamlReader]::Load( $reader ) 

# Add Form objects as script variables 
$xaml.SelectNodes("//*[@Name]") | ForEach-Object {Set-Variable -Name ($_.Name) -Value $Form.FindName($_.Name)} 

foreach ($loc in $LocData) {
  $LocDept = "$($loc.Loc)$($loc.Dept)"

$Form.Title = $FormTitle
$Text_User.Maxlength = $MaxUserNameLength
if (!($IgnoreCase)) {
  $Text_User.CharacterCasing = "Upper"
# add form handler for pressing Enter on UserName text box
  if ($args[1].key -eq 'Return') {
    Write-Verbose "action -> user pressed Enter on username textbox"
    $Location = $Combo_Loc.SelectedValue
    $UserName = $Text_User.Text.ToString()
    Write-Verbose "selection -> $Location"
    Write-Verbose "username -> $UserName"
    if (!([string]::IsNullOrEmpty($Location))) {
      $Script:LocIndex = $Combo_Loc.SelectedIndex
      $Script:NewName = $Location+'-'+$UserName
      $Script:Ready = $True
# add form handler for clicking Continue button on exit
  Write-Verbose "action -> pressed Continue button"
  $Location = $Combo_Loc.SelectedValue
  $UserName = $Text_User.Text.ToString()
  Write-Verbose "selection -> $Location"
  Write-Verbose "username -> $UserName"
  if (!([string]::IsNullOrEmpty($Location))) {
    $Script:LocIndex = $Combo_Loc.SelectedIndex
    $Script:NewName = $Location+'-'+$UserName
    $Script:Ready = $True
# display the form for the user to interact with

$Form.ShowDialog() | Out-Null

if (!($Script:Ready)) {
  Write-Warning "No selection or entry. Nothing to do."

$RowSet = $LocData[$Script:LocIndex]
$OuPath = $RowSet.DeviceOU

if ($Apply) {
  Write-Host "New Name...: $NewName" -ForegroundColor Green
  if (-not ($KeepOuLocation)) {
    Write-Host "OU Path....: $OuPath" -ForegroundColor Green
    Move-ComputerOU -TargetOU $OuPath
  Write-Verbose "renaming computer to $NewName"
  Rename-Computer -NewName $NewName -Force
  if (!($NoRestart)) {
    Restart-Computer -Force
else {
  Write-Host "Test Mode (No changes were applied)" -ForegroundColor Cyan
  Write-Host "New Name...: $NewName" -ForegroundColor Cyan
  if (-not ($KeepOuLocation)) {
    Write-Host "OU Path....: $OuPath" -ForegroundColor Cyan

Locations.csv File for Assign-UserDevice.ps1

Note: “Loc” can be a building, campus, city, or whatever.  The ADGroup column is for future/optional/possible/potential use for adding the computer to an AD security group as well.


Cheesy Examples

Example: Assign-UserDevice.ps1 -MaxUserNameLength 9 -Verbose

Summary and Conclusion

As you may have surmised by now, everything you’ve read above is completely stupid and useless. You’re shaking your head in disbelief that you skipped some other opportunity to read this, and you should have chosen otherwise, even if that other opportunity was a prostate exam.  You are now dumber for having read this.

You’re welcome.