Table of contents
- What is Windows PowerShell
- Key Features
- PowerShell’s origin story
- Common uses of Windows PowerShell
- Management and automation of Azure services (e.g. Entra, Virtual machines or networking)
- On-premise infrastructure management (e.g. Active Directory, Group policy, DNS)
- Configuration Management and IAS (e.g. PowerShell DSC )
- Application packaging and deployment in ConfigMgr
- Searching the Windows event log
- Managing WSUS
- Installing Windows updates
- Remote device management
- Best Practices
- Things to stop doing
- Things you wish you knew about sooner
- Conclusion
What is Windows PowerShell
Windows PowerShell is a task automation framework and a command-line shell developed by Microsoft.
Windows PowerShell is built on top of the .NET Framework and supports cmdlets (pronounced “command-lets”), which are small, focused scripts or tools that perform a specific task. These cmdlets can be combined and reused to create more complex PowerShell scripts and automation workflows.
Key Features
Command-line Shell
PowerShell’s command-line shell is a versatile interface enabling administrators to perform administrative tasks like interacting with cloud services like Azure and on-premise services like Active Directory, modifying server configuration and automating daily tasks. PowerShell’s command-line has a very strong feature set, including object-oriented output, tab completion, scripting, command history as well as accepting and returning .NET objects.
Scripting language
PowerShell is widely used by administrators to automate the management of Windows systems. However, it can also be used to automate the deployment of new devices, as well as test, and deploy code. PowerShell scripts can do something as simple restarting a service, or creating an active directory group, or it could be extended through the use of functions, classes and modules to automate the deployment and maintenance of infrastructure.
Integration with .NET Framework
PowerShell’s integration with .NET framework allows administrators to easily incorporate .NET functionality into their scripts. Providing them direct access to .NET classes, making it very easy to utilize a wide range of libraries and capabilities, like creating and manipulating .NET objects, invoking .NET methods, loading external .NET assemblies and creating graphical user interfaces through .NET’s Windows Presentation Foundation(WPF) or Windows Forms (WinForms), allowing expansion beyond traditional command-line tasks.
Remote Management
PowerShell’s remote management functionality allows administrators to execute PowerShell commands and scripts on remote devices using technologies like Windows Management Instrumentation (WMI) and PowerShell Remoting, allowing them to gather information, monitor and make configuration changes and provide centralized administration of their environment.
Cmdlets
PowerShell cmdlets, or commandlets, are specialized commands created for system administration and automation tasks. These tend to follow a naming convention of verb-noun (e.g. Get-Process, or New-Item). Cmdlets perform very specific operations, and their output is generally structured as objects allowing them to be easily combined using pipelines to chain multiple commands together.
Script Execution Policies
PowerShell script execution policies are a security feature designed to allow the control of the conditions under which a script can be run, helping to prevent unintended execution of potentially harmful or malicious scripts. By default PowerShell enforces a fairly restrictive policy, however, users can adjust these policies based on their security requirements.
PowerShell’s origin story
Back in 2002, Before Windows PowerShell was “PowerShell” it was known as “Monad”. This name came from Jeffrey Snover’s realization that Windows needed a good command-line interface and scripting language, similar to Linux, so he coined the Monad Manifesto
Development started in 2003, and v1 was released in 2006. During development it remained “Monad” but upon release the name “PowerShell” was used.
Over the years since then, PowerShell has had many releases, each adding more and more functionality
Monad (2003): The development of PowerShell began in 2003 under the codename “Monad.”
PowerShell 1.0 (2006): v1.0 was included as part of Windows Management Framework, This was when the concept of cmdlets was first introduced.
PowerShell 2.0 (2009): v2.0 was released as part of Windows 7 and Windows Server 2008r2. This release first introduced the Integrated Scripting Environment (ISE), a GUI for creating and running scripts.
PowerShell 3.0 (2012): v3.0 was released as part of Windows 8 and Windows Server 2012. Features such as workflow capabilities, improved remoting, and new cmdlets for managing features like networking and storage were included.
PowerShell 4.0 (2013): Released with Windows 8.1 and Windows Server 2012 R2. With this version we saw enhancements to Desired State Configuration (DSC) for declarative configuration management. New cmdlets for web services and networking were also introduced.
PowerShell 5.0 (2014): v5.0 was initially released with Windows 10 and Windows Server 2016. The PowerShellGet module was included in v5.0, which allowed for the managing PowerShell modules. Script debugging capabilities were improved, and classes were introduced.
PowerShell Core (2016): Microsoft expanded PowerShell’s reach beyond Windows to Linux and macOS with PowerShell Core. PowerShell Core is an open-source, cross-platform version of PowerShell that can run on various operating systems.
PowerShell 7 (2020): PowerShell 7 is the latest major version. Building on the foundation of PowerShell Core, PowerShell 7 brings some additional features like improved performance, and compatibility with Windows PowerShell 5.1.
Common uses of Windows PowerShell
This list is far from extensive, and common PowerShell uses will be very subjective but these are some of the common uses I found on the PowerShell subreddit and through some internal discussion.
We won’t really go into any of these in huge detail
Management and automation of Azure services (e.g. Entra, Virtual machines or networking)
Managing Azure services is possible through the use of Azure PowerShell. Azure PowerShell is a CLI built on top of the Windows PowerShell framework. It provides a specific set of cmdlets designed for interacting with Azure services and resources including provisioning and managing VMs, configuring network, deploying applications and managing Entra ID.
On-premise infrastructure management (e.g. Active Directory, Group policy, DNS)
Through the use of PowerShell commands that are included in additional modules, Administrators can manage on-premise infrastructure such as Active Directory, Group Policy objects, DNS records and Certificate Services.
Configuration Management and IAS (e.g. PowerShell DSC)
PowerShell Desired state configuration (DSC) is a framework that allows for a consistent and repeatable definition of system configurations. Integrated into PowerShell, DSC gives administrators the ability to specify the desired state of a device using simple scripts known as DSC configurations rather than manually carrying out the step-by-step procedures to achieve the same state.
Application packaging and deployment in ConfigMgr
Administrators can leverage Windows PowerShell to streamilne the creation of ConfigMgr applications by capturing installation configurations and configuring deployment parameters. Additionally, PowerShell allows administrators to automate the deployment of their applications by managing distribution of content, creating deployments and monitoring deployment statuses.
Create applications – Configuration Manager | Microsoft Learn
Deploy applications – Configuration Manager | Microsoft Learn
I would try to explain PSADT to you in my own words, but it’s own tag line does it perfectly!
Additionally, utilizing PowerShell to work with your application packages lets you work with technologies like PowerShell App Deployment Toolkit (PSADT).
PSAppDeployToolkit is a versatile solution that streamlines and standardizes the process of software deployment, making it easier than ever to manage your IT environment. It has a comprehensive set of features, such as dynamic logging, user interaction capabilities, and customizable functionality.
If you are interested in reading more about PSADT, check out their website PSAppDeployToolkit.
Searching the Windows event log
Being able to use PowerShell to interact with the Windows event log allows administrators a versatile and efficient way of monitoring and managing system events. PowerShell cmdlets such as Get-EventLog and Get-WinEvent allow for the retrieval of useful event data, filtering on specific criteria and analysis of logs for troubleshooting and auditing.
Managing WSUS
Utilizing PowerShell commands to interact with Windows Server Update Services (WSUS) allows for the managing of Windows updates within an organization in a more streamlined and automated manner.
Note: To interact with WSUS via PowerShell, you will need to install the WSUS tools, which can be done relatively easily.
Windows 10 & 11 – Add-WindowsCapability -Online -Name Rsat.WSUS.Tools~~~~0.0.1.0
Windows Server – Install-WindowsFeature UpdateServices-API
Cmdlets such as Get-WsusUpdate, Approve-WsusUpdate and Invoke-WsusServerCleanup can be used to query, approve and optimize the update process. Administrators can also automate the process of routine tasks, like synchronizing update metadata and the approval of patches using a PowerShell script.
With that being said, the WSUS cmdlets can be very inefficient and not fun to work with, however, you can also interact with the WSUS API using PowerShell, which is a much better experience.
Microsoft.UpdateServices.Administration Namespace | Microsoft Learn
Installing Windows updates
Admins are able to use Windows PowerShell to automate the download and installation of Windows updates using custom PowerShell scripting. Rather than explain it here, I would recommend checking out this blog post by Adam Cook where he goes into great detail on the subject of using PowerShell to install Windows updates.
Remote device management
Being able to remotely manage your devices is critical, especially if your devices are located in different parts of the country, or even the world. Using PowerShell commands like Invoke-Command and Enter-PSSession to establish remote connections and execute commands on devices helps Administrators query devices, troubleshoot problems and in some situations remediate them as well. Additionally, modules such as PSRemoting allow for the configuration and management of remote sessions, enabling admins to carry out tasks such as software installations, configuration changes and troubleshooting across multiple devices.
Best Practices
There are absolutely more best practices for PowerShell than I can fit in this blog post, but here are 5 that I think are the best ones to mention!
Comment your code!
Writing PowerShell scripts with clear comments are a must have when writing a script that someone else may eventually use in the future.
This ensures that anyone reading it has a better chance of understanding what the script does, and allows then to potentially contribute to the script.
Most importantly, it helps you! For example, If you come back to that script in 6 months time and you forget what you created a specific PowerShell function for.
Comments do not need to be full paragraphs, more often than not a single concise line can sum something up just as well.
Example
In this example we can see 3 comments, “Import the ConfigurationManager.psd1 module”, “Connect to the site’s drive if it is not already present” and “Set the current location to be the side code”
function Set-ConfigMgrSiteDrive { [OutputType([System.Void])] param ( [Parameter(Mandatory)] [String] $SiteCode, [Parameter(Mandatory)] [String] $ProviderMachineName ) try { # Import the ConfigurationManager.psd1 module if ($null -eq (Get-Module ConfigurationManager)) { Import-Module "$($ENV:SMS_ADMIN_UI_PATH)..ConfigurationManager.psd1" } # Connect to the site's drive if it is not already present if ($null -eq (Get-PSDrive -Name $SiteCode -PSProvider CMSite -ErrorAction SilentlyContinue)) { New-PSDrive -Name $SiteCode -PSProvider CMSite -Root $ProviderMachineName } # Set the current location to be the site code. Push-Location Set-Location "$($SiteCode):" } catch { throw $_.Exception.Message } }
Use comment-based help in your script headers
Adding a header to your PowerShell scripts lets you add additional useful information like
- A synopsis and description of your script
- Notes
- Examples
- Links to documentation
A header within your script allows someone who is unfamiliar with your script to understand more about how to use it, what it does and where to go for more help.
The Microsoft documentation on comment-based help can be found here, for more information! – about Comment Based Help – PowerShell | Microsoft Learn
Example
In this example, We can see that a synopsis, description, parameters, examples and notes are all defined.
Example taken from here – https://github.com/PatchMyPCTeam/CustomerTroubleshooting/blob/Release/PowerShell/Export-PMPCInstalledSoftware.ps1
<# .SYNOPSIS Get installed software from the local computer's registry and export to .csv .DESCRIPTION Get installed software from the local computer's registry and export to .csv .PARAMETER ExportCsvPath Specifies the desired path to the CSV to export. This defaults to the current directory with a file name of 'PMPC-Uninstall-Hive-Export.csv' .EXAMPLE Export-PMPCInstalledSoftware -ExportCsvPath 'C:tempPMPC-Export.csv' Exports all the uninstall hives to a CSV file named 'C:tempPMPC-Export.csv' .EXAMPLE Export-PMPCInstalledSoftware Exports all the uninstall hives to a CSV file named 'PMPC-Uninstall-Hive-Export.csv' in the directory where the function was ran .NOTES ################# DISCLAIMER ################# Patch My PC provides scripts, macro, and other code examples for illustration only, without warranty either expressed or implied, including but not limited to the implied warranties of merchantability and/or fitness for a particular purpose. This script is provided 'AS IS' and Patch My PC does not guarantee that the following script, macro, or code can or should be used in any situation or that operation of the code will be error-free. #>
If we query this script using Get-Help we see the following output, which shows the name, synopsis, syntax and related links, but note that there are no examples listed even though we defined them.
What we do see is some additional remarks at the end telling us we we can use Get-Help -Full, -Detailed, or -Examples.
Use clear and concisely named variables
While it may seem quicker and easier to use shorthand variables like $i to make your script shorter, or smaller, when you haven’t updated that script in 6 months or a colleague tries to edit it, $i causes more confusion than anything.
When creating variables, you ideally want to name them after what they are being used for, or what they represent. For example $DeviceNames clearly suggests that it is used to store names of devices.
Additionally, when creating variables the best practice is to stick to alphanumeric characters and the underscore (_) character. Including things like whitespace or other special characters makes variables more difficult to use.
Some additional information taken from the Microsoft Documentation
- Alphanumeric variable names can contain these characters:
- Unicode characters from these categories: Lu, Ll, Lt, Lm, Lo, or Nd.
- Underscore (_) character.
- Question mark (?) character.
- The following list contains the Unicode category descriptions. For more information, see UnicodeCategory.
- Lu – UppercaseLetter
- Ll – LowercaseLetter
- Lt – TitlecaseLetter
- Lm – ModifierLetter
- Lo – OtherLetter
- Nd – DecimalDigitNumber
Tabs, not spaces!
Like the other best practices we’ve discussed so far, consistent code indentation really helps with your PowerShell scripts readability. To help keep things as consistent as possible, It’s always recommend to use tab to indent your line, rather than repeatedly pressing the space bar.
- Note: While this is generally recommended, different PowerShell text editors can interpret indentations like tabs differently. If you create your PowerShell scripts in VSCode then move to NotePad++, it’s worth double checking that your indentation is still correct.
Example
- Adding parameters to a param block – about Functions Advanced Parameters – PowerShell | Microsoft Learn
- Example taken from here, https://github.com/PatchMyPCTeam/CustomerTroubleshooting/blob/Release/PowerShell/Export-PMPCInstalledSoftware.ps1
- Adding content to a script block – about Script Blocks – PowerShell | Microsoft Learn
- Nested statements (If, Do While, ForEach)
Pick a capitalization convention and stick to it!
While PowerShell is not case sensitive, it is recommended to follow a capitalization convention to ensure your code is easy to read.
- Microsoft’s documentation on capitalization conventions lists 2 appropriate ways to capitalize identifiers in your scripts.
- PascalCasing
- PascalCasing is used for all identifiers, with the exception of parameter names. Capitalize the first character of each word (including all acronyms over two letters in length).
- e.g. ValidatePattern
- e.g PSChildName
- An exception is made for two-letter acronyms, where both letters are capitalized.
- e.g. IOStream
- PascalCasing is used for all identifiers, with the exception of parameter names. Capitalize the first character of each word (including all acronyms over two letters in length).
- camelCasing
- camelCasing is used only for parameter names. Capitalize the first character of each word, except the first.
- e.g. $employeeName
- e.g. $temperature
- Unlike PascalCasing, two-letter acronyms that begin a camel-cased identifier are lowercase
- e.g. ioStream
- camelCasing is used only for parameter names. Capitalize the first character of each word, except the first.
- PascalCasing
- Do use PascalCasing for all public member, type, and namespace names consisting of multiple words
- Do use camelCasing for parameter names.
- PowerShell keywords, just to confuse matters more!
- PowerShell keywords are written in lowercase
- e.g. begin, foreach, for, exit, if, return.
- PowerShell keywords are written in lowercase
- PowerShell keywords, just to confuse matters more!
- Do not capitalize each word in close-form compound words
- NOTE: Languages that can run on the CLR are not required to support case-sensitivity, although some do. Even if your language supports it, other languages that might access your framework do not. Any APIs that are externally accessible, therefore, cannot rely on case alone to distinguish between two names in the same context.
- Do not assume that all languages are case sensitive.
- At the end of the day PowerShell is not case-sensitive, but be nice to whoever may read your script in the future 🙂
Things to stop doing
Overcomplicating things
While I’m almost definitely guilty of this, more does not always mean better. Keeping it simple is absolutely recommended where possible. Keep your scripts as streamlined and simple as possible, where possible, try to avoid making your script jump around, but instead keep it linear so that it is readable from top to bottom.
PowerShell functions are a fantastic example of where scripts can get unnecessarily complicated.
You can achieve the same result with a simple script, or with a PowerShell function, both of which have their place. Functions are great when writing reusable code, but for single-use or quick snippets, keep it simple!
Example
Stop disabling PowerShell in your environment
Instead, configure it correctly.
Now this is a rabbit hole that I’m not going to go too deep into, however, while Windows PowerShell is a very powerful tool, and can absolutely be used malicious, it is equally as powerful at analyzing issues, incident response, automating security tasks as well as basic day to day administrative tasks across your estate.
An excerpt from the NSA, CISA, NZ NCSC and NCSC-UK on keeping PowerShell.
Cybersecurity authorities from the United States, New Zealand, and the United Kingdom recommend proper configuration and monitoring of PowerShell, as opposed to removing or disabling PowerShell entirely. This will provide benefits from the security capabilities PowerShell can enable while reducing the likelihood of malicious actors using it undetected after gaining access into victim networks.
Some straight forward recommendations on securing PowerShell
- Enable and configure Script Execution
- Configuring the Windows PowerShell execution policy within your estate, including both client endpoints and servers, to, for example, AllSigned ensures the following
- Scripts can run
- Requires that all scripts and configuration files are signed by a trusted publisher, including scripts written on the local device.
- Prompts before running scripts from publishers that have yet to be classified as trusted or untrusted
- The remaining risk with AllSigned is that a signed script may still be malicious.
- Configuring the Windows PowerShell execution policy within your estate, including both client endpoints and servers, to, for example, AllSigned ensures the following
- Constrained language mode
- ConstrainedLanguage mode protects your systems by limited the available cmtlets and .NET types that can be used in a Windows PowerShell session.
- Application Control
- Windows 10 introduced two new technologies, Windows Defender Application Control (WDAC) and AppLocker. Both of these technologies all you to create a lockdown experience to help secure Windows PowerShell in your environment.
- Just Enough Administration
- JEA, another technology from Microsoft, is a security tool that enables delegated administration for anything managed by PowerShell.
- JEA lets you do the following
- Reduce the number of administrators on your machines
- Limit what users can do
- Better understand what your users are doing
- Secure PowerShell remoting using WinRM
- Microsoft recommend using Windows PowerShell remoting to manage Windows systems, and after seeing how powerful it is, I totally agree, as long as you secure it!
- Security considerations for PowerShell remoting
The list of ways you can secure PowerShell goes on, and while you may find it easier to just block PowerShell entirely, the pros of using PowerShell in your environment far out-weight the cons, in my opinion.
Worrying about your code
Everyone writes code differently, which can be seen in the examples given throughout this blog post. As long as you choose a standard for your script, and stick to it, that’s fine – If it works, it works! Yes, I’m sure everyone’s scripts could be better written in some places, consolidated in others and more efficient, but at the end of the day everyone is different. Follow the general best practices, comment your code and stick to your standard and use tabs instead of spaces, you’ll do just fine.
Things you wish you knew about sooner
GitHub Copilot
If I can stress anything enough in this post, it’s that you should look into copilot from GitHub – GitHub Copilot · Your AI pair programmer.
Copilot, from GitHub, can be used within code editors like Visual Studio Code (VSCode) to provide autocomplete-style suggestions. It will provide you with suggestions based off existing code that you have started to type, or from plain text comments detailing what you are trying to achieve. It can review both the open file, as well as other files in your project, to show these suggestions directly in your editor.
Here is an example of using copilot with plaintext input to generate code within VSCode
While the suggestions provided by copilot may not always be perfect, they are usually always a great starting point for what ever you are trying to do.
The PowerShell community
The PowerShell community is extremely active, supportive and available across multiple platforms. If you’re stuck with something, you’ll always find someone is willing to help!
Places that I recommend checking out
- Twitter, specifically the PowerShell team! The PowerShell Team (@PowerShell_Team) / X (twitter.com), This is the engineering team within Microsoft that are behind PowerShell.
- Twitter again, but this time make sure you use the #powershell hashtag.
- The PowerShell Subreddit, reddit.com/r/PowerShell/. Here you will find questions, and answers, from other members of the PowerShell community, and you may even find that someone has already created what you are trying to achieve!
- The PowerShell Discord, https://discord.gg/powershell. There are channels here dedicated to all things PowerShell.
- The WinAdmins Discord, https://discord.gg/winadmins. While not specifically dedicated to PowerShell, it has a vast array of members who are very PowerShell savvy.
- The PowerShell gallery, PowerShell Gallery | Home. You will find a vast array of pre-existing modules hosted here, which are free for you to use within your scripts!
Last, and most definitely not least, PSConf EU is an absolute must, PSConfEU – PowerShell Conference Europe. Each year, people from all around the world head to PSConfEU to share their knowledge with Windows PowerShell. Whether your relatively new or have been using PowerShell from day 1, you’re guaranteed to learn something new!
PowerShell in a month of lunches
Some light reading never hurt anyone, especially not when it’s related to PowerShell! PowerShell in a month of lunches is really what got me into PowerShell when I first started as an IT administrator. I can’t recommend it enough if you’re looking to start from scratch, or even brush up on your existing knowledge.
PowerShell is cross platform!
While commonly known as “Windows PowerShell”, PowerShell itself is available on Windows, Linux and macOS! Obviously there are some differences between Windows PowerShell and Linux/macOS, but you can take a lot of what you know and use it to manage and interact with non-Windows devices.
PowerShell differences on non-Windows platforms – PowerShell | Microsoft Learn
Conclusion
You can use Windows PowerShell to do pretty much anything these days, from automating the deployment of virtual servers in platforms like Hyper-V and VMWare, the building of physical servers, or client endpoint devices, automating the configuration of Windows and Linux devices, automate the onboarding or offboarding of new users in Active Directory or Entra ID, interact with APIs, the list is endless.
I feel I could quite easily talk about PowerShell all day, but I’ll finish with this.
PowerShell is awesome.