Search icon CANCEL
Cart icon
Close icon
You have no products in your basket yet
Save more on your purchases!
Savings automatically calculated. No voucher code required
Arrow left icon
All Products
Best Sellers
New Releases
Learning Hub
Free Learning
Arrow right icon
Mastering PowerShell Scripting - Fifth Edition
Mastering PowerShell Scripting - Fifth Edition

Mastering PowerShell Scripting: Automate repetitive tasks and simplify complex administrative tasks using PowerShell, Fifth Edition

By Chris Dent
$35.99 $24.99
Book May 2024 826 pages 5th Edition
$35.99 $24.99
$15.99 Monthly
$35.99 $24.99
$15.99 Monthly

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon AI Assistant (beta) to help accelerate your learning
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now
Table of content icon View table of contents Preview book icon Preview Book

Mastering PowerShell Scripting - Fifth Edition

Introduction to PowerShell

PowerShell is a shell scripting language from Microsoft originally released for Windows in 2006. PowerShell was written to appeal to systems administrators and presents a great deal of its functionality as commands such as Get-ChildItem, Get-Content, New-Item, and so on.

Microsoft Exchange was one of the first systems to embrace PowerShell with the release of Exchange 2007.

Active Directory tools followed a few years later along with tools to manage on-premises virtualization platforms from VMware and Microsoft Hyper-V.

More recently, PowerShell has been offered as a management tool for cloud platforms like Azure and AWS. In addition to modules that can be used to interact with either service, Azure and AWS both offer in-browser shells to directly manage services.

Windows PowerShell, or the Desktop edition, includes the original version through to 5.1, which is the final release of the Windows-specific shell. Windows PowerShell versions are based on .NET Framework.

In 2018, the first version of PowerShell Core was released with PowerShell 6. The move from .NET Framework to .NET Core allows the latest versions of PowerShell to run on Linux and macOS, as well as Windows.

Since then, PowerShell 7 has been released and continues to receive new features and updates. The core edition of PowerShell has seen a move through .NET Core 3.1 to .NET 8 with PowerShell 7.4.

The other significant difference between Windows PowerShell and PowerShell is that PowerShell 6 and above are open source. The project is on GitHub and is open to public contributors:

A significant number of community contributors have been driving change, making commands more usable and useful, adding new features, and fixing bugs. For example, Invoke-WebRequest and Invoke-RestMethod were completely overhauled in PowerShell 6, greatly improving how they perform while retaining much in the way of backward compatibility.

Several core commands were removed while these changes were being made. For example, the Get-WmiObject and New-WebServiceProxy commands have been removed. The reasons for this vary; in some cases, the commands are fundamentally incompatible with .NET Core. In a few cases, the commands were under restricted licensing agreements and could not be made open source. These differences are highlighted in this book and alternatives are demonstrated where possible.

Despite all this change, PowerShell still maintains strong backward compatibility, with very few breaking changes between the two editions. Operators and language keywords remain the same, and most changes are new features instead of changes to existing ones. Exceptions to this tend to be edge cases like parameter changes to Get-Content when reading byte content. These differences in behavior are highlighted throughout this book. Lessons learned using Windows PowerShell can be applied to PowerShell 7, and they will continue to be applicable to future versions of PowerShell.

This book is split into several sections. Much of this book is intended to act as a reference. The following topics will be covered:

  • Exploring PowerShell fundamentals
  • Working with data
  • Automating with PowerShell
  • Extending PowerShell

While exploring the fundamentals of the language, this first section of the book attempts to cover as many of the building blocks as possible.

This chapter explores a diverse set of topics:

  • What is PowerShell?
  • The command line
  • PowerShell editors
  • Getting help
  • Command naming and discovery
  • About profile scripts
  • Parameters, values, and parameter sets
  • Introduction to providers
  • Introduction to splatting
  • Parser modes
  • Experimental features

Technical requirements

This chapter makes use of the following on the Windows platform: PowerShell 7.

At the start of this chapter, PowerShell was described as a shell scripting language. But this is perhaps not a complete description.

What is PowerShell?

PowerShell is a mixture of a command-line interface, a functional programming language, and an object-oriented programming language. PowerShell is based on Microsoft .NET, which gives it a level of open flexibility that was not available in Microsoft’s scripting languages (such as VBScript or batch) before this.

PowerShell has been written to be highly discoverable. It has substantial built-in help, which is accessible within the console via the Get-Help command. PowerShell has commands such as Get-Member to allow a user to discover the details of any objects it returns.

PowerShell 7 can be installed alongside Windows PowerShell. Windows PowerShell is installed in Windows\System32 by the Windows Management Framework packages, and it cannot be moved elsewhere. PowerShell Core and 7 are both installed in the Program Files folder and do not share any of the files used by Windows PowerShell. Preview versions of PowerShell can be installed alongside the full releases and have separate folder structures.

Command line customization is a popular subject, and several tools are available to help.

The command line

PowerShell 7 comes with a module called PSReadLine. A module is a collection of related commands. Modules are explored in greater detail in Chapter 2, Modules.

PSReadLine provides command-line syntax highlighting, preserves history between sessions, and offers completion services when writing commands.

PSReadLine can be configured to offer command completion based on previously typed commands, a useful feature when using similar commands in the console and one that can save searching history for the right command. By default, PSReadline 2.2.6 uses history and a command prediction plugin. The plugin may be explicitly enabled using Set-PSReadLineOption.

Set-PSReadLineOption -PredictionSource HistoryAndPlugin

Once enabled, PSReadLine will offer suggestions based on typed content that may be completed using Tab as shown in Figure 1.1.

Figure 1.1: PSReadLine Predictive completion

By default, Tab can be used to complete any command or parameter, and a variety of arguments for parameters. In addition to Tab completion, PSReadLine allows the use of Control and Space to provide menu style completion. For example, entering the following partial command:

Get-ChildItem -

Then pressing Control and Space (immediately after the hyphen) will show a menu that can be navigated using the cursor keys, as shown in Figure 1.2:

Figure 1.2: PSReadLine List completion

In PowerShell, the prompt displayed is controlled by a function named prompt. A very simple prompt can be set as shown below:

