Technology, windows

Windows 11 – Part 2. The Electric Boogaloo

I’ve already shared my thoughts on Windows 11, but that was pre-release. This is now.

WARNING: May contain language not suitable for intelligent people.

copyright 2017 skatterbrainz

What I like about Windows 11

Pretty much the same as my previous post. The user interface is nice. It’s clean. It’s refined. It’s fresh. It’s a lot like MacOS, and I don’t even use a Mac (my son uses Mac exclusively, and loves to joke about Windows 11 now).

The new Settings app is finally what it should’ve been from day one with Windows 10. It looks like it was kidnapped in a white van from camp Linux, but it’s really nice. I like it.

The centered taskbar is not really a deal-breaker for me. I know some people hate it, but I just don’t care if the icons are in the middle or to the left/right/top/bottom, etc. But if you want some (really nice) PowerShell help with the UI, check out CustomizeWindows11 by Jaap Brasser. (Install-Module CustomizeWindows11).

“Windows Terminal” has replaced “Windows PowerShell” as the default Start menu right-click option. I like Terminal a lot.

Finally! The “Enterprise” SKU doesn’t install a bunch of stupid games like Windows 10 did early on (Candy Crush, etc.) Someone finally listened to the business customers.

What I don’t like about it

It’s still version 10.x (10.0.22000 to be exact). As if vendors can’t do the ($version -ge 10.0) math? Why?

PowerShell 5.1 is the only version installed by default. Why?

The same old prompt to run “Install-PackageProvider -Name NuGet -MinimumVersion -Force”. I tweeted that this is like selling cars with 1 lug nut missing on each wheel, every single year, and requiring buyers to install the nuts themselves. This is approaching government-level stupidity. Why?

TLS is still “SystemDefault”, not 1.2. Shouldn’t it default to 1.2 and let customers downgrade if needed? I thought “security” is a major selling point of this version.

PowerShell still isn’t woven into the fabric of the UX, it’s still an add-on. For example, in some apps like SSMS, you can right-click and generate a script of a desired action (create, delete, etc.), but why not in Explorer, REGEDIT, or Event Viewer? Frivolous? Maybe. But still… aside from die-hard PowerShell geeks, how much cumulative time is spent every year by users Google searching how to update a registry value, or export event log search results.

WinGet is flaky. Yes, flaky. Consider item 1, your honor:

winget install --name notepad++ 

This did not work.

This returns an error that there are “Multiple packages found matching input criteria”. No, there are not. There is only one with name “Notepad++”. The other is “Notepad+” (one plus sign). You have to use –id notepad++.notepad++ (kind of like Little Caesar’s pizza pizza) for this one. This tells me that the input filter handler is flawed (defaulting to regex or something that’s not swallowing the “++” properly).

Also, silent installs are NOT the default. You will need to be careful to add –silent, and possibly –accept-package-agreements, and –accept-source-agreements. The default appears to be what MSI folks would use as /qb! (basic w/no cancel).

The winget silent install command that worked for me

winget install --id notepad++.notepad++ --silent --accept-package-agreements

I’m aware this is nit-picky, but Chocolatey (my favorite package manager so far) doesn’t have this issue. The corresponding command to run a silent install of Notepad++ with Chocolatey is

cinst notepad++ -y

The other complaints I mentioned in the previous blog post still stand. For example,

  • No “Edit” option on right-click menus for PowerShell scripts. Why?
  • File extensions are still hidden by default. Why?

And speaking of hidden file extensions: It’s time once again for…

Exam Question of the Day

You call a (non-technical) user to advise them to perform certain actions while troubleshooting an issue on their shiny-new Windows 11 laptop. You have to speak loudly to overcome the sounds of cats on their end.

You: “I need you to edit the PowerShell script I just copied to your Documents folder. It’s named ‘Sample.ps1′” (see Figure 1)

Them: “Ok, How do I edit it?”

You: “Right-click on it and choose ‘Edit'”

Them: “There is no ‘Edit’. Should I use ‘Open’?”

You: “No!!!!!!!!! It’s got to be modified before you run it!”

Them: “I don’t like your tone. I’m hanging up and calling HR.”

You: (starts working on resume and updating LinkedIn profile)

Try this again…

You: “No. Just right-click on the one without an extension on the name.”

Them: “What’s an extension?”

You: (rubbing your temples with a 9mm and a glass of whiskey) “It’s…. uhhh…. hold on (sips, clicking sound)…. “okay, happy thoughts…”

Them: “What? Are you okay?”

You: “Yeah, I’m fine. It’s just, oh, never mind. So, I’ll need to ask you to click on “View” at the top of the Explorer window, then click on “Show” at the bottom of that popup menu, then click on “File name extensions”.

