This post is part 4 in an open ended series on PowerShell for IT Pros. It is intended to be a framework to learn from, not an exhaustive study guide. Consider it a survey in what's possible, not a master's class in all things PowerShell. You can find the first post in the series here.
It’s taking everything in me right now to not break into School House Rock’s “Conjunction Junction,” but unfortunately this post is about functions, not conjunctions.
A function in PowerShell is a block of code that you can call from within a script. Parameters can be passed into a function, and it can be called any number of times. I typically write functions for one of two different purposes: either I need to run the same block of code multiple times in the same script, or I plan on reusing the code block in multiple scripts.
Functions are essentially scripts that are included as part of a larger script. You will often hear experienced scripters talking about building a toolbox. For many of us, that is a collection of scripts and functions that we reuse regularly. For example, I have several different functions that I use as source material for other scripting project. I have a logging function, a function that writes an exit code to the registry, and functions to build PowerShell objects. Some of these, like the logging and exit code functions, can be plugged into a script with almost no changes. The PS Object function usually needs to be customized based on the script I am work on. Whether a function needs to be edited or can be plugged directly into another script – they all save time and assist with common tasks.
A function can be as simple as a single cmdlet, or as complex as many scripts. Generally, I like to keep my functions simple. If it needs dozens of lines, it may be best broken out into small functions. Conversely, if a task can be handled in one or two cmdlets, it may be harder to justify handling it in a function. In this post we are going to explore a relatively simple function, building off the Connect-AzureAD cmdlet from my previous post.
This is the third post in my series on Practical PowerShell for the IT Pro. You can find the first post here.
(Note: any PowerShell cmdlets shown in a screenshot will be included in a block that can be copied and pasted later in the post.)
It has been a long time since my last post on Practical PowerShell for the IT pro. A lot of things have changed in the world. The last few weeks have been a bit of a whirlwind. I would apologize for not making this post sooner, but I think it’s good for us to acknowledge the need to unwind. Focusing on writing has been hard, but now that I have adjusted to this new normal, I am ready to get back into the groove. For many of us, our jobs are unlikely to return the the “old normal.” Covid-19 will prove to be a world changing event, and the impact will be felt for years. Many of us have had to shift our approach from incremental change to rapid workplace modernization, and we have been asked to do it virtually overnight.
As we modernize, we will find a greater need to rely on PowerShell for managing users, devices, and licenses in the cloud. While the Administrative consoles give us access to most functionality, some controls aren’t exposed in the UI and many batch jobs or repetitive tasks can be completed more efficiently through a script. I hope that this blog series acts as a jumping off point for administrators that want to get started with PowerShell for systems administration.
In the last Practical PowerShell post I walked you through how to find the cmdlets you need to return an Azure AD user object. To complete that task, we had to install the Azure AD module, connect to Azure AD, then run the Get-AzureADUser cmdlet to return the user object. We ran each of these cmdlets separately to accomplish our goal. We can now use those cmdlets to create a basic script.
In my most recent blog post I discussed how we, as IT pros in the modern workplace, can respond to empower our end users to be more effective while working remote. Most of us are facing the monumental task of identifying the best solutions for our workers and getting them implemented quickly and efficiently in the midst of this crisis.
I am going to use this post to keep track of resources I have found to be helpful. Feel free to share this post and send me any links that you have found to be useful. If you share a link with me, please include a link to your Twitter or website so I can give you credit for sharing content!
I haven’t been on my game this week. If we’re honest, I think a lot of us have been a little bit off. Covid-19 has been looming for months, yet somehow we failed to anticipate how the virus would impact our daily lives. In North America, we watched as the pandemic exploded first in Southeast Asia then quickly moved across Europe. Most of us expected we would see it here, but I think that in our hubris we never expected a major disruption to business and society. Our culture isn’t one to slow down. We tend to believe we are above the fray and can weather any storm.
It’s not a secret that I claim to be a technology disruptor. As IT pros working with Microsoft 365, we want to change the way that our organizations work. Our goal is to empower our end users. Change typically takes time and being a disruptor in technology is as much about being a salesman as it is about being a skilled technologist. We are used to pitching new solutions, talking about the benefits of new technology, and working to build allies in our organizations. Workplace disruption is typically a slow and methodical process. Even if we know the value these tools have it can take time to deploy them because of the impact they would have on end users, infrastructure requirements, and workplace culture that isn’t always ready for change.
Six months ago, we couldn’t have predicted the impact a global pandemic would have on the workplace. What was once unthinkable is now our reality. The disruptors have now joined the ranks of the disrupted. Pitching a modern workplace was always about creating a nirvana that would empower workers to work from any location, on any device with total security and unlimited freedom. It sounds great on paper, but a lot of organizations weren’t ready to adopt remote work models, so change was incremental. Many of the modern workplace tools were considered ‘nice-to-haves,’ but not essential for continuing day to day operations. Our roadmaps have been filled with bucket list items from the Microsoft 365 suite of tools, but for most of us those tools aren’t deployed yet. However, we can’t unmake decisions that were made six months ago. It would be easy to say, “If we had deployed Teams globally six months ago, we wouldn’t be in this situation,” or, “If we had only decided to set up a Cloud management gateway or co-manage our Windows 10 devices we could address this issue on PCs.”
Practical PowerShell Part 2: Perfection not needed - finding cmdlets, interpreting errors, and returning an object
This is the second part in my series on Practical Powershell for the IT Pro looking to get started with PowerShell. You can find the first post here.
Welcome back! You have found the second post in my series on Practical PowerShell, perhaps this series would be more aptly titled, “How to stop worrying and love the script.” This is a series that is dedicated to the IT pro that wants to learn PowerShell but doesn’t really know where to start. There are more comprehensive resources available, but this is meant to be a logical introduction on PowerShell. The first post was meant to be a basic introduction. The rest of the series will follow a common theme. Each post builds on the lessons taught in the one before it. We are going to start with a basic concept that can be accomplished in a few cmdlets, and eventually build a utility that started with these first few steps.
The most important lesson in learning PowerShell is simple: No one expects you to know everything.
Let that sink in. You don’t have to be perfect. In fact, most of us who use PowerShell regularly learned through trial and error (mostly error). The most important tool in a proficient PowerShell toolkit is a search engine. It helps you find cmdlets, troubleshoot errors, and find scripts other IT Pros have created that we can use as is or repurpose to fit our needs.
This series would be really short if I just presented a challenge and used Bing to find a pre-canned script that solved all of our problems. It may be the right answer for a lot of the issues we run into daily, but it doesn’t help us to build a bigger toolbox. My goal is to point you in the right direction to begin writing your own scripts, build basic utilities, and become more confident in your own abilities. This is a modern endpoint management blog, so I want to make sure we build skills that are relevant in a cloud-first endpoint management world. Through this blog series we will build a utility to help use manage users, devices, and licenses in Azure AD through PowerShell.
Welcome! This blog series will examine how traditional IT team dynamics fit in the Modern Workplace, and whether we are prepared to manage and deploy solutions effectively in a cloud-first world.
Sometimes it’s best to sit and listen.
In a recent meeting I sat back as the attendees “discussed” their vision for addressing a specific challenge. I was a late invitee, and it was clear to me that the brief overview of the agenda I was given didn’t match the meeting’s intent.
There was a business challenge that needed to be addressed, but the actual intent of the meeting was much broader. It turned into a round table discussion about many of the challenges that we face and how we can overcome them.
I’m not known for keeping quiet. Typically, I jump into a conversation early and make sure my opinions are known. In this meeting I chose to sit back and listen. The perspective I gained was invaluable. Once we had exchanged the typical pleasantries, one colleague led with a question. She had barely completed her question when another team member offered a solution. Unfortunately, the “solution” being offered was little more than a defense of the status quo.
The back and forth continued and I quickly realized that while everyone was in the same discussion, both sides were talking about something different. One team member was looking for a new, modern solution to a problem, while the other team member only saw challenges – the costs involved, man hours, lack of expertise, and a litany of other issues were brought up. No one bothered to ask if it was worth it – or even worse, if there was a workable solution available that we could easily leverage.
As technologists on the forefront of workplace modernization we are by nature disrupters. We want to empower our users to do more, but it can be difficult to share our vision and gain traction on deploying modern solutions. Our teams don’t always share a unified vision, and when we do, we frequently talk past each other.
This post is the first in a series on PowerShell scripting for the SysAdmin who doesn't know where to begin. This series is designed to move quickly from PowerShell basics to advanced scripting techniques. It is meant as a guide, not a standalone resource.
“So, where do I begin?”
You really thought I was going to start this post by shattering the third wall and asking a self-referential question? I wasn’t.
I was reading your mind.
There are two common refrains I have heard from people about PowerShell. The first is simple, “I want to learn PowerShell.” Support team members and young systems administrators know that the best way to learn a new role and grow their career is by learning a new skillset. PowerShell is becoming one of the most important and empowering skills that an aspiring administrator or engineer can learn.
The other statement is always tinged with a bit of regret, “I really wish I would have learned PowerShell sooner.” For any number of reasons many seasoned IT Pros have waited to learn PowerShell. It may not have been relevant to the systems they worked on, perhaps they had a preferred scripting language, or could complete most tasks through a GUI. In a cloud first world development cycles have been shortened and not every function finds its way into a GUI. Most systems administrators eventually find a need for PowerShell, and in the end, regret not using it sooner.
There’s one underlying principle in both cases – people don’t know where to begin with PowerShell. It’s a massive topic. There are countless resources available – from user groups, to video series, tutorials, and books. I will include a few links to some of those tools at the bottom, and if anyone has other links they would like to share I would be happy to add them. If you have the time to sit down and digest in-depth content on PowerShell I would highly recommend diving into some of the more advanced content written by experts in our field.
I wouldn’t consider myself an expert in PowerShell. I’m an IT Pro who had a need, and like many other IT Pros I didn’t know where to begin. I began my systems administration journey in a role that required me to learn WiseScript and AutoIT. I had a basic understanding of VBScript and .Net. PowerShell, while similar, is also a completely different tool. If you understand the basic concepts of scripting, PowerShell is easy to pick up, but the syntax is different and can be a tripping point for more experienced script writers.
Managing localization settings in a Microsoft Endpoint Manager CM Task Sequence with native functionality
This blog post is the completion of a series on managing language and input settings in a Microsoft Endpoint Manager task sequence. Previous posts covered using UI++ to set language values and using WimWitch to inject language packs in a Windows 10 WIM.
MEMCM Native Task Sequence Language Behavior
In previous posts I discussed my process for setting native language and keyboard settings using UI++ (from @JasonSandys) and injecting language packs into a Windows 10 WIM using WimWitch (from @TheNotoriousDRR). I decided on those tools based on my needs, but those posts overlooked important behavior that was introduced in Microsoft Endpoint Manager 1910.
Prior to 1910 there was not a native setting in the task sequence for setting UI language and input settings. 1910 introduced new settings on the Apply Windows Settings task sequence step that allow you to select from a list of native language packs and input settings. These still require either a WIM with language packs injected or installing the language packs dynamically during the task sequence, but they do make managing simple language settings simple. They are not perfect and don’t cover every possible option, but the native MEMCM functionality can be ideal in some scenarios.
This post will cover 3 native scenarios:
1) Setting the language and UI settings for a single language scenario using Apply Windows Settings
2) Dynamically setting language and UI settings with optional conditions and a Collection Variable
3) Using Collection Variables and a custom unattend.xml to set language options
Each one of these scenarios has advantages and disadvantages.
This post is a follow up to my post on customizing language settings in a Microsoft Endpoint Manager task sequence using UI++ and a custom unattend.xml file. I will continue this series in a third post that discusses the native functionality in MEMCM 1910 and later.
In a post a few weeks ago I discussed my process for managing languages in a Microsoft Endpoint Manager task sequence. That post went in depth on using UI++ and a custom unattend.xml file to allow a technician to select a primary language and alternate keyboard layout during OS deployment. That process requires having a Windows image that already has language packs and features on demand injected. I briefly discussed my process for creating a WIM file.
That post mentioned that I initially created a WIM file with WimWitch from Donna Ryan (@theNotoriousDRR). I would create the image, run my own script to inject the languages and features on demand, and then update the WIM using WimWitch. At that point WimWitch did not support language pack injection. Donna had mentioned that language injection support was coming – but I didn’t know when it would be available. Shortly after posting my last post she released the 1.4 beta release of WimWitch which previewed the language pack injection! WimWitch version 1.4.1 is now available. The language support is excellent!
I was originally going to write about my own script, but Donna hit this process out of the park. With each new version, WimWitch adds amazing new features that could only be designed by someone who is familiar with MEMCM, the imaging process, and has an excellent eye for detail. If you aren’t already using WimWitch, take the time to explore all of the features that are currently available – it’s a great tool and new features are being added regularly!
Are we even speaking the same language?
We spend a lot of time writing user-facing documentation, only to have users ask us questions that we already answered in our communications to them. It seems like no one is reading any of what we wrote. Users who need clear step-by-step instructions still contact the help desk, and the users who “get it” stop us in the hall and ask us questions we covered in the documentation.
We hear the term “digital native” being thrown around a lot lately. It was first coined in 2001 by Marc Prensky, in a paper titled, “Digital Natives, Digital Immigrants.” Prensky was an educator. His paper focused on the different languages and learning styles of people raised in a world of technology, the digital natives, and people who grew up before technology became so ubiquitous, or “digital immigrants.” Prensky’s paper was targeted at educators, but for IT pros, his message carries several important lessons. He best sums up his own argument in one line: “Our students have changed radically. Today’s students are no longer the people our educational system was designed to teach.”
The biggest different between these two groups is how they engage with technology. Digital natives speak the language of a digital world. It has shaped how younger generations learn and engage with the world around them.
Traditional education was very methodical. Lessons were carefully planned and calculated to teach us important lessons through repetition and rote memorization. Lessons were singularly focused. Subjects were explored separately, and students were expected to give their undivided attention to the lessons of the day. It was far from perfect but designed to help the highest number of students succeed.
My name is Sean Bulger. I am an IT Pro that has worked in the Modern Endpoint Management work space since 2015. I have worked in various environment, ranging from mature enterprise all the way down to a fledgling IT organization looking to find their way in a cloud first world. Before rejoining the technology field in 2014 I had a wide range of careers - from plumber to paramedic - that have helped to shape my perspective on the world.