function prompt {
    "$env:USERNAME $pwd PS>"

The default prompt can be restored by restarting PowerShell. A profile script is required to make changes on console restart. See about_profiles for more information:

Get-Help about_profiles

Several modules and tools exist to help customize prompts in PowerShell:

PowerShell is a complex language; a good editor can save time finding the right syntax to use in a script.

PowerShell editors

While PowerShell scripts can be written using the Notepad application alone, it is rarely desirable. Using an editor that was designed to work with PowerShell can save a lot of time.

Editors with explicit support for PowerShell, such as Visual Studio Code (VS Code with the PowerShell extension) and the PowerShell Studio editor offer automatic completion (IntelliSense). IntelliSense reduces the amount of cross-referencing help content required while writing code. Finding a comfortable editor early on is a good way to ease into PowerShell; memorizing commands and parameters is not necessary.

In addition to VS Code and PowerShell Studio, Windows PowerShell comes with the PowerShell ISE. The PowerShell ISE has not been updated for PowerShell 6 and higher and will only function correctly for the Windows PowerShell Desktop edition.

PowerShell Studio is not free but includes graphical user interface development features.

VS Code is a highly recommended editor for PowerShell as it is free and supports a wide variety of different languages. VS Code is an open-source editor that was published by Microsoft and can be downloaded from VS Code tends to be the editor of choice for many in the PowerShell community.

The functionality of VS Code can be enhanced by using extensions from the marketplace: The Extension installer is part of the VS Code user interface, and the types of available extensions are shown in Figure 1.3:

Figure 1.3: PowerShell extensions in VS Code

The icons available on the left-hand side change depending on the extensions installed. A new installation of VS Code will show fewer icons than Figure 1.3.

The PowerShell Extension should be installed. Other popular extensions include:

  • Bracket Pair Colorizer 2
  • Blockman
  • Chocolatey
  • Error Lens
  • Live Share
  • Prettify JSON

Paid-for extensions, such as PowerShell Pro Tools, offer us the ability to design user interfaces in VS Code.

The integrated console in VS Code can be used with all installed versions of PowerShell. The following screenshot shows how to change the version of PowerShell used when editing a script. Note the clickable version in the bottom-right corner:

Figure 1.4: Choosing a PowerShell version

The IntelliSense version provided by the editor will list and hint at the possible commands and parameters available. Help content is available to fill in the details.

Getting help

PowerShell includes a built-in help system accessible using the Get-Help command. Help content in PowerShell is often rich and detailed, frequently including multiple examples. Gaining confidence using the built-in help system is an important part of working with PowerShell. Script authors and PowerShell developers can easily write their own help content when working with functions, scripts, and script modules.

Updatable help

The concept of updatable help was added in Windows PowerShell 3. It allows users to obtain the most recent versions of their help documentation outside of PowerShell on a web service. Help content can be downloaded and installed using the Update-Help command in PowerShell.

Which modules support updatable help?

The command below shows a list of modules that support updatable help:

Get-Module -ListAvailable | Where-Object HelpInfoURI

Help for the core components of PowerShell is not part of the PowerShell 7 installation package. Content must be downloaded before it can be viewed.

The first time Get-Help runs, PowerShell prompts to update help.

Computers with no internet access or computers behind a restrictive proxy server may not be able to download help content directly. The Save-Help command can be used in this scenario, which is discussed later in this section, to work around the problem.

If PowerShell is unable to download help, it can only show a small amount of information about a command; for example, without downloading help, the content for the Out-Null command is minimal, as shown here:

PS> Get-Help Out-Null
    Out-Null [-InputObject <psobject>] [<CommonParameters>]
    Get-Help cannot find the Help files for this cmdlet on this computer.
    It is displaying only partial help.
        -- To download and install Help files for the module that
           includes this cmdlet, use Update-Help.
        -- To view the Help topic for this cmdlet online, type:
           "Get-Help Out-Null -Online" or go to

The help content in the preceding example is automatically generated by PowerShell. PowerShell inspects the command to determine which parameters are available.

Updatable help as a help file can be viewed using the following command:

Get-Help about_Updatable_Help

Updateable help is not entirely free from issues. Internet resources change as content moves around over time, which may invalidate HelpInfoUri, the URL stored within the module and used to retrieve help files. For example, help for the Dism module was not available when this chapter was written.

The Get-Help command

When Get-Help is used without parameters, it shows introductory help about the help system. This content is taken from the default help file (Get-Help default); a snippet of this is as follows:

PS> Get-Help
 PowerShell Help System
 Displays help about PowerShell cmdlets and concepts.
 PowerShell Help describes Windows PowerShell cmdlets, functions,

Help content can be long

The help content, in most cases, does not fit on a single screen. The help command differs from Get-Help in that it pauses (waiting for a key to be pressed) after each page; for example:

help default

The previous command is equivalent to running Get-Help and piping it into the more command:

Get-Help default | more

Alternatively, Get-Help can be asked to show a window:

Get-Help default -ShowWindow

The available help content may be listed using either of the following two commands:

Get-Help *
Get-Help -Category All

Help for a subject can be viewed as follows:

Get-Help -Name <Topic>

For example, help for the Get-Variable command may be shown:

Get-Help Get-Variable

If a help document includes an online version link, it may be opened in a browser with the -Online parameter:

Get-Help Get-Command -Online

The URL used for online help can be viewed using Get-Command:

Get-Command Get-Command | Select-Object HelpUri

The help content is broken down into several sections: name, synopsis, syntax, description, related links, and remarks.

Name simply includes the name of the command. Synopsis is a short description of the functionality provided by the command, often no more than one sentence. Description often provides much greater detail than synopsis. Related links and remarks are optional fields, which may include links to related content.

Syntax is covered in the following section in more detail as it is the most complex part of the help document. A good understanding of the syntax allows quick evaluation of how to use a command, often removing the need to do more than skim help content.


The syntax section lists each of the possible combinations of parameters a command accepts; each of these is known as a parameter set.

A command that has more than one parameter set is shown in this example for the Get-Process command:

    Get-Process [[-Name] <System.String[]>] [-FileVersionInfo] [-Module] [<CommonParameters>]
    Get-Process [-FileVersionInfo] -Id <System.Int32[]> [-Module] [<CommonParameters>]

The syntax elements written in square brackets are optional; for example, syntax help for Get-Process shows that all its parameters are optional, as the following code shows:

    Get-Process [[-Name] <System.String[]>] [-FileVersionInfo] [-Module] [<CommonParameters>]

As the Name parameter is optional, Get-Process may be run without any parameters. The command may also be run by specifying a value only and no parameter name. Alternatively, the parameter name can be included as well as the value.

Each of the following examples is a valid use of Get-Process:

Get-Process pwsh
Get-Process -Name pwsh

Get-Command can show syntax

Get-Command may be used to view the syntax for a command. For example, running the following command will show the same output as seen in the Syntax section of Get-Help:

Get-Command Get-Variable -Syntax

The different parameter types and how they are used are explored later in this chapter.


The Examples section of help provides working examples of how a command may be used. Help often includes more than one example.

In some cases, a command is sufficiently complex that it requires a detailed example to accompany parameter descriptions; in others, the command is simple, and a good example may serve in lieu of reading the help documentation.

PowerShell users can update help

Help documentation for built-in commands is open source. If a cmdlet is missing helpful examples, they can be added.

A link to the PowerShell-Docs repository is available at the bottom of the online help page. It should send you to the en-US version of help:

Examples for a command can be requested by specifying the Examples parameter for Get-Help, as shown in the following example:

Get-Help Get-Process -Examples

The help information for most cmdlets usually includes several examples of their use, especially if the command has more than one parameter set.


Parameters in PowerShell are used to supply named arguments to PowerShell commands.

Help for specific parameters can be requested as follows:

Get-Help Get-Command -Parameter <ParameterName>

The Parameter parameter allows for the quick retrieval of specific help for a single parameter; for example, help for the Path parameter of the Import-Csv command may be viewed:

PS> Get-Help Import-Csv -Parameter Path
-Path [<String[]>]
    Specifies the path to the CSV file to import. You can also
    pipe a path to `Import-Csv`.
    Required? false
    Position? 1
    Default value None
    Accept pipeline input? true (ByValue)
    Accept wildcard characters? false

This avoids needing to scroll through a potentially large help file to see how to use just one parameter.

The preceding content describes the parameter, whether the parameter is mandatory (Required), its position, default value, pipeline behavior, and support for wildcards.

Detailed and Full switches

The Detailed switch parameter (a parameter that does not require an argument) asks Get-Help to return the most help content.

The default sections returned by help are Name, Synopsis, Syntax, Description, Related Links, and Remarks.

When Detailed is requested, Parameters and Examples are added. Related Links is excluded.

The Detailed parameter is used as follows:

Get-Help Get-Process -Detailed

The Full switch parameter includes all the default sections, as well as Parameters, Inputs, Outputs, Notes, and Examples.

The following code shows the sections detailing the input and output types for Get-Process from the full help document; content before those sections has been removed from this example:

PS> Get-Help Get-Process -Full
... <content removed> ...
        You can pipe a process object to Get-Process.
        By default, this cmdlet returns a
        System.Diagnostics.Process object.
        If you use the FileVersionInfo parameter, this cmdlet
        returns a FileVersionInfo object.
        If you use the Module parameter, without the
        FileVersionInfo parameter, this cmdlet returns a
        ProcessModule object. 

INPUTS is typically used to describe the value types that can be piped to a command. Pipelines are introduced in Chapter 4, Working with Objects in PowerShell.

In addition to the extra sections, the Full switch parameter includes metadata in the parameter section, the same parameter metadata seen when using Get-Help Get-Process -Parameter Name.

Help content in PowerShell is extensive and a valuable resource to have on any system running PowerShell.


The Save-Help command can be used with modules that support updatable help. It allows help content for installed modules to be saved to disk.

Help for a module can be downloaded using the following command. The destination folder must exist before running the command:

New-Item -Path C:\PSHelp -ItemType Directory
Save-Help -Module Microsoft.PowerShell.Management -DestinationPath C:\PSHelp

By default, Save-Help attempts to download help content for the current UI culture; that is, the current user interface language. The Get-UICulture command can be used to view the current culture, as the following example shows:

PS> Get-UICulture
LCID             Name             DisplayName
----             ----             -----------
2057             en-GB            English (United Kingdom)

If help content is not available for that culture, Save-Help will not do anything and will not raise an error. For UI cultures other than en-US, the C:\PSHelp folder will likely be empty.

Save-Help can be instructed to download help in a specific language by using the UICulture parameter:

Save-Help -Module Microsoft.PowerShell.Management -DestinationPath C:\PSHelp -UICulture en-US

If help content is available, it is downloaded as shown in the C:\PSHelp folder here:

Figure 1.5: Downloaded help content for en-US

By default, Save-Help (and Update-Help) will not download help content more often than once every 24 hours as a rate-limiting control. This can be seen using the Verbose switch parameter:

PS> Save-Help -Module Microsoft.PowerShell.Management -DestinationPath C:\PSHelp -UICulture en-US -Verbose
VERBOSE: Help was not saved for the module Microsoft.PowerShell.Management, because the Save-Help command was run on this computer within the last 24 hours.

The Verbose switch parameter is used to make any verbose messages the command author has included visible in the console.

If help content is available for other cultures, and that content is downloaded immediately after en-US, then the Force parameter must be added:

Save-Help -Module Microsoft.PowerShell.Management -DestinationPath C:\PSHelp -UICulture pl-PL -Force

However, as help content for the Microsoft.PowerShell.Management module is only available in en-US, the preceding command displays an error message describing which cultures help is available for.

Help content for all modules supporting updateable help can be saved as follows:

Save-Help -DestinationPath C:\PSHelp -UICulture en-US

Saved help content can be copied to another computer and imported using Update-Help. This technique is useful for computers that do not have internet access as it means help content can be made available.


The Update-Help command performs two tasks:

  • Update help files on the local computer from the internet.
  • Updates help files on the local computer from previously saved help files.

To update help from the internet for all modules that support updateable help, run the Update-Help cmdlet with no parameters:


The Update-Help command includes a Scope parameter, which may be used to make help content available without needing Administrative access:

Update-Help -Scope CurrentUser

When the Scope parameter is set to CurrentUser, help content is downloaded to and read from (by Get-Help) $home\Documents\PowerShell\help. This path may be affected by folder redirection of the Documents folders, such as with services like OneDrive.

The Scope parameter is not available in Windows PowerShell and administrative rights are required to update help content.

For UI cultures other than en-US, the UICulture parameter may be required:

Update-Help -UICulture en-US

Like Save-Help, Update-Help will not download help for a module more than once every 24 hours by default. This can be overridden by using the Force parameter:

Update-Help -Name Microsoft.PowerShell.Management -Force -UICulture en-US

Help content that was saved using Save-Help can be imported from a folder using the SourcePath parameter:

Update-Help -SourcePath C:\PSHelp

If the folder does not contain content for the current UI culture (shown with Get-UICulture), an error message will be displayed:

PS> Update-Help -Module Microsoft.PowerShell.Management -SourcePath C:\PSHelp
Update-Help: Failed to update Help for the module(s) 'Microsoft.PowerShell.Management' with UI culture(s) {en-GB} : Unable to retrieve the HelpInfo XML file for UI culture en-GB. Make sure the HelpInfoUri property in the module manifest is valid or check your network connection and then try the command again..

The UICulture parameter can be used again to update help content from the folder:

Update-Help -Module Microsoft.PowerShell.Management -SourcePath C:\PSHelp -UICulture en-US

Help content is not limited to help for specific commands. PowerShell includes many topical help documents.

About_* help files

About_* documents describe features of the language or concepts that apply to more than one command. These items do not fit into help for individual commands.

The list of help files can be viewed by running Get-Help with the category set to HelpFile, as demonstrated in the following code:

Get-Help -Category HelpFile

Alternatively, wildcards can be used with the Name parameter of Get-Help:

Get-Help -Name About_*

These help files cover a huge variety of topics ranging from aliases to modules to WMI. A number of these are shown here. The list will vary, depending on the modules installed on the computer running the command:

Name                         Category  Module  Synopsis
----                         --------  ------  --------
default                      HelpFile          SHORT DESCRIPTION
about_PSReadLine             HelpFile                
about_Configuration          HelpFile          The Configuratio...
about_Aliases                HelpFile                          
about_Alias_Provider         HelpFile                          
about_Arithmetic_Operators   HelpFile                          
about_Arrays                 HelpFile                          
about_Assignment_Operators   HelpFile                          
about_Automatic_Variables    HelpFile                          
about_Break                  HelpFile                          

Using help content is an important part of working with PowerShell. Memorizing content is not necessary where instructions and reference material are easily accessible.

Get-Help may lead to finding a command to help achieve a task; however, it is often quicker to search using Get-Command.

Command naming and discovery

Commands in PowerShell are formed around verb and noun pairs in the form verb-noun.

This feature is useful when finding commands; it allows educated guesses about the names of commands so that there is little need to memorize long lists of commands. Commands use verbs to describe intent, and nouns to describe the target.


The list of verbs is maintained by Microsoft. Verbs are words such as Add, Get, Set, and New. This formal approach to naming commands greatly assists in discovery.

The list of verbs can be seen in PowerShell using the following command:


Verbs are grouped around different areas, such as data, life cycle, and security. Complementary actions such as encryption and decryption tend to use verbs in the same group; for example, the verb Protect may be used to encrypt something and the verb Unprotect may be used to decrypt something.

More commonly, Get and Set, or New and Remove commands may also be seen as complementary.

Verb descriptions

A detailed list of verbs, along with their use cases, is available on MSDN:

It is possible, although not recommended, to use verbs other than those in the approved list. If a command with an unapproved verb is written and included in a module, a warning message will be displayed every time the module is imported.

Verbs are paired with nouns that describe the target of a command.


A noun provides a very short description of the object the command is expecting to act on. The noun part may be a single word, as is the case with Get-Process, New-Item, and Get-Help, or more than one word, as seen with Get-ChildItem, Invoke-WebRequest, and Send-MailMessage.

Command names often include a prefix on the noun. The Microsoft AD module uses the AD prefix. The Microsoft Graph modules are prefixed with the Mg prefix. Commands for managing the network components of the Windows operating system are prefixed with Net.

Modules are explored in Chapter 2, Modules. As mentioned above, the commands used to manage the networking components of Windows use the Net prefix on every noun. This, in turn, allows the use of wildcards to search for commands.

Finding commands

The verb-noun pairing strives to make it easier to find commands without resorting to search engines.

For example, if the goal was to list firewall rules, the following command may be used to show the Get commands that might affect the firewall:

PS> Get-Command Get-*Firewall*
CommandType Name                               Version Source
----------- ----                               ------- ------
Function    Get-NetFirewallAddressFilter NetSecurity
Function    Get-NetFirewallApplicationFilter NetSecurity
Function    Get-NetFirewallInterfaceFilter NetSecurity
Function    Get-NetFirewallInterfaceTypeFilter NetSecurity
Function    Get-NetFirewallPortFilter NetSecurity
Function    Get-NetFirewallProfile    NetSecurity
Function    Get-NetFirewallRule       NetSecurity
Function    Get-NetFirewallSecurityFilter NetSecurity
Function    Get-NetFirewallServiceFilter NetSecurity
Function    Get-NetFirewallSetting    NetSecurity

A wildcard might be used for the verb or the specific parameters for Verb and Noun might be used with Get-Command:

Get-Command -Verb Get, Set -Noun *Firewall*

The Get-Help command may also be used to find the list of commands above:

Get-Help Get-*Firewall*

As Get-Help also searches for help content, it is slower to use to search than Get-Command.

The list of commands returned may vary, depending on the modules installed on the computer.

From the preceding list, Get-NetFirewallRule closely matches the requirement (to see a list of firewall rules) and should be explored. Notice how each of the commands in the list above maintains the same prefix. This is a common naming practice in PowerShell.

Once a potential command has been found, Get-Help can be used to assess whether the command is suitable.


An alias in PowerShell is an alternate name for a command. A command may have more than one alias. Unlike languages like Bash, an alias cannot include parameters.

The list of aliases can be viewed by using Get-Alias. The first few aliases are shown in the following example:

PS> Get-Alias
CommandType Name
----------- ----
Alias       % -> ForEach-Object
Alias       ? -> Where-Object
Alias       ac -> Add-Content
Alias       cat -> Get-Content
Alias       cd -> Set-Location

Get-Alias may be used to find the command behind an alias:

Get-Alias dir

The aliases available change depending on the operating system. For example, PowerShell on Linux omits aliases such as ac (Add-Content), ls (Get-ChildItem), and cat (Get-Content).

Get-Alias may also be used to find the aliases for any command:

PS> Get-Alias -Definition Get-ChildItem
CommandType     Name                     Version    Source
-----------     ----                     -------    ------
Alias           dir -> Get-ChildItem
Alias           gci -> Get-ChildItem
Alias           ls -> Get-ChildItem

Examples of aliases that are frequently used in examples on the internet include the following:

  • % for ForEach-Object
  • ? for Where-Object
  • cd for Set-Location
  • gc or cat for Get-Content
  • ls or dir for Get-ChildItem
  • irm for Invoke-WebRequest
  • iex for Invoke-Expression

An alias does not change how a command is used. There is no difference in the result of the following two commands:

cd $env:TEMP
Set-Location $env:TEMP

New aliases are created with the New-Alias command. For example, an alias named grep for the Select-String command can be created as follows:

New-Alias grep -Value Select-String

Aliases can be removed using the Remove-Alias command, including default aliases such as ls:

Remove-Alias grep

Aliases may also be removed using Remove-Item as an alternative to Remove-Alias:

Remove-Item alias:\grep

Aliases created in one session are not remembered when a new PowerShell session is started.

More information is available about aliases in the help file about_Aliases. The help file is viewed using the following command:

Get-Help about_Aliases

As mentioned above, aliases do not persist between PowerShell sessions (when the console is restarted). Profile scripts can be used to make an alias (or any other preferences) available when PowerShell is restarted.

About profile scripts

Aliases do not persist across PowerShell sessions. A profile script is often used for user-specific preferences like this.

Profiles are where most user-specific shell customization takes place, from changing prompts and default settings to loading modules to creating aliases.

Shell customization with profile scripts is an enormously involved and highly personal topic. This section provides a brief introduction to the topic only.

PowerShell has four different profile paths – two are user-specific and two are machine-specific. The profile paths are also dependent on the host – one user and one machine path are specific to the terminal that started PowerShell.

The profile paths are described by the built-in variable $profile. The Select-Object * command is used to show all the possible values in the example below:

PS> $profile | Select-Object *
AllUsersAllHosts       : C:\Program Files\PowerShell\7\profile.ps1
AllUsersCurrentHost    : C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts    : C:\Users\user\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\user\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

If the same command is run in the VS Code integrated terminal, the two host-specific paths will differ:

PS> $profile | Select-Object *
AllUsersAllHosts       : C:\Program Files\PowerShell\7\profile.ps1
AllUsersCurrentHost    : C:\Program Files\PowerShell\7\Microsoft.VSCode_profile.ps1
CurrentUserAllHosts    : C:\Users\user\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\user\Documents\PowerShell\Microsoft.VSCode_profile.ps1

PowerShell will run each of the profile scripts where the script exists. If the script does not exist, the path is ignored.

Starting PowerShell with the -NoProfile switch avoids loading profile script files, a useful parameter for any scheduled scripts, or for testing to see if the profile is causing a problem.

The paths used above may not exist at all. To create a profile script, create the directory first, if necessary, then save the script file using one of the names and paths above.

The about document for profiles explores this topic further:

Get-Help about_profiles

A variety of different tools are available to customize the look and feel, which are typically started from a profile script. Customization of the prompt is a common activity:

The Windows Terminal customized prompts article makes use of oh-my-posh in an example setup:

Finally, for users with multiple computers, the chezmoi tool might be used to ensure all computers use the same configuration:

Commands (and aliases) use parameters to pass arguments into a command.

Parameters, values, and parameter sets

As seen while looking at syntax in Get-Help, commands accept a mixture of parameters. The following sections show how these parameters are described in help and how to use them.


When viewing help for a command, several different conventions are used to describe when a parameter is required and how it should be used. These conventions include:

  • Optional parameters, where parameter names and arguments are enclosed in a single pair of square brackets.
  • Optional positional parameters – the same as an optional parameter but with the parameter name also enclosed in square brackets.
  • Mandatory parameters, where the parameter name and argument are not bracketed.
  • Mandatory positional parameters, where the parameter name is in square brackets, but the argument is not.

The following sections show each of these conventions in greater detail.

Optional parameters

Optional parameters are surrounded by square brackets. If a parameter is used, a value (or argument) must be supplied. A fragment of the syntax for Get-Help is shown below. It shows that a Category parameter is available and that the parameter is optional.

    Get-Help ... [-Category <string[]>] ...

If a value for the Category parameter is to be used, the name of the parameter must also be specified. This is shown in the following example:

Get-Help -Category HelpFile

The command above filters help documents to help files, the “about” documents.

Optional positional parameters

An optional positional parameter is surrounded by square brackets, like an optional parameter. In addition, the parameter name itself is enclosed in square brackets. This indicates that the parameter is optional and that if it is used, the parameter and value can be supplied, or just the value without the parameter name.

It is not uncommon to see an optional positional parameter as the first parameter:

    Get-Process [[-Name] <string[]>] ...

In this example, either of the following may be used:

Get-Process -Name pwsh
Get-Process pwsh

The output from the two commands is identical. This includes the parameter name, which, even when it is optional, is less ambiguous and therefore a recommended practice.

Mandatory parameters

A mandatory parameter must always be supplied and is written as follows:

    Get-ADUser -Filter <string> ...

In this case, the Filter parameter name must be used, and it must be given a value. For example, to supply a Filter for the command, the Filter parameter must be explicitly written:

Get-ADUser -Filter 'sAMAccountName -eq "SomeName"'

The Get-ADUser command has a second parameter set that uses a different parameter name with a positional value.

Mandatory positional parameters

Mandatory parameters must always be supplied, but in some cases, it is possible to supply the value without using the parameter name. The parameter the value applies to is based on position.

Parameters that are mandatory and accept values based on position are written with the parameter name only in square brackets, as shown here:

    Get-ADUser [-Identity] <ADUser> ...

In this case, the Identity parameter name is optional, but the value is not. This command may be used as described by either of the following examples:

Get-ADUser -Identity useridentity
Get-ADUser useridentity

In both cases, the supplied value fills the Identity parameter.

The Add-Content command has a parameter set that uses more than one mandatory positional parameter. The first part of the syntax for the parameter set is shown here:

Add-Content [-Path] <string[]> [-Value] <object[]>

In this case, the command may be called using any of the following:

Add-Content -Path c:\temp\file.txt -Value 'Hello world'
Add-Content -Value 'Hello world' -Path c:\temp\file.txt
Add-Content 'Hello world' -Path c:\temp\file.txt
Add-Content c:\temp\file.txt -Value 'Hello world'
Add-Content c:\temp\file.txt 'Hello world'

The first of these is easiest to read as both parameters are explicitly named and tends to be the better style to use.

Each of the parameters so far has required an argument, a value. PowerShell also allows parameters that do not require arguments.

Switch parameters

A switch parameter does not require an argument. If the switch is present, the value is equivalent to true, while if the switch parameter is absent, it is equivalent to false.

As with the other types of parameters, optional use is denoted by using square brackets around the parameter.

Switch parameters are typically used to toggle a behavior on. For example, Recurse is a switch parameter for Get-ChildItem:

    Get-ChildItem ... [-Recurse] ...

Using the switch instructs Get-ChildItem to recurse when listing the content of a directory, as shown here:

Get-ChildItem c:\windows -Recurse

It is possible to supply a value for a switch parameter from a variable. This might be desirable when writing a script where the presence of a switch parameter is based on another variable. As switch parameters do not normally expect a value, a syntax change is required:

# Code which determines if Recurse is required
$recurse = $false
Get-ChildItem c:\windows -Recurse:$recurse

In some cases, a switch parameter will default to present, and it may be desirable to stop the parameter from applying. The most common example is the Confirm parameter, which will be explored later in this chapter.

Parameter values

The syntax blocks explored in the preceding sections show the type that is expected when providing a value for a parameter. A type is a .NET concept; it describes what an object is, how it behaves, and what it can do. Types will be covered in greater detail in Chapter 7, Working with .NET.

The Get-CimInstance command expects a string as the argument for the ClassName parameter. This is shown in the snippet taken from the syntax block:

Get-CimInstance [-ClassName] <String>

A string is a sequence of characters. For example, the string Win32_Service can be used as follows:

Get-CimInstance -ClassName Win32_Service

ClassName must always be a single value. If more than one value is supplied, an error will be displayed:

PS> Get-CimInstance -ClassName Win32_Service, Win32_Process
Get-CimInstance: Cannot convert 'System.Object[]' to the type 'System.String' required by parameter 'ClassName'. Specified method is not supported.

Parameters that accept more than one value use [] after the type name. This indicates that the type is an array. The Name parameter for the Get-Service command is shown here:

Get-Service [[-Name] <String[]>]

In this case, the parameter type is an array of strings. An array may consist of one or more strings separated by a comma:

PS> Get-Service -Name WinDefend, WlanSvc
Status   Name               DisplayName
------   ----               -----------
Running  WinDefend          Windows Defender Antivirus Service
Running  WlanSvc            WLAN AutoConfig

PowerShell will attempt to coerce any value supplied into the required type. A single string can be used as an argument for the parameter. PowerShell will convert the single value into an array of strings with one element. For example:

Get-Service -Name WinDefend

Each of the commands used in this section will allow the value to be entered without the parameter name. For example, for Get-Service, the Name parameter can be omitted:

Get-Service WinDefend
Get-Service WinDefend, WlanSvc

When using positional parameters, PowerShell can use the type to determine which parameter (and which parameter set) should be used.

Parameter sets

In PowerShell, a parameter set is a set of parameters that may be used together when running a command.

Many of the commands in PowerShell have more than one parameter set. This was seen when looking at the Syntax section when using Get-Help.

For example, the Stop-Process command has three parameter sets:

    Stop-Process [-Id] <Int32[]> [-Confirm] [-Force] [-PassThru] [-WhatIf] [<CommonParameters>]
    Stop-Process [-InputObject] <Process[]> [-Confirm] [-Force] [-PassThru] [-WhatIf] [<CommonParameters>]
    Stop-Process [-Confirm] [-Force] -Name <String[]> [-PassThru] [-WhatIf] [<CommonParameters>]

PowerShell will attempt to find a matching parameter set based on the parameters and values it is given.

The parameter sets for Stop-Process have two different sets that will accept a value by position:

Stop-Process [-Id] <Int32[]>
Stop-Process [-InputObject] <Process[]>

The first expects an ID as an integer. The second expects a Process object, an object returned by the Get-Process command.

The variable $PID is an automatic variable that holds the process ID (an integer) of the current PowerShell console. Running the following command will stop the PowerShell process. The first parameter set for Stop-Process is chosen because an integer value is used:

Stop-Process $PID

The second parameter set expects a value for InputObject. Again, this may be supplied as a positional parameter (or via the pipeline). In this case, PowerShell distinguishes based on its type. The following snippet contains the three possible approaches available when using the InputObject parameter:

$process = Start-Process notepad -PassThru
Stop-Process -InputObject $process
Stop-Process $process
$process | Stop-Process

Pipeline input

Get-Help shows which parameters accept pipeline input in the help for each parameter. This may be viewed using either of the following commands:

  • Get-Help Stop-Process -Parameter *
  • Get-Help Stop-Process -Full

Examples are likely to show how to use the parameters with a pipeline.

If Get-Help is incomplete, Get-Command can be used to explore parameters:

(Get-Command Stop-Process).Parameters.InputObject.Attributes

Each of the parameter sets here also shows that the command supports common parameters.

Common parameters

Common parameters are used to control some of the standardized functionality PowerShell provides, such as verbose output and actions to take when errors occur.

When looking at the syntax, most commands will end with a CommonParameters item:

    Get-Process ... [<CommonParameters>]

The following is a list of common parameters:

  • Debug
  • ErrorAction
  • ErrorVariable
  • InformationAction
  • InformationVariable
  • OutBuffer
  • OutVariable
  • PipelineVariable
  • Verbose
  • WarningAction
  • WarningVariable

Each is described in the about_CommonParameters document:

Get-Help about_CommonParameters

The help document is also available online:

For example, Stop-Process does not explicitly state that it has a Verbose switch parameter, but since Verbose is a common parameter, it may be used. This can be seen if notepad is started and immediately stopped:

PS> Start-Process notepad -Verbose -PassThru | Stop-Process -Verbose
VERBOSE: Performing the operation "Stop-Process" on target "notepad (5592)".

Not so verbose

Just because a command supports common parameters does not mean it uses them. For example, Get-Process supports the Verbose parameter, yet it does not write any verbose output when Verbose is specified.

In addition to common parameters, PowerShell also offers specialized parameters for commands that make changes.

Confirm and WhatIf

Confirm and WhatIf can be used with commands that make changes to files, variables, data, and so on. These parameters are often used with commands that use the verbs New, Set, or Remove, but the parameters are not limited to specific verbs.

Confirm and WhatIf have associated preference variables that are used to customize default behavior in PowerShell. Preference variables have an about file, which may be viewed using the following command:

Get-Help about_Preference_Variables

The Confirm switch parameter is used to control automatic prompting for high impact operations by default.

Confirm and ConfirmPreference

The Confirm switch parameter and the ConfirmPreference variable can be used to decide if a command should prompt. The decision to prompt is based on a comparison of ConfirmPreference with ConfirmImpact when set by a command author.

ConfirmPreference has four possible values:

  • High: Prompts when command impact is High (default)
  • Medium: Prompts when command impact is Medium or High
  • Low: Prompts when command impact is Low, Medium, or High
  • None: Never prompts

ConfirmImpact uses the same four values.

In Windows PowerShell, the default value for ConfirmImpact is Medium.

In PowerShell 7, the default value for ConfirmImpact is None. If the command uses SupportsShouldProcess, then the default is Medium. SupportsShouldProcess is explored in greater detail in Chapter 17, Scripts, Functions, and Script Blocks.

Finding commands with a specific impact

The following snippet returns a list of all commands that state they have a high impact:

Get-Command -CommandType Cmdlet, Function | Where-Object {

$metadata = [System.Management.Automation.CommandMetadata]$_

$metadata.ConfirmImpact -eq 'High'


If the Confirm parameter is explicitly provided, the value of ConfirmPreference within the scope of the command is set to Low, which will trigger any confirmation prompts. Scoping of preference variables is explored in greater detail in Chapter 17, Scripts, Functions, and Script Blocks.

The Confirm switch parameter therefore causes a command to prompt before an action is taken; for example, the Confirm switch parameter forces Remove-Item to prompt when a file is to be removed:

PS> Set-Location $env:TEMP
PS> New-Item FileName.txt -Force
PS> Remove-Item FileName.txt -Confirm
Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\Users\whoami\AppData\Local\Temp\FileName.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):

In the previous example, a confirmation prompt was explicitly requested. In a similar manner, confirmation prompts may be suppressed. For example, the value of the Confirm parameter may be explicitly set to false:

Set-Location $env:TEMP
New-Item FileName.txt -Force
Remove-Item FileName.txt -Confirm:$false

The ability to provide a value for the Confirm parameter is useful for commands that prompt by default; for example, Clear-RecycleBin prompts by default:

PS> Clear-RecycleBin
Are you sure you want to perform this action?
Performing the operation "Clear-RecycleBin" on target " All of the contents of the Recycle Bin".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):