Them: “That’s dumb. So many clicks? Why aren’t these extensions turned on by default?”

You: “YES!!!! OMG! OMFG!! I love you!!!” (drops headset, and knocks over shot glass)

Them: “I’m married! You need to calm down!”

You: “Yes, I apologize. All good. Let’s continue…”

Which of the following will satisfy the requirement

A. Quit this IT job and pursue woodworking or guitar playing

B. Ask the user to marry you

C. Continue drinking and playing with your gun

D. Use a GPO or MDM policy to show file extensions, because they should have been displayed by default, from the very first version of Windows to contain Explorer. Then complain to everyone else on StackOverflow, Slack, Discord, Twitter, Reddit, Facebook, Twitch and maybe even LinkedIn, then post on your blog about it.


Figure 1
Figure 2
Figure 3
Figure 4

As with everything software, it’s never done. Windows 11 will continue to evolve, like all other software products. So I would expect some of these complaints to be remediated over time. It’s just annoying that some of these complaints have been around for a very long time (file extensions, PowerShell version), and some appear to be regressions (right-click menus). That’s a sign of one of two possible things going on:

  • Internal knowledge sharing is broken (old team to new team, or product1-team to product2-team)
  • The customer feedback system is broken (user feedback is not being collected and/or assessed properly)

Maybe Windows 11 22H1 or 22H2 will take care of this.


My Windows 11 Score Card

Updated: 2021-09-30 (see PS at the end)

Windows 11 is actually 10.0.22449. If Steve Ballmer was still doing the monkey dance, it would most likely be named “Windows 10 Ultimate Extras Edition”. Software versioning has always had a weird, glue-sniffing history. IBM’s OS/2 Warp was 3.x then 4.x before being left on the roadside. How is (or was) an “OS/2” not automatically a version 2.x?

When Windows 8.1 skipped over 9.x to 10.x, the excuse was third party crackhead developers were too dumb or lazy to differentiate 9 from 95 or 98. Because strings are tough, but version numbers are tougher? Autodesk was one of the few companies I can think of who stuck to a consistent version sequence, at least for most of their products. And they weren’t scared of using the superstitious 13 in a version (AutoCAD R13).

For decades, a “major” upgrade meant breaking changes. Significant things were added, removed or modified. But, as with IT job titles, the labels aren’t what they used to be. An “analyst” used to analyze things. Today, it’s just a title and the duties are anything but. The same seems to be true for version numbering. Office 2019 is 16.x, and Windows 11 is 10.x). The marketing folks have taken control of the spaceship.

Anyhow, I digress. Let’s dive into my meaningless list of meaninglessness…


As shocking as it may be: Windows 11 is the next version after Windows 10. It’s supposed to be 1 better, but (so far, to me anyway) it’s about 0.25 better. The most significant changes appear to be in two general areas:

  • Security
  • Comfort

The security improvements in Windows 11 are generally based on a higher bar for hardware compatibility (TPM 2.0, SecureBoot, Intel 8th gen processor, etc.). As far as I can tell, there aren’t any major replacements to the Defender stack that ships in the OS, nor to things like ACLs or accounts.

The comfort improvements in Windows 11 are mostly lipstick, and a spandex girdle, but some of the body parts are in better shape.

What it is

So far anyway, because it’s not scheduled for release until October 5, 2021 (roughly 28 days from now) Windows 11 is an incremental update to Windows 10. It still includes all the legacy stuff that you loved from Windows (pick any version), with some new adjustments. Windows Scripting Host (and VBScript, etc.) are alive and well. Control Panel and MMC are still sitting on the sofa watching TV. Third party apps can still smash your configuration and leave it in a back alley if you allow it.

However, it’s not all doom and gloom. The Settings app has been overhauled, and finally where it should’ve been in Windows 10. I don’t really consider that a “new” feature, but more of a “late” feature. Even though Control Panel is still hiding under the bed. Another nice change is Windows Terminal being the default for the right-click Start menu.

What is isn’t

What it is not… a true “major” upgrade release (IMHO). A major upgrade (IMHO) would be changing major things, like Program Files (x86) and WOW6432Node, start with modern baselines (PowerShell), remove legacy stuff like Silverlight, Windows Scripting Host, and Internet Explorer components. COM and DCOM are still there. The same REGEDIT, CMD, MMC, and related MSC things like EVENTVWR, CERTIFICATES, are all there. To me, 11.0 should bring 100% parity between GUI and CLI (or .NET/PowerShell), but it still hasn’t reached that point.

