PowersHELL scripting
Does anyone else in here use powershell as a sysadmin? If you do, do you also feel the agitation and drive to want to throw yourself down a stair case face first through frustration?
I hit a wall a couple of weeks ago due to the deprecation of msonline and with this believed it would be good to move to PS7. What I didn't realise is how much of an absolute jar of jam and mustard mix Powershell is. Core, Desktop, modules and clashing assemblies. Trying to combine ps7 core with AD, AzureAD and having to use Graph for license management - urgh!
I just spent two days writing up an amazing script with functions and arrays to load modules, connect to Entra, get licensing info with nice math, turn that in to a menu, create local AD user and sync, license in EntraID, mailbox enable and sync location, the works.
Then, something changed in a module update. Locally in the OneDrive I had 2.6.1 of graph users and Auth, that was playing well with AzureAD in core, but OS had 2.7.0 of graph. I cleared out my modules and it's broken everything, even on reinstallation.
How in the bloody Hell is Powershell ever supposed to be used and stable when module inconsistencies exist everywhere? I pulled down AzureAD again to find it no longer connects in PowerShell 7 core due to assembly version issues. I use the switch to use Windows Powershell for the AzureAD connection to then have that break the licensing math that was working in a function.
Sigh.
I'm coming from Bash on Linux where shit just works. It works for YEARS! Very few times in my almost 30 year career have I had Bash just decide it doesn't want to work and when it does, it's documented. Powershell does not seem to make sense or be documented well.
Anyway. Rant over. Back to working out what module I need fixed at an EXACT version to make it all work again and to hope MS don't randomly deprecate it again.
EDIT and SOLVED!
I shouldn't even need to update this but after spending a lot of time debugging, it turns out that you cannot call microsoft.graph.users and microsoft.graph.users.actions as they will clash, even though they are part of the same package, you'll get assembly issues. The fix - install the whole MICROSOFT.GRAPH module, all 10k parts of it, but DO NOT IMPORT IT. Now you can import-module microsoft.graph.users and the parts from .actions will also be available without loading. I don't understand why, I'm actually past caring. I'm hoping someone else scouring the internet and hitting the same wall may stumble on this and it'll help them out. Hell, I may even blog about it. Thanks for listening to my misery.
A couple of things to consider. Specifically to your issue, you may want to consider looking into the #Requires keyword. It should make fixing versions of modules easier and I'd recommend it particularly if you're consuming the Az modules (although to your point, it's a web of dozens of interconnected modules and it might take a couple hours to figure out which versions of what module you need to fix).
Alternatively, if you're used to bash, you're probably pretty familiar with curl. Most, if not all, of the use cases you're describing have REST endpoints you can integrate with using Invoke-RestMethod:
It has the added benefit of returning the calls in object format which, fan of pwsh or not, is way easier to work with than what curl returns.
Chances are those PSModules you're leveraging are just using the REST endpoints behind the scenes (many of the modules are auto-generated based on the REST endpoints), so leveraging them directly will both give you more control over the information returned and allow you to fix the backend REST endpoint in your code so you don't run into those version bump issues you're seeing now.
Edit: Additionally, you could also look into PSDepend. It's been around for a while and can help manage dependencies (once you figure out what you need exactly). If you're distributing this to the rest of your team, it'd be a handy tool to get their environment configured properly. Also added a few useful doc links.
One of the primary reasons why I'm not a fan of PowerShell is that even though I like some of the ideas, I just don't see the point of learning it if I don't have to. I can understand that Microsoft really needed to go beyond their DOS batch scripting limitations (for decades before PowerShell came out, even), but I legitimately think they would have done better to just have an official pre-bundled ports of bash/zsh and some of the GNU utilities. That's one of the major reasons why devs tend to love Macs; it all works without having to have a virtualized linux instance like WSL2. Sometimes I wonder how much of Microsoft's decision making comes from not invented here syndrome.
Of course it was. Why embrace a decades-old favored tool and make it work well rather than push your fledgling tech stack (dotnet) harder?
That's the way Microsoft does things, 12 ways to do the same thing, 11 of them deprecated. I ran into a similar issue with msonline the other day when I needed to change an attribute in Azure and couldn't find anything documented, but there were 100's of old threads about how to do it using the old msonline method.
May the 'msonline' module Rest In Peace. This is the cause of my complete NewHybridUser.ps1 rewrite from the ground up.
The opening code comment:
Version History:
2023/10/12 - Rewrite, ground up, FU MS!
Modules used:
$ModuleArray = @(
"AzureAD.Standard.Preview",
"MicrosoftTeams",
"Microsoft.Graph.Users",
"Microsoft.Graph.Authentication",
"ActiveDirectory"
)
I have to use AzureAD.Standard.Preview because that's the only one that seems to be PS7 (core) compatible. This whole script has been a firefight, all 978 lines of it, and it's not complete yet.
Why not use bash scripts on Windows subsytem?
I would love to, but I need to use the PowerShell modules for Active Directory, AzureAD/EntraID and a couple of other things.
Bash doesn't have that ability right now, although I probably could Frankenstein launching pwsh to do bits, kill the session and then create again for the next part from Bash. I may end up having to do that for this script to stop the modules eating themselves in pwsh7 as it is.
Well it's still being developed, and I don't think it solves most of your problems, nushell might be worth looking into.
And from the people I know who are better at this than me, I believe dotnet 8 is coming with some improvement to authentication, which might wind up affecting other systems like powershell/graph (i'm a little unsure on the details because I mostly code in C#/F# and make apps so coming from a different perspective).
I would love it if that would be the real reason, but like all MS products, they keep changing things to keep us on our toes when we really want to just be flat footed.
If .NET 8 is just around the corner and solves half these problems, that would be amazing. It's just looking like MS is forcing local on-prem in Windows Desktop (v5) and allowing only certain things in Core (v7+) and they haven't worked out that people run in both environments and not necessarily on Windows.
This started out as a Windows script and I thought to move to Core to solve the cross platform problem, to discover that AD module, WinRM (invoke-command) and the alike are ONLY available to Windows systems.
I've specifically avoided putting myself in a position to do so, for pretty much all the reasons you listed.
But if I were gonna be tasked with doing so tomorrow, I'd give a good look at Ansible's Windows modules. Probably still have to use Powershell, depending on the tasks needed, but perhaps using Ansible as the glue may help smooth over some of those problems.
I don't have an answer for you since I don't work with Windows at all, but it does always surprise me to see people love on Powershell. We have people here who are absolutely passionate about it. I just didn't expect that from a Microsoft CLI tool.
PowerShell is very powerful when it comes to managing Windows and anywhere else it has modules (AWS is another one where I use PowerShell frequently instead of the AWS CLI).
A lot of that comes down to the fact that it's not just text in PowerShell, it uses objects and most things in it are objects which makes item easier to work with and completely removes the need to use things like awk to return a specific column out of returned text (as a simple example). Outside of objects, PowerShell has built in functions to manipulate text and perform math equations without needing to rely on additional tools.
It's also very helpful for managing Active Directory - any AD Admins not using PowerShell to manage it are not really up for the task of managing it - it's easy to update 100s of user, computer or group objects that would take hours to do manually.
OP's frustration with the Graph and MSOnline modules are 100% valid though - Microsoft is not documenting those well enough at all let alone including examples, and along with the Teams module they're frequently being updating without correponding documentation. It's generally a bad idea to update those modules without testing on a non-prod system first.
OP feels PowerShell 'doesn't make sense' compared to Bash since that's what they're more familiar and experienced with; I wish Bash was more like PowerShell when I'm managing Linux systems since I'm more comfortable with it than I am with Bash. (PowerShell can be installed on Linux but I'm certainly not about to install it on production servers).
I'm completely onboard with your whole comment here. I'm far from a newbie with Powershell but there's just a massive rabbit hole you can fall down.
I've just taken the very old new user script and rebuilt it using functions and arrays to simplify how it's written, added the tries and catches for any failures, etc. Powershell is very extensible but that is where the problems come in. Those modules change frequently and whe you least expect it. I do not force module updates in working scripts, but on a new workstation running the script would pull in the latest modules, I suppose that's on me for not specifically placing in the wanted module version. The true issue for replacing the script was that msonline deprecated and killed off a working module and the replacement was completely different. If you change the server side the client side needs to change and it was forced on us. That's what's more annoying than anything, when stuff works and then stops because the vendor changes/disables it and it's stuff that is in production.
Heads up if you do go and play on Bash again, it does have text manipulation and math built in now.
Yeah, I had to rebuild the new user script for my company, from the previous one using so many poor practices (like instead of defining functions, they just repeated code for several things many times over).
The new version has been running solidly for over a year now without any changes.
I'm still learning Bash - switched out my personal computer to OpenSUSE to avoid Windows 11. Just figuring out Bash arrays this morning. That's great to hear about text manipulation and math being built in, I haven't seen that yet but it's great!
My assumption is because it's a shell that actually goes beyond the "everything is a text stream" model of most unix shells*. Being able to have actual structured objects in my shell scripts makes things so much easier. Pair that up with the fact that I can import (or write!) modules written in C# and it feels like there's a much smaller gap between the power of writing a full program for a task vs writing a shell script.
*Nushell is out there, but it baffles me that every article or blogpost I see about it completely ignores the fully-in-use Powershell when talking about "reinventing the shell"
Personally, I really like PowerShell. I like it enough that it is my default shell for MacOS and Linux (WSL) installs as well. There are some modules which are Windows only, and that can be frustrating at times, but the core language is something I can use across different Operating Systems and I can share my $PROFILE. That's very useful for a lot of situations. I have additional scripts I use to encapsulate specific environment needs, but most of setting up my system can be used independent of the platform.