Setting the Confirm parameter to false for Clear-RecycleBin bypasses the prompt and immediately empties the recycle bin:

Clear-RecycleBin -Confirm:$false

If the Confirm parameter is not set, whether a prompt is shown is determined by PowerShell. The value of the ConfirmPreference variable is compared with ConfirmImpact on a command.

There is more than one way to prompt

There are two ways of requesting confirmation in PowerShell. These are ShouldProcess and ShouldContinue. These are explored in Chapter 17, Scripts, Functions, and Script Blocks.

ShouldProcess is affected by the Confirm parameter and ConfirmPreference variable.

ShouldContinue is a forced prompt and is unaffected by the Confirm parameter and ConfirmPreference variable.

For example, Remove-Item will always prompt when attempting to delete a directory that is not empty without supplying the Recurse parameter.

It is not possible to easily discover commands using forced prompts. Reviewing documentation and testing is vital.

By default, the value of ConfirmPreference is High. This means that prompts will be raised when ConfirmImpact for a command is High. The default value for ConfirmPreference may be viewed as follows:

PS> $ConfirmPreference

Finding ConfirmImpact

In scripts and functions, the ConfirmImpact setting is part of the CmdletBinding attribute:

[CmdletBinding(ConfirmImpact = 'High')]

If CmdletBinding or ConfirmImpact is not present, the impact is Medium in Windows PowerShell and None in PowerShell 7.