What I like

  • The Settings app is finally what I had expected Windows 10 to get to, but never did
  • Terminal replaces PowerShell on the (right-click) Start menu
  • The icon themes are cleaner (generally speaking)
  • “Copy as Path” on the main right-click menu (no need to hold Shift, etc.)

What I Don’t Like

  • Right-click menus are weird. I can’t think of a better word
  • PowerShell 5.1 is the default
  • TLS 1.2 is still not the default
  • Taskbar right-click is USELESS unless you’re within the icon stack area (wasted potential)
  • It still relies on Windows Scripting Host for things like slmgr.vbs and ospp.vbs (Office) among other things
  • Control Panel is still hiding under the bed
  • Internet Explorer is deprecated, sort of, but also hiding under the bed with Control Panel, sort of
Pop-up: 3 main items, with 3 child items? Why not 6 on one menu?

Right-click taskbar could show what Windows 10 does, but doesn’t.

Right-click: Copy as path is nice. But no “Edit” on the right-click pop-up menus? That seems risky with script files. (the icon strip is “cut”, “copy”, “rename”, “share” and “delete”)
Start menu right-click: Nothing surprising, but I’d still like to see “Windows Update” included.
The overall UI theme is starting to look a bit Gnome-ish to me. Nothing wrong/bad about that, just an observation.

What I was hoping for

The following items are still on my wish list for an imaginary real major upgrade, if it happens in my lifetime:

  • Start with latest/current API items:
    • .NET, PowerShell, Nuget, PowerShellGet, etc.
  • Remove 32/64-bit distinctions
  • Remove spaces in core folder names: “Program Files” –> “ProgramFiles” or just “Apps”
  • Update basic apps like:
    • Notepad: line numbers, circular find/replace
    • REGEDIT: “Script As” > “Create”, “Delete”, etc. (using PowerShell, a la SSMS)
    • Explorer: Move Defrag, CheckDisk, Sharing, Permissions to the right-click menu
    • Mail: Yes, the weird store app, doesn’t follow the same UI motif as anything else. Maybe it should look a little bit like I know, that’s a dumb thought.


I respect the complexity of both Windows as a product, and the Windows platform as an ecosystem, present themselves to Microsoft when it comes to steering that ship. The impact it has on customers, partners, vendors, developers, and more, has to be challenging. Kind of like Justin Bieber trying to go shopping at a downtown mall without any bodyguards.

However, when I watched Panos deliver that heartfelt monologue, sans John Williams music score, I expected a tectonic shift would be coming. This is more like a table bump. Why not just call it “Windows 10+” or “Windows 10.1”? It’s about as significant of a change as Windows XP going to SP2 (remember the firewall changes?) This feels, to me at least, more like a service pack combined with a feature pack, than a “major” upgrade.

I’m admittedly sounding a bit negative, I admit, even though I already admitted that. But, I need to be clear about why. It’s not the product itself, it’s the expectation vs. delivery. The product itself looks and feels rock solid, to me. The marketing hype always makes me cringe, because (and I’m no Apple fan) it seems like the trend is to position every new announcement like Steve Jobs would have done it, maybe with some orchestral string swells to add some drama. But there’s more to that than just playing the part, you have to clear the checklist too. I just hope that the next incremental update (which is what this really is) isn’t going to be called Windows 12, but 11.x (if the version number ever gets to 11.x).

PS (Sept 30, 2021)

I’ve heard some feedback on specific problems with various device models, but I would caution to check if it’s vendor-specific, rather than Microsoft. For example, I have a Lenovo P50 in my lab which keeps installing a stupid crappy Lenovo driver that breaks the fingerprint reader. At first it seemed like a Windows 11 feature/setting was disabling it, but removing the stupid crappy Lenovo driver, and a restart fixed it. So, I would recommend confirming the actual source of issues if/when you encounter them.


Who’s on First.

Setup: A doctor, a lawyer, and a cloud engineer, having a conversation over drinks.

“I have a sore.”

“You have a S.O.A.R.?”

“No, a sore.”

“Oh. I thought you mean a Security, Orchestration and Response.”

“That’s dumb. Everyone knows it means SSI/SSDI Outreach, Access and Recovery!”

“Secure Socket Interface?”

“No. It’s related to helping people on SSA.”

“My nephew is a member of SSA.”

“Member? You mean employee, right?”

“No. Seismological Society of America. He’s a geologist by trade.”

“Oh geez, you guys. Talk about SSDD!”

“I bought a Samsung SSDD. I got a good deal on it online.”

“Ted. That’s shame shit, different day! I didn’t know you could buy one of those.”