The impact of a function or cmdlet may be viewed using the ConfirmImpact property of a command’s metadata:

[System.Management.Automation.CommandMetadata](Get-Command Remove-Item)

The use of CmdletBinding is explored in detail in Chapter 17, Scripts, Functions, and Script Blocks.

A new value for ConfirmPreference may be set by assigning it in the console; for example, it can be set to Low. When the preference variable is set to Low, prompts may be raised by all commands where ConfirmImpact is Low, Medium, or High:

$ConfirmPreference = 'Low'

ConfirmPreference and the Confirm parameter

When ConfirmPreference is set to None to suppress confirmation prompts, confirmation may still be explicitly requested using the Confirm parameter; for example:

$ConfirmPreference = 'None'

New-Item NewFile.txt -Confirm

Support for confirmation also provides support for WhatIf.

WhatIf and WhatIfPreference

WhatIf is typically used when testing a command. If implemented correctly by a command author, WhatIf should allow a state-changing command to be run without it making the change.

WhatIf is not always implemented as expected

WhatIf support for a command is defined by a command author. If the author does not correctly handle the preference, an undesirable change may be made.

The Set-ADAccountPassword had a bug for a while where WhatIf was ignored.

Even if a command supports WhatIf, test it on small sets of data before using the parameter to verify a large change.

The WhatIf parameter has an associated preference variable, WhatIfPreference, which may be set to either true or false. The default value is false.

The WhatIf parameter replaces the confirmation prompt with a simple statement describing the action the command would have taken. Using Remove-Item as an example again, a message will be displayed, and the file will not be deleted:

PS> Set-Location $env:TEMP
PS> New-Item FileName.txt -Force
PS> Remove-Item FileName.txt -WhatIf
What if: Performing the operation "Remove File" on target "C:\Users\whoami\AppData\Local\Temp\FileName.txt".

WhatIf can be explicitly set on a per-command basis by supplying a value in the same manner as the Confirm parameter. For example, WhatIf might be explicitly set to false:

'Some message' | Out-File $env:TEMP\test.txt -WhatIf:$false

Setting WhatIf in the manner used here might, for instance, be useful if a log file should be written even if other state-changing commands are ignored.

If the preference variable is set to true, all commands that support WhatIf act as if the parameter is set explicitly. A new value may be set for the variable, as shown in the following code:

$WhatIfPreference = $true

The WhatIf parameter and $WhatIfPreference preference variable take precedence over the Confirm parameter. For example, the WhatIf dialog is shown when running the following New-Item, but the Confirm prompt is not:

PS> $WhatIfPreference = $true
PS> New-Item NewFile.txt -Confirm
What if: Performing the operation "Create File" on target "Destination: C:\Users\whoami\AppData\Local\Temp\NewFile.txt".