“Oh. I thought you mean an SSD device.”

“Anyhow, what kind of sore?”

“Not really A sore, but I have a sore knee.”

“You should see a doctor for that.”

“Like a DO?”

“Delivery Optimization?”

“What’s that?! I mean a Doctor of Osteopathy! Geez!”

“Speaking of. Did any of you guys happen to catch that update on MCAS?”

“Wait. Microsoft Cloud App Security or Marine Corps Air Station?”

“No. Mast Cell Activation Syndrome. My cousin has it.”

“What was the news?”

“He was accepted into a phase 1 trial for a new study they’re doing out at MCAS Cherry Point”

“Wait. So he’s doing an MCAS study at an MCAS?”

“I know, right?”

“So, confusing.”

“I heard the Corps is moving to the cloud and using MCAS.”

“MCAS is using MCAS for an MCAS study?”

“Just stop it.”

“Is there an acronym for acronym?”

“I think it’s ‘acro’, but don’t quote me.”

“Hey, Bob. What do you know about SMS?”

“You mean SMS texting, Springfield Middle School, or Safety Management System?”

“Uh, no. I’m talking about a Security Monitoring System.”



Let’s get (remote) connected. Mmmkay?

You start work on Monday at the reputable company, makers of robotic death machines for sale to anyone with a credit card. Their motto is “security is never secure enough“, referring to their super-duper extra ultra mega turbo secure environment. The rumor is that it was created by the previous CIO before he was convicted of embezzlement, but that’s not discussed at anymore.

After you check in at the front desk, and get your picture taken, badge printed, finger-printed, retinal scanned and voice printed, you’re escorted to the conference room, shown the coffee area and pile of sugary stuff. After a few minutes, your “ambassador” person walks in and begins your orientation.

Them: “Are you excited?!” (loud, startling clap and over-caffeinated facial movements) “Let’s begin!

(several back and forth challenges “That’s not an enthusiastic reply. Let’s try that again!”)

You: “Yes! Okay, where do we start?

Them: “First, you need five separate physical machines, which are all on order. Each running a different operating system. We use the ‘Isolated Divided Independent Operating Trust’ security system, or IDIOT for short, here at KIF. It prevents hackers from hacking us.

You: “Five devices? Really?

Yes. One device is too easy to compromise, so you’ll need five.

Why not VM’s?

You still need a physical device to connect to the VM’s, right?! Well, we don’t trust VM’s or other VM’s with VM’s, or phones to VM’s either. And we *never* trust one machine by itself. Actually, we take zero trust to a whole new level: We don’t even trust you! Anyhow, the five devices run Windows XP, MacOS, Ubuntu, Redhat, and OS/2 Warp 3. Nobody bothers hacking Warp, so it’s the safest.

Ok. Um, wow. So then what?

You’ll need Cisco AnyConnect on machine 1. Global Protect on machine 2. Pulse VPN on machine 3. Azure Connect VPN on machine 4. And the NetExtender VPN client on machine 5. But machine 1 will also need the the RSA agent, and some crap we’ve been using since 2005. Oh, and you’ll need 3 separate FIDO keys for machines 2, 4, and 5. Then you’ll need Microsoft Authenticator on all of your company phones. Oh! I almost forgot. You’ll also need the BeyondTrust remote access client on machines 1, 3, and 5. And, last but not least: All five will need Citrix.

Phones? Plural? But I already have a personal phone.

We don’t trust personal phones. Ever. You’ll need to carry all work phones with you at all times, 24×7. We require one for each environment, so five (5) in all, unless you’re on-call, then eight (8). You’ll get a separate number and email account for each phone, and the Authenticator activation on each.”

This seems like...”

Overkill? There is no overkill! Not when it comes to security. Do you think the hackers are worried about overkill? We strive to overkill the overkill!

(office tour)

Is this my cube?

We prefer to call them ‘workspaces’. So, yes, that’s your workspace. Except for when you need to connect from machines 3 or 5, then you need to move to either SCIF 1A or 7C, which are over in building 6, 8th floor. If you need those, be sure to bring your retinal scanner. They don’t have one over there.”

Retinal scanner?”

See Jimmy. He’ll get you set up.”

I may need to find you if I have questions or forgot something.”

No worries. If it helps, just write all of it down on a sheet of paper and tape it up on your cube shelf. That’s what the rest of us do. Get settled. Lunch is at noon, and we’re all going to Twin Peaks.

Scripting, Technology

Ridiculous Redactions