Restarting the console will restore preference variables to their default values.

The behavior of Confirm and WhatIf is prescribed by PowerShell. Parameters such as Force and PassThru are commonly used in PowerShell but have less well-defined behavior.

Force parameter

The Force parameter is not one of the common parameters with behavior defined by PowerShell itself, but the parameter is frequently used.

Force has no fixed usage; the effect of using Force is a choice a command author must make. Help documentation should state the effect of using Force with a command. For example, the use of Force with Remove-Item is available:

Get-Help Remove-Item -Parameter Force

With the Force parameter, New-Item overwrites any existing file with the same path. When used with Remove-Item, the Force parameter allows the removal of files with Hidden or System attributes.

The error that is generated when attempting to delete a Hidden file is shown by running the following code:

Set-Location $env:TEMP
New-Item FileName.txt -Force
Set-ItemProperty FileName.txt -Name Attributes -Value Hidden
Remove-Item FileName.txt

When Remove-Item is run, the following error will be displayed:

Remove-Item: You do not have sufficient access rights to perform this operation or the item is hidden, system, or read only. RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand

Adding the Force parameter allows the operation to continue:

Remove-Item FileName.txt -Force

The Force parameter may be worth exploring if a command is prompting, and the prompts cannot be suppressed using the Confirm parameter or the ConfirmPreference variable.

PassThru parameter

The PassThru parameter, like Force, is frequently used, but the behavior of the parameter is not defined by PowerShell. However, PassThru tends to have predictable behavior.

The PassThru parameter is typically used with commands that do not normally generate output and is used to force the command to return the object it was working with.

For example, the Start-Process command does not normally return any output. If PassThru is used, it will return the process it created:

PS> Start-Process notepad -PassThru
 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
      9     1.98       6.70       0.05   22636   1 notepad

The PassThru parameter is therefore useful if more work is to be done with the object after the first command has finished.

For example, PassThru might be used with Set-Service, which ordinarily does not return output, allowing a service to be started immediately after another change:

Get-Service Audiosrv |
    Set-Service -StartupType Automatic -PassThru |

Parameters in PowerShell are a complex topic but are a vital part of working with the language.

Introduction to providers

A provider in PowerShell is a specialized interface to a service or dataset that presents items to the end user in the same style as a file system.

All operating systems include the following providers:

  • Alias: PowerShell aliases
  • Environment: Environment variables (for the process)
  • FileSystem: Files and folders
  • Function: Any functions in the session
  • Variable: Any variables in the session

Windows operating systems also include Windows-specific providers:

  • Registry: All loaded registry hives
  • Certificate: The LocalMachine and CurrentUser certificate stores
  • WSMan: Windows remoting configuration

Several modules, such as the ActiveDirectory and WebAdministration modules, add service-specific providers when imported.

A longer description of Providers can be seen by viewing the about file:

Get-Help about_Providers

The available providers can be viewed in the current PowerShell session by running Get-PSProvider, as shown in the following example:

PS> Get-PSProvider
Name           Capabilities                       Drives
----           ------------                       ------
Registry       ShouldProcess, Transactions        {HKLM, HKCU}
Alias          ShouldProcess                      {Alias}
Environment    ShouldProcess                      {Env}
FileSystem     Filter, ShouldProcess, Credentials {C, D}
Function       ShouldProcess                      {Function}
Variable       ShouldProcess                      {Variable}
Certificate    ShouldProcess                      {Cert}
WSMan          Credentials                        {WSMan}

Each of the previous providers has a help file associated with it. In PowerShell, the help files are named about_<ProviderName>_Provider; for example:

Get-Help -Name about_Certificate_Provider

A list of all help files for providers in PowerShell 7 can be seen by running the following command:

Get-Help -Name About_*_Provider

In Windows PowerShell, the help files have a special category and are accessed by name, for example:

Get-Help -Name Certificate -Category Provider

Or, the provider help files can be listed by category:

Get-Help -Category Provider

The provider-specific help documents describe the additional parameters added to *-Item and *-ChildItem, as well as Test-Path, Get-Content, Set-Content, Add-Content, Get-Acl, Set-Acl, and so on.

Provider-specific parameters, when added to the preceding commands, allow provider-specific values for filtering, making changes to existing items, and creating new items.

PowerShell offers tab completion for parameters when the Path parameter has been defined. For example, entering the following partial command and then pressing Tab will cycle through the parameters available to the certificate provider:

Get-ChildItem -Path cert:\LocalMachine\Root -

For example, pressing Tab several times after the hyphen is entered offers up the CodeSigningCert parameter.

The items within a provider can be accessed by following the name of a provider with two colons. For example, the content of the variable provider can be shown as follows:

Get-ChildItem variable::

The same approach can be used to view the top-level items available in the Registry provider on Windows:

Get-ChildItem registry::

Child items can be accessed by adding a name; for example, a variable:

Get-Item variable::true

The preceding command is equivalent to running Get-Variable true.

The FileSystem provider returns an error when attempting to access FileSystem:: without specifying a path. A child item must be specified, for example:

Get-ChildItem FileSystem::C:\Windows

While it is possible to access providers directly using the preceding notation, several of the providers are given names and are presented in the same manner as a Windows disk drive.

Drives and providers

Drives are labels used to access data from providers by name. Drives are automatically made available for FileSystem based on the drive letters used for mounted partitions in Windows.

The output from Get-PSProvider in the previous section shows that each provider has one or more drives associated with it.

Alternatively, the list of drives can be seen using Get-PSDrive, as shown in the following example:

PS> Get-PSDrive
Name     Used (GB) Free (GB) Provider       Root
----     --------- --------- --------       ----
Alias                        Alias
C            89.13    111.64 FileSystem     C:\
Cert                         Certificate    \
D             0.45     21.86 FileSystem     D:\
Env                          Environment
Function                     Function
HKCU                         Registry       HKEY_CURRENT_USER
HKLM                         Registry       HKEY_LOCAL_MACHINE
Variable                     Variable
WSMan                        WSMan

As providers present data in a similar manner to a file system, accessing a provider is like working with a disk drive. This example shows how Get-ChildItem changes when exploring the Cert drive. The first few certificates are shown:

PS C:\> Set-Location Cert:\LocalMachine\Root
PS Cert:\LocalMachine\Root> Get-ChildItem
 Directory: Microsoft.PowerShell.Security\Certificate::LocalMachine\Root