Today’s waste of time will focus on using PowerShell to crawl through a bunch of Microsoft Excel workbook files, commonly referred to as “Excel Database Files” by many MBA recipients, to effectively replace one text string pattern with another. A typical scenario might be that the workbook files contain hyperlinks to documents which have been moved to a new location, or maybe someone got fired, and the CEO hates them enough to demand their name be stricken from every workbook file.

For demonstration purposes let’s assume that CEO Jim Useless wants to replace every occurrence of the name of the former Sales Manager, Mike Hunt, with “Sales Manager”. Because, nothing makes a new employee feel valued and welcomed as much as being referred to only by their job title. So, an example source table (top example below) would be modified to look like the example below that.

Let’s drink a whole pot of coffee (or a whole box of Keurig cups) and get started.

Step 1 is setting up some variables to use later on.

[string]$SearchFor = "Mike Hunt"
[string]$ReplaceWith = "Sales Manager"

Step 2 is getting all the .xlsx files within the folder.

[array]$files = Get-ChildItem -Path $Path -Filter "*.xlsx" -ErrorAction Stop

Step 3 is making sure Excel is installed. I was hoping to use the ImportExcel module for this, but it doesn’t provide the functionality for doing this sort of thing yet, so we need to make sure Excel is available to handle the heavy-lifting.

try {
  Write-Verbose "Opening excel application session"
  $excel = New-Object -ComObject Excel.Application
  $excel.Visible = $False
catch {
  Write-Error "Excel could not be found on this cheap-ass computer."

Step 4 is putting on some Latex gloves and facemask to begin crawling through all those stinky workbook files. Keep in mind that the Open() method may need to be modified to suit password-protected files, and other such silliness. Then fetch the worksheets within each workbook to start the search and replace fun.

foreach ($file in $files) {
  $workbook = $excel.Workbooks.Open($file.FullName)
  $worksheets = $workbook.Worksheets
  # add more stuff here to crawl through each worksheet in the workbook - see Step 5

Step 5 is searching for the text you want to replace. This will be shoved into the “add more stuff here” line in Step 4

# insert into while() loop for each workbook
$found = $worksheet.UsedRange.Find($SearchFor)
if ($null -ne $found) {
  $address1 = $found.Address(0,0,1,1)
  $row = $found.Row
  $col = $found.Column
  [string]$textvalue = $worksheet.Cells($row,$col).Formula
  [string]$newvalue = $textvalue.Replace($SearchFor, $ReplaceWith)
  if ($textvalue -ne $newvalue) {
    $worksheet.Cells($row,$col).Formula = $newvalue
  while ($found = $worksheet.UsedRange.FindNext($found)) {
    $address2 = $found.Address(0,0,1,1)
    if ($address1 -eq $address2) { break } # no more matches found on this worksheet.. skip to the next one
    $row = $found.Row
    $col = $found.Column
    [string]$textvalue = $worksheet.Cells($row,$col).Formula
    [string]$newvalue = $textvalue.Replace($SearchFor, $ReplaceWith)
    if ($textvalue -ne $newvalue) {
      $worksheet.Cells($row,$col).Formula = $newvalue
# end of code insertion

The final merged slurry of ingredients should look something like this…

foreach ($file in $files) {
  $workbook = $excel.Workbooks.Open($file.FullName)
  $worksheets = $workbook.Worksheets
  # insert into while() loop for each workbook
  $found = $worksheet.UsedRange.Find($SearchFor)
  if ($null -ne $found) {
    $address1 = $found.Address(0,0,1,1)
    $row = $found.Row
    $col = $found.Column
    [string]$textvalue = $worksheet.Cells($row,$col).Formula
    [string]$newvalue = $textvalue.Replace($SearchFor, $ReplaceWith)
    if ($textvalue -ne $newvalue) {
      $worksheet.Cells($row,$col).Formula = $newvalue
    while ($found = $worksheet.UsedRange.FindNext($found)) {
      $address2 = $found.Address(0,0,1,1)
      if ($address1 -eq $address2) { break } # no more matches found on this worksheet.. skip to the next one
      $row = $found.Row
      $col = $found.Column
      [string]$textvalue = $worksheet.Cells($row,$col).Formula
      [string]$newvalue = $textvalue.Replace($SearchFor, $ReplaceWith)
      if ($textvalue -ne $newvalue) {
        $worksheet.Cells($row,$col).Formula = $newvalue
    } # while
  } # if
} # foreach

Step 6 is, after all of the worksheets have been processed, save and close the workbook file.

if (!$workbook.Saved) { $workbook.Save() }

Step 7 is to close Excel and clean up the spewage it may leave behind. But also to make sure to release those roach-infested COM objects in reverse order (from how they were instantiated)

while ([System.Runtime.InteropServices.Marshal]::ReleaseComObject($worksheet) -gt 0) {}

while ([System.Runtime.InteropServices.Marshal]::ReleaseComObject($worksheets) -gt 0) {}
while ([System.Runtime.InteropServices.Marshal]::ReleaseComObject($workbook) -gt 0) {}
# and if Excel just won't die...
Get-Process 'excel' | Stop-Process -Force

Step 8 is to grab something to eat. Because coding and talking make me hungry.

Step 9 is to assemble all of this into one script – which, if you’re as lazy as I am, can get here. It also contains some additional exception handling sauce and comment seasoning.

I hope you enjoyed this mindless rambling. The code provided at the link above has been tested and works, for me at least, so if it doesn’t work for you, I’ll respond with “that’ll be addressed in the next build.”. Seriously, if you see a problem with the mess above, please share a comment below. Thank you!


business, Scripting, Technology

Replace Excel Data using PowerShell

The full title of this should be, “Replace Excel Data in Workbooks using PowerShell with the ImportExcel Module“, but that’s what the introduction paragraph is for. That should be clear enough, but just in case you are still unsure what this is about: I’m going to demonstrate how to replace hyperlinks in an Excel workbook, using PowerShell. And the best part of this? You don’t even need Excel (or Office) to be installed, in order for this to work. In fact, the better best part is that you don’t even have to do any of this. You could go find something else to do that’s way more fun.

People First Corporate Culture? 6 Steps to Take | LSA Global
(image borrowed from a Google search showing corporate people excited to look at your new spreadsheet)


You’ll need a few things to run this demo:

  • A Windows device (I don’t think ImportExcel will work on a Linux machine, but I don’t know for sure)
  • PowerShell 5.1 or later
  • ImportExcel (PowerShell module)
  • A sample workbook (.xlsx file)
  • No life whatsoever, oops, I mean time. You’ll need a few minutes of nothing better to do

My sample file looks like this (below) and resides on a worksheet named “Sheet1”. Close your eyes and imagine this has thousands of rows of juicy corporate data links, dripping with exciting corporatey information. Way more than you’d want to edit manually, because that would cut into your Facebook time.

CFO Jim Facefister called to say that the intranet URL is changing because “corp” sounds too “corpy” and he prefers “general“, because it’s more general sounding. So he wants the URLs under the “Link” column in this favorite “Excel database” (don’t correct him or he’ll beat you with a golf club), and you want to stay employed long enough to buy that new Ford F150 Lightning your neighbor would envy for at least a few months.

So, you need to change the links to replace “/corp/” items with “/general/” and leave the rest of the contents unchanged. And if it makes the CFO happy, maybe he’ll actually call you Brad instead of Bob, every time he passes you in the hall, even though your name is Susan. But never let a valuable compliment go to waste.

Here’s a view of the source code captured from PowerShell ISE, even though I use Visual Studio Code. I do this because I know it infuriates some of my colleagues, and cheap entertainment is all I can afford right now.

For those who don’t like images, here’s the 100-level, no-exception-handling, poorly formatted, grade D, organic, GMO-free source code…

$XlFile = "\\intranet\corporatystuff\corp\corpdata\corpy-corp-corp\Company Handbook.xlsx"

if (-not(Test-Path $XlFile)) { Write-Warning "File not found: $XlFile"; break }

$xldata = Import-Excel -Path $XlFile -WorksheetName "Sheet1"

$newdata = $xldata | Foreach-Object {
        Title = $_.Title
        Link  = $($_.Link -replace '/corp/', '/general/')

$newdata | Export-Excel -Path $XlFile -WorksheetName "Sheet1" -ClearSheet -AutoSize

Let’s walk through this stuff (or crawl through it, depending on how much you’ve had to drink today). First we define the file (path and name) as $XlFile. Then we check to see if it exists, because your colleagues probably moved or renamed it by the time you recovered from last night’s drinking. Then we import the data using Doug Finke’s super-fantastic ImportExcel module function “Import-Excel”. Then we loop through it (lines 7 to 12) to replace the original “Link” values with the new values. Then we shove it out the door like, well, shoving it out the door. I’m too tired for more analogies right now.

Pausing before line 6, we can see $xldata shows the original content:

Pausing before line 14, we can see $newdata shows the modified content:

So that’s pretty much it. Now you can impress your C-level folks and maybe earn a chance to serve drinks at their next party. Next request they’ll send you is to “fix the internet” because it’s broken again.



Great Moments in IT History


  • “UUEncoding is so cool! You can download an entire JPEG in only 30 minutes!”
  • “Let me tell you, 2400 baud is where it’s at. The Jetson’s are now, baby!”


  • “OMG! you need to dump AOL and join CompuServe! It’s the best thing ever! It’ll be around forever!”
  • “No, Prodigy is where the future is”


  • “OMG! you have to try ColdFusion! It’s the best thing ever! It’s here to stay!”


  • “OMG! the new Blackberry is rocking! There’s nowhere to go from here with this perfect phone!”
  • “The only search engine that will be around in ten years is Excite or AltaVista”
  • “No, Yahoo! will outlast all of them.”


  • “OMG! ASP web pages are the ultimate! And this VB6 just blows everything else away! Last programming language you will EVER need to learn!”
  • “ColdFusion is the future.”


  • “OMG! I just got my Novell certification! Now I have my WordPerfect, FoxPro AND dBase certs! Woo hoo! I’m set for life!”
  • “Holy pig squeeling shit!!!! Did you know that when 2000 arrives all our computers will implode?!!! We have to spend a metric shit-ton of $$$ on preventing this impending doom!!”


  • “OMFG! Have you seen the latest Sun Sparcstations?! Windows NT doesn’t have a future, trust me!”
  • “No way. SGI is where my money is.”


  • “Hey, what happened with all that Y2K stuff?”
  • “Oooh, the Internet market is the future. No way it could crash now!”


  • “Facebook is never going to take off. Dumb idea”
  • “Twitter is never going anywhere either.”


  • “A touch screen phone? Stupidest idea ever! Who would ever NOT want a real keypad?!”
  • “I’m telling you, Real Estate investments simply CANNOT FAIL. I’m advising everyone to buy buy buy!!”


  • “Sun Microsystems is a name that will be around long after Microsoft, Google and Apple are gone”


  • “A ‘ride-sharing’ business is stupid. Who would ever not want to use a taxi or a bus?!”


  • “The Cloud is all a silly fad. It’ll be forgotten in a year or two.”


  • “Letting employees work from home is a bad idea. Nothing will get done. Businesses will collapse immediately just from that alone.”


  • (let’s just skip past that, mmmkay?)


business, humor, Technology

2001 vs 2021 (aka 2020 CU1)


IT planning Meeting: / Project = Document Management

Teams present: IT Architect, PM, InfoSec, Network, Storage, Accounts, Licensing, Customer stakeholders, Customer stakeholder stakeholders, Stakeholders for other stakeholders, Vendor reps handing out business cards and shaking hands, all packed in one conference room.

Preliminary: Storage and Network teams are blaming InfoSec for system issues. InfoSec is blaming Licensing for holding up a PO. Licensing blames the CFO. PM asks them to keep it down.

Vendor: “(blah blah blah blah blah blah) some pointing and hand gestures learned from a sales book.

IT PM:Thank you for the introduction, Bob.”

Vendor: “Uhhh, it’s Doug, actually.”

IT PM: (turns to stakeholders) “So, what features do you need from Electronic Document Management?

Customer: “What does it do?

IT Architect: (talks for 30 minutes, reads directly from PowerPoint slides, attendees coughing, staring at Blackberry phones, texting jokes about TV sitcom episode from previous night, sounds of thumbs clicking on physical keypad, spoons clanking against coffee cups) … “Any questions?

Customer: “We need all of it.

General IT takeaway: (old-timers: dread. younger folks: excitement)


IT Planning Meeting / Project = Cloud Security

Teams present: Cloud Architect, PM, InfoSec, Cloud Networking, Cloud Identity, Licensing, Customer stakeholders, Customer stakeholder stakeholders, Stakeholders for other stakeholders, Vendor reps, everyone on a Teams call.

Preliminary: Azure/AWS/GCS and M365 teams are blaming InfoSec for system issues. InfoSec is blaming Licensing for holding up a PO. PM asks them to keep it down.

Vendor: “(blah blah blah blah blah blah) some more PowerPoint slides and a QR code.

IT PM: “Thanks for introduction, Juan.”

Vendor: “Uhhh, it’s Carlos, actually.”

IT PM: (turns to stakeholders) “So, what features do you need from Cloud Security?

Customer: “What does it do?

Cloud Architect: (talks for 30 minutes, reads directly from PowerPoint slides, attendees not on mute add background sounds of cats, dogs, birds, car horns, kitchen pots and pans, messaging about Netflix/Hulu/YouTube/Amazon/HBO show from previous day, crumpling fast food bags, spoons clanking against coffee cups) someone keeps taking a heavy drag on their vape in front of the mic … “Any questions?

Customer: “We need all of it.

General IT takeaway: (old-timers: dread. younger folks: excitement)


A Query for the Weary

Trying to find SolarWinds Orion stuff in your Configuration Manager environment? Probably not, but in case you are, here’s a query to fire against your SQL site database. If you don’t have permissions to query the database, threaten your DBA with promises to post illicit photos of them from the last company party when they passed out and were never told what really happened to them before waking up. That, or a pizza and some beer, either might help.

For more in-depth inspection, check out the blog post by Matt Dowst at Detecting the SolarWinds Compromise Signals with PowerShell – Catapult Systems

  dbo.v_CombinedDeviceResources AS cdr ON isc.ResourceID = cdr.MachineID
  (isc.NormalizedPublisher LIKE 'SolarWinds%')

Modify to add an additional filter condition, at no extra charge, but only if your parents call before midnight….

  dbo.v_CombinedDeviceResources AS cdr ON isc.ResourceID = cdr.MachineID
  (isc.NormalizedPublisher LIKE 'SolarWinds%') AND
  (isc.NormalizedName LIKE '%Orion%')

And for a limited time, for only 30 cereal box tops, shove it into a PowerShell pipeline using a toilet plunger and some good old foot stomping power with module “dbatools”…

  dbo.v_CombinedDeviceResources AS cdr ON isc.ResourceID = cdr.MachineID
  (isc.NormalizedPublisher LIKE 'SolarWinds%') AND
  (isc.NormalizedName LIKE '%Orion%')"
$evil_little_turd_machines = Invoke-DbaQuery -SqlInstance "mysadsqlserver.loser.nowhere" -Database "CM_WOW" -Query $query


Destroying Orphaned OneDrive sites; See them Driven before you, and Hear the Lamentation of the Losers

Today’s sampling of client cases… I’ve had two unrelated clients with the same issue: their Microsoft Cloud App Security alerts went bonkers over potential PCI sensitive file content in user OneDrive folders, where the user accounts had been deleted LONG ago. How long ago? 2015 to be precise.

Since the user account was obliterated long ago, nothing shows in AzureAD, or SharePoint, etc. And since the ownership is (or was) still tied to the missing account, the URL link in each MCAS alert wouldn’t open for the tenant admin (Global or SharePoint administrator).

So, first we needed to find the orphaned turds in the cloud kitty litter box. The following script will dump the turds into a CSV bag for auditing and review. Then pepper spray each one so the new admin person can access the turds in the folders and destroy them.

This was adapted from the examples in and

param (
  [parameter()][string] $TenantUrl = "",
  [parameter()][string] $CsvFile = ".\contoso_onedrive_users.csv",
  [parameter()][string] $AdminUser = ""

try {
  Write-Host "connecting to AzureAD and SharePoint Online"
  Connect-AzureAD | Out-Null
  Connect-SPOService -Url $TenantUrl | Out-Null

  Write-Host "requesting Azure AD users"
  $adusers = Get-AzureADUser -All $True
  Write-Host "requesting SharePoint OneDrive personal sites"
  $odusers = (Get-SPOSite -IncludePersonalSite $True -Limit All -Filter "url -like ''")

  Write-Host "comparing site owners with Azure AD users"
  $odata = @()
  $odusers | Foreach-Object {
    if ($_.Owner -notin $adusers.UserPrincipalName) {
      if (![string]::IsNullOrEmpty($AdminUser)) {
        Write-Host "adding site collection admin for: $($_.Url)"
        Set-SPOUser -Site $_.Url -LoginName $AdminUser -IsSiteCollectionAdmin $True
      $odata += [pscustomobject]@{
        Url = $_.Url
        Owner = $_.Owner
  if ($odata.Count -gt 0) {
    $odata | Export-Csv -Path $CsvFile -NoTypeInformation 
    Write-Host "$($odata.Count) sites found. Saved to: $CsvFile"
  } else {
    Write-Host "no orphaned sites found"
catch {
  Write-Error $_.Exception.Message 

There are a hundred quadrazillion to the forty-five thousandth power variations for coding this, and this is just one. And more than likely it’s the one instance you will point a finger at and shake your head, thinking “I could’ve done this better”, and you’re right, you could have done this better. Go ahead and pat yourself on the back, I’ll wait…

Ok, so you may have noticed I used a cheap method for controlling the part of the process where it changes ownership on the sites, by checking for the $AdminUser value being blank (or not). Just run it as-is (well, change the defaults for your environment first) to get the OneDrive sites without a corresponding Azure AD user.

Then run it again with a UPN assigned to the $AdminUser parameter to apply ownership changes. Keep in mind that the $AdminUser must have SharePoint Administrator role membership.

And now I need to go for a walk. I forgot how to use my legs.