Thumbprint                                  Subject
----------                                  -------
CDD4EEAE6000AC7F40C3802C171E30148030C072    CN=Microsoft Root Certif...
BE36A4562FB2EE05DBB3D32323ADF445084ED656    CN=Thawte Timestamping C...
A43489159A520F0D93D032CCAF37E7FE20A8B419    CN=Microsoft Root Author...

By default, drives are available for the current user, HKEY_CURRENT_USER (HKCU), and local machine, HKEY_LOCAL_MACHINE (HKLM), registry hives.

A new drive named HKCC might be created for HKEY_CURRENT_CONFIG with the following command:

New-PSDrive HKCC -PSProvider Registry -Root HKEY_CURRENT_CONFIG

After running the preceding command, a new drive may be used to view the content of the hive, as demonstrated by the following example:

PS C:\> Get-ChildItem HKCC:
Name                           Property
----                           --------

Functions for drive letters

Running C: or D: in the PowerShell console changes to a new drive letter. This is possible because C: is a function that calls the Set-Location command. This can be seen by looking at the definition of one of the functions:

(Get-Command C:).Definition

Every letter of the alphabet (A to Z) has a predefined function (Get-Command *:).

Set-Location must be explicitly used to change to any other drive, for example:

Set-Location HKCU:

Providers are an important part of PowerShell, especially the FileSystem provider. Providers are explored in greater detail in Chapter 10, Files, Folders, and the Registry.

Introduction to splatting

Splatting is a way of defining the parameters of a command before calling it. This is an important and often underrated technique that the PowerShell team added to PowerShell 2.

Splatting is often used to solve three potential problems in a script:

  • Long lines caused by commands that need many parameters
  • Conditional use of parameters
  • Repetition of parameters across several commands

Individual parameters are written in a hashtable (@{}), and then the @ symbol is used to tell PowerShell that the content of the hashtable should be read as parameters.

This example supplies the Name parameter for the Get-Process command, and is normally written as Get-Process -Name explorer:

$getProcess = @{
    Name = 'explorer'
Get-Process @getProcess

In this example, getProcess is used as the name of the variable for the hashtable. The name is arbitrary; any variable name can be used.

Splatting can be used with cmdlets, functions, and scripts. Splatting can be used when the call operator is present, for example:

$getProcess = @{
    Name = 'explorer'
& 'Get-Process' @getProcess

The ability to use splatting with the call operator is useful if the command name itself is held in a variable.

The uses of splatting are explored in the following sections.

Splatting to avoid long lines

The benefit of splatting is most obvious when working with commands that expect a larger number of parameters.

This first example uses the module ScheduledTasks to create a basic task that runs once a day at midnight:

$taskAction = New-ScheduledTaskAction -Execute pwsh.exe -Argument 'Write-Host "hello world"'
$taskTrigger = New-ScheduledTaskTrigger -Daily -At '00:00:00'
Register-ScheduledTask -TaskName 'TaskName' -Action $taskAction -Trigger $taskTrigger -RunLevel 'Limited' -Description 'This line is too long to read'

Each of the commands is spread out over multiple lines; it is hard to see where one ends and the next begins.

Commands can also be spread out using a backtick, the escape character in PowerShell, as shown here:

$taskAction = New-ScheduledTaskAction `
    -Execute pwsh.exe `
    -Argument 'Write-Host "hello world"'
$taskTrigger = New-ScheduledTaskTrigger `
    -Daily `
    -At '00:00:00'
Register-ScheduledTask `
    -TaskName 'TaskName' `
    -Action $taskAction `
    -Trigger $taskTrigger `
    -RunLevel 'Limited' `
    -Description 'This line is too long to read'

This approach is relatively common, but it is fragile. It is easy to miss a backtick from the end-of-line, or to accidentally add a space after a backtick character. Both break continuation and the command executes but with an incomplete set of parameters; afterward, an error may be displayed, or a prompt may be shown, depending on the parameter (or parameters) it missed.

This problem is shown in the following screenshot, where a space character has been accidentally included after a backtick following the Daily switch parameter:

Figure 1.6: Space after the escape character

Splatting provides a neater, generally easier-to-read, and more robust alternative. The following example shows one possible way to tackle these commands when using splatting:

$newTaskAction = @{
    Execute = 'pwsh.exe'
    Argument = 'Write-Host "hello world"'
$newTaskTrigger = @{
    Daily = $true
    At    = '00:00:00'
$registerTask = @{
    TaskName    = 'TaskName'
    Action      = New-ScheduledTaskAction @newTaskAction
    Trigger     = New-ScheduledTaskTrigger @newTaskTrigger
    RunLevel    = 'Limited'
    Description = 'Splatting is easy to read'
Register-ScheduledTask @registerTask

Switch parameters may be treated as if they are Boolean when splatting.

The Daily parameter that was defined in the previous example is a switch parameter.

The same approach applies to Confirm, Force, WhatIf, Verbose, and so on.

Conditional use of parameters

Conditional use of parameters is one of the most important ways in which splatting can help.

If a command must be run and the parameters for a command can change based on user input or other circumstances, then it may be tempting to repeat the entire command. For example, a Credential parameter might be conditionally used.

The command may be repeated entirely based on there being a value for the Credential variable:

if ($Credential) {
    Get-ADUser 'Enabled -eq $true' -Credential $Credential
} else {
    Get-ADUser 'Enabled -eq $true'

The disadvantage of this approach is that any change to the command must be repeated in the second version.

Alternatively, a splatting variable may be used, and the Credential parameter added only when it is needed:

$params = @{}
if ($Credential) {
    $params['Credential'] = $Credential
Get-ADUser 'Enabled -eq $true' @params

Using splatting in this manner ensures only one version of the command must be maintained, reducing the risk of introducing a bug when making changes.

Splatting to avoid repetition

Splatting may be used to avoid repetition when a parameter must be optionally passed on to several different commands. It is possible to splat more than one set of parameters.

In this example, the ComputerName and Credential parameters are used by two different commands:

# Parameters used to authenticate remote connections
$remoteParams = @{
    Credential   = Get-Credential
    ComputerName = $env:COMPUTERNAME
# Parameters which are specific to Test-WSMan
$testWSMan = @{
    Authentication = 'Default'
    ErrorAction    = 'SilentlyContinue'
# By default, do not pass any extra parameters to New-CimSession
$newCimSession = @{}
if (-not (Test-WSMan @testWSMan @remoteParams)) {
    # If WSMan fails, use DCOM (RPC over TCP) to connect
    $newCimSession['SessionOption'] = New-CimSessionOption -Protocol Dcom
# Parameters to pass to Get-CimInstance
$getCimInstance = @{
    ClassName  = 'Win32_Service'
    CimSession = New-CimSession @newCimSession @remoteParams
Get-CimInstance @getCimInstance

This example takes advantage of several features:

  • It is possible to splat no parameters using an empty hashtable (@{}) when all the parameters are conditionally added.
  • It is possible to test conditions and dynamically add parameters at runtime (if needed).
  • It is possible to splat more than one set of parameters into a command.

As the preceding example shows, it is possible to dynamically choose the parameters that are passed to a command without having to write the command in full more than once in a script.

Splatting and positional parameters

It is possible, although rare and inadvisable in production scripts, to splat positional parameters; that is, to splat a parameter without stating a parameter name.

This can be seen with the Rename-Item command, which has two positional parameters: Path and NewName. Rename-Item may be run as follows:

Rename-Item oldname.txt newname.txt

An array to splat these positional parameters looks as follows:

$renameItem = 'oldname.txt', 'newname.txt'
Rename-Item @renameItem

A splatting variable with positional parameters may be used with executable files (.exe files), although it is often difficult to see any difference between splatting and using a normal variable. For example, both of the following commands execute in the same way:

$argumentList = '/t', 2
timeout.exe $argumentList
timeout.exe @argumentList

Splatting is a powerful technique and can be used to make code more readable by reducing the line length or repetition.

When using splatting, string values in the hashtable must be quoted. Conversely, when using a parameter directly, it is often unnecessary. The parser is responsible for deciding how statements and expressions should be interpreted.

Parser modes

The parser in PowerShell is responsible for taking what is typed into the console, or what is written in a script, and turning it into something PowerShell can execute. The parser has two different modes that explain, for instance, why strings assigned to variables must be quoted, but strings as arguments for parameters only need quoting if the string contains a space.

The parser modes are different modes:

  • Argument mode
  • Expression mode

Mode switching allows PowerShell to correctly interpret arguments without needing values to be quoted. In the following example, the argument for the Name parameter only needs quoting if the name contains spaces:

Get-Process -Name pwsh

The parser is running in Argument mode at the point the pwsh value is used and therefore literal text is treated as a value, not something to be executed.

This means that, in the following example, the second command is interpreted as a string and not executed:

Set-Content -Path commands.txt -Value 'Get-ChildItem', 'Get-Item'
Get-Command -Name Get-Content commands.txt

The second command in the preceding code therefore does not do anything.

To execute the Get-Content command, the argument must be enclosed in parentheses:

Set-Content -Path commands.txt -Value 'Get-ChildItem', 'Get-Item'
Get-Command -Name (Get-Content commands.txt)

The code in parentheses is executed, and the parser is in Expression mode.

Another example of this can be seen when using an enumeration value. An enumeration is a list of constants described by a .NET type. Enumerations are explored in Chapter 7, Working with .NET:

PS> Get-Date [DayOfWeek]::Monday
Get-Date: Cannot bind parameter 'Date'. Cannot convert value "[DayOfWeek]::Monday" to type "System.DateTime". Error: "String '[DayOfWeek]::Monday' was not recognized as a valid DateTime."

If the value for the argument is placed in parentheses, it will run first and expand the value. Once the value is expanded, Get-Date will be able to work with it:

Get-Date ([DayOfWeek]::Monday)

The help document, about_parsing, explores this topic in greater detail.

Experimental features

PowerShell 7 uses experimental features to make some new functionality available, which are not yet considered to be mainstream features. Features may be added to a later release of PowerShell, or discarded if they are not successful.

Three commands are available for working with experimental features:

  • Enable-ExperimentalFeature
  • Disable-ExperimentalFeature
  • Get-ExperimentalFeature

Get-ExperimentalFeature can be used to view the available features. The list of features changes depending on the version of PowerShell. The following list has been taken from PowerShell 7.3.3.

PS> Get-ExperimentalFeature
Name                                Enabled Source  Description
----                                ------- ------  -----------
PSCommandNotFoundSuggestion         False PSEngine  Recommend…
PSLoadAssemblyFromNativeCode        False PSEngine  Expose an API…
PSNativeCommandErrorActionPreferen… False PSEngine  Native comman…
PSSubsystemPluginModel              False PSEngine  A plugin mode…

In addition to the output shown here, each feature has a description. Format-Table can be used to view these descriptions:

Get-ExperimentalFeature | Format-Table Name, Description -Wrap

The use of these commands is described in the About_Experimental_Features help file.

If an experimental feature is enabled, PowerShell must be restarted for us to use the feature. For example, PSCommandNotFoundSuggestion can be enabled:

Enable-ExperimentalFeature -Name PSCommandNotFoundSuggestion

Once enabled, if a command is spelled incorrectly in the console, PowerShell will suggest possible command names alongside the error message:

PS> Get-Procss
Get-Procss: The term 'Get-Procss' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
Suggestion [4,General]: The most similar commands are: Get-Process, Wait-Process, Get-Host, Get-DbaProcess.

If the feature is no longer wanted, it can be disabled again:

Disable-ExperimentalFeature -Name PSCommandNotFoundSuggestion

In the past, several experimental features have become permanent features in PowerShell.


This chapter contained several foundational topics for PowerShell, starting with picking an editor, using help content, and command discovery.

The ability to use the help system and discover commands is vital, regardless of skill level. The availability of help content in the shell allows new commands to be quickly incorporated and used.

Naming plays an important role in PowerShell. Strict use of a reasonably small set of verbs greatly enhances discovery and reasonable assumptions can be made about a command before reaching for help content. PowerShell tends to use longer and more descriptive command names compared with other scripting languages.

Once a command has been found, it is important to understand how to use the help content and the parameters a command offers to use it effectively.

Providers allow access to data in a similar manner to using a file system. Providers play an important role in PowerShell and are explored again later in this book when exploring the file system and registry. Providers are explored in greater detail in Chapter 10, Files, Folders, and the Registry.

Splatting was introduced and will be used repeatedly throughout this book. In the context of this book, it is primarily used to reduce line length. Splatting is an incredibly useful technique when scripting. The ability to conditionally use parameters without repeating code reduces complexity and the chance of introducing bugs.

The parser was introduced to explain command syntax, when values must be quoted, and when parentheses are required. The parser is complex and the examples in about_parsing should be reviewed.

Finally, PowerShell 6 introduced the idea of experimental features. This continues into PowerShell 7. Features can be toggled on (or off again) before they become mainstream.

The next chapter moves on to exploring modules and snap-ins, allowing PowerShell users to go beyond the base set of commands and include content published by others.

Learn more on Discord

Read this book alongside other users, PowerShell experts, and the author himself. Ask questions, provide solutions to other readers, chat with the author via Ask Me Anything sessions, and much more.

Scan the QR code or visit the link to join the community.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Explores PowerShell as a programming language
  • Take advantage of the features built into the PowerShell language in day-to-day automation
  • Automation of complex tasks, data manipulation, and environment security


Mastering PowerShell Scripting, Fifth Edition, can help you overcome any fears and become proficient in navigating PowerShell's capabilities. This edition includes new chapters on debugging, troubleshooting, and creating GUIs. You will learn about the latest features of PowerShell 7.3, including working with parameters, objects, and .NET classes. The book covers basic and advanced topics, such as asynchronous processing, desired state configuration, managing large amounts of data, interacting with other services, and working with regular expressions and Windows Management Instrument (WMI). Discover how to efficiently use PowerShell's automation features and error-handling techniques for more complex scripts and filters. Starting with foundational knowledge, this extensive guide progresses to advanced concepts like using complex scripts and filters, asynchronous processing, desired state configuration, debugging, and error-handling techniques. You will learn how to effectively handle large data sets and interact with external services using PowerShell 7.3. Additionally, you'll discover how to fully utilize PowerShell's automation capabilities, including parsing data, manipulating regular expressions, and working with WMI using various methods.

What you will learn

Create scripts that can be run on different systems PowerShell is highly extensible and can integrate with other programming languages Discover the powerful command-line interface that enables users to perform various operations with ease Create reusable scripts and functions in PowerShell Utilize PowerShell for various purposes, including system administration, automation, and data processing Integrate PowerShell with other technologies such as .NET, COM, and WMI Work with common data formats such as XML, JSON, and CSV in PowerShell Create custom PowerShell modules and cmdlets to extend its functionality

Product Details

Country selected

Publication date : May 24, 2024
Length 826 pages
Edition : 5th Edition
Language : English
ISBN-13 : 9781805120278
Languages :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon AI Assistant (beta) to help accelerate your learning
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details

Publication date : May 24, 2024
Length 826 pages
Edition : 5th Edition
Language : English
ISBN-13 : 9781805120278
Languages :

Table of Contents

23 Chapters
Preface Chevron down icon Chevron up icon
1. Introduction to PowerShell Chevron down icon Chevron up icon
2. Modules Chevron down icon Chevron up icon
3. Variables, Arrays, and Hashtables Chevron down icon Chevron up icon
4. Working with Objects in PowerShell Chevron down icon Chevron up icon
5. Operators Chevron down icon Chevron up icon
6. Conditional Statements and Loops Chevron down icon Chevron up icon
7. Working with .NET Chevron down icon Chevron up icon
8. Files, Folders, and the Registry Chevron down icon Chevron up icon
9. Windows Management Instrumentation Chevron down icon Chevron up icon
10. Working with HTML, XML, and JSON Chevron down icon Chevron up icon
11. Web Requests and Web Services Chevron down icon Chevron up icon
12. Remoting and Remote Management Chevron down icon Chevron up icon
13. Asynchronous Processing Chevron down icon Chevron up icon
14. Graphical User Interfaces Chevron down icon Chevron up icon
15. Scripts, Functions, and Script Blocks Chevron down icon Chevron up icon
16. Parameters, Validation, and Dynamic Parameters Chevron down icon Chevron up icon
17. Classes and Enumerations Chevron down icon Chevron up icon
18. Testing Chevron down icon Chevron up icon
19. Error Handling Chevron down icon Chevron up icon
20. Debugging Chevron down icon Chevron up icon
21. Other Books You May Enjoy Chevron down icon Chevron up icon
22. Index Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Empty star icon Empty star icon Empty star icon Empty star icon Empty star icon 0
(0 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Top Reviews
N/A Jun 28, 2024
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Mr. Dent has created what is easily, hands-down the single best resource for all things PowerShell. Well done, sir!
Feefo Verified review Feefo image
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial


How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to
  • To contact us directly if a problem is not resolved, use
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.