Mastering Windows PowerShell Scripting - Third Edition

5 (1 reviews total)
By Chris Dent
    Advance your knowledge in tech with a Packt subscription

  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Introduction to PowerShell

About this book

PowerShell scripts offer a handy way to automate various chores, however working effectively with these scripts can be a difficult task.

This comprehensive guide starts with the fundamentals before moving on to advanced-level topics to help you become a PowerShell Core 6.0 expert. The first module, PowerShell Core 6.0 Fundamentals, begins with the new features of PowerShell Core 6.0, installing it on Linux, and working with parameters, objects and .NET classes from within PowerShell Core 6.0. As you make your way through the chapters, you'll see how to efficiently manage large amounts of data and interact with other services using PowerShell Core 6.0. You'll be able to make the most of PowerShell Core 6.0's powerful automation feature, where you will have different methods available to parse data and manipulate regular expressions and Windows Management Instrumentation (WMI). After having explored automation, you will enter the extending PowerShell Core 6.0 module, covering asynchronous processing and desired state configuration. In the last module, you will learn to extend PowerShell Core 6.0 using advanced scripts and filters, and also debug issues along with working on error handling techniques.

By the end of this book, you will be an expert in scripting with PowerShell Core 6.0.

Publication date:
February 2019


Chapter 1. Introduction to PowerShell

PowerShell has reached a point where it has split into Windows PowerShell and PowerShell Core. Windows PowerShell accounts for versions up to, and including, PowerShell 5.1. Windows PowerShell is based on the .NET full framework. PowerShell Core accounts for version 6 and over and is based on the .NET core framework.

The future of PowerShell is in PowerShell Core; it opens up cross-platform scripting with PowerShell, that is, support for Linux and macOS.

As well as the change to .NET, there are an increasing number of differences between Windows PowerShell and PowerShell Core that must be accounted for.

The differences between Windows PowerShell and PowerShell Core will be highlighted throughout this book.

This book is split into a number of sections. Much of this book is intended to act as a reference. We will cover the following topics in this book:

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

In the first section of this book, while exploring the PowerShell fundamentals, we will look at the use of language and cover as many building blocks as possible.

In this chapter, we will briefly look at a number of short, diverse topics:

  • What is PowerShell?
  • PowerShell editors
  • Getting help
  • Command naming
  • Command discovery
  • Parameters and parameter sets
  • Introduction to providers
  • Introduction to splatting

Technical requirements

This chapter makes use of the following on the Windows platform:

  • Windows PowerShell 5
  • PowerShell Core 6.1

What is PowerShell?

PowerShell is a mixture of a command line, 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 is an explorer's scripting language. With built-in help, command discovery, and with access to much of the .NET framework, it is possible to dig down through the layers.

This book is based on PowerShell Core 6.1 with references to PowerShell 5.1; some of the features that are discussed in this book may not be available in the earlier versions of PowerShell.

PowerShell Core may be installed side by side with Windows PowerShell. Preview versions of PowerShell Core can often be installed side by side with full releases of PowerShell Core.


PowerShell editors

While it is possible to write for PowerShell 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.

Specialized PowerShell editors such as Visual Studio Code (VS Code), PowerShell Studio, and PowerShell ISE offer automatic completion (IntelliSense), which reduces the amount of cross-referencing 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.

PowerShell ISE is not planned to be released to support PowerShell 6 at this time. VS Code is the most commonly recommended editor for PowerShell. VS Code is a free open source editor that was published by Microsoft VS Code and may be downloaded from

The PowerShell extension should be installed, and other extensions may be found on the marketplace:

VS Code provides support for PowerShell Core; the following screenshot shows how to change the version of PowerShell that's used when editing a script:


Getting help

Gaining confidence using the built-in help system is an important part of working with PowerShell. In PowerShell, help is extensive; authors can easily write their own help content when working with functions, scripts, and script modules.

A number of commands are available to interact with the help system, as follows:

  • Get-Help
  • Save-Help
  • Update-Help

Before exploring these commands, the concept of Updatable help should be discussed, as help may not be present on a system after installation.

Updatable help

Updatable help was introduced with PowerShell 3. It gives authors the option to store the most recent versions of their help documentation outside of PowerShell on web servers.


Which modules support updatable help?A list of modules that support updatable help may be viewed by running the following command: Get-Module -ListAvailable | Where-Object HelpInfoURI -like *.

Help for the core components of PowerShell is no longer a part of the Windows Management Framework package and must be downloaded before it can be viewed. The first time Get-Help is run, you will be prompted to update help.

If the previous prompt is accepted, PowerShell will attempt to download content for any module that supports updatable help.

Computers with no internet access or computers behind a restrictive proxy server may not be able to download the help content directly. The Save-Help command, which will be discussed later in this section, may be used to work around this 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

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

Get-Help about_Updatable_Help

The Get-Help command

Without any arguments or parameters, Get-Help will show 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

 Windows PowerShell Help System

 Displays help about Windows PowerShell cmdlets and concepts. 

 Windows PowerShell Help describes Windows PowerShell cmdlets,


The help content can be long The help content, in most cases, will not fit on a single screen. The helpcommand 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, in Windows PowerShell, but not PowerShell Core, 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 command may be viewed as follows:

Get-Help <CommandName>

Let's look at an example:

Get-Help Get-Variable

If a help document includes an online version link, it may be opened in a browser by using this:

Get-Help Get-Command -Online

The help content is broken down into a number of visible sections: name, synopsis, syntax, description, related links, and remarks. Syntax is covered in the following section in more detail as it is the most complex.


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

A command that has more than one parameter set is displayed as follows:

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

    Get-Process [-ComputerName [<String[]>]] [-FileVersionInfo]
    [-Module] -InputObject <Process[]> [<CommonParameters>]

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

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

Get-Process may be run without any parameters at all, or it may be run with a value only and no parameter name, or it may include the parameter name as well as the value. Each of the following examples is a valid use of Get-Process:

Get-Process powershell 
Get-Process -Name powershell


Get-Command can show syntaxGet-Command may be used to quickly view the syntax for a command, for example, by running the following code: Get-Command Get-Variable -Syntax.

Later in this chapter, we will take a more detailed look at the different parameters and how they might be used.


The examples section of help is often invaluable. In some cases, a command is sufficiently complex to require 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.

Examples for a command may be requested using Get-Help, as shown in the following example:

Get-Help Get-Process -Examples

It is common for a command to list several examples of its use, especially if the command has more than one parameter set.


Help for specific parameters may be requested as follows:

Get-Help Get-Command -Parameter <ParameterName>

This option 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 quickly 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 

Detailed and full switches

The Detailed switch parameter asks Get-Help to return the most help content. This adds information about each parameter and the set of examples to name, synopsis, syntax, and description. Related links are excluded when using this parameter.

The Detailed parameter is used as follows:

Get-Help Get-Process -Detailed

Using a Full switch adds more technical details (compared to using the Detailed parameter). Inputs, outputs, notes, and related links are added to those that are seen using Detailed. For example, the sections detailing input and output types from Get-Process may be extracted from the full help document:

PS> Get-Help Get-Process –Full

        You can pipe a process object to Get-Process.

    System.Diagnostics.Process, System.Diagnotics.FileVersionInfo, System.Diagnostics.ProcessModule

        By default, Get-Process returns a System.Diagnostics.Process 
        object. If you use the FileVersionInfo parameter, it returns a
        System.Diagnotics.FileVersionInfo object. If you use the Module
        parameter (without the FileVersionInfo parameter), it returns a


The Save-Help command can be used with modules that support updatable help. It saves help content for modules to a folder; for example, the help content for the DnsClient module can be saved to C:\PSHelp (the directory must already exist):

Save-Help -DestinationPath C:\PSHelp -Module DnsClient

Alternatively, the help content for all modules may be saved as follows:

Save-Help -DestinationPath C:\PSHelp

The process creates an XML formatted HelpInfo file that holds the source of the help content and a CAB (cabinet) file that's named after the module and culture.

Opening the CAB file shows that it contains a number of XML formatted help files, as shown in the following screenshot:

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


The Update-Help command can perform two tasks:

  • Update help files from the internet
  • Import previously saved help files


To update help from the internet, Update-Help may be run without any parameters:



Administrator rights are required Updating help for some modules will require administrative rights (run as administrator). This applies to modules that are stored in protected areas of the filesystem, such as those in $PSHost (%SystemRoot%\System32\WindowsPowerShell\v1.0) or under program files.

When updating help information from the internet, by default, Update-Help will not download help content more than once every 24 hours. This restriction is documented in the help command and may be seen in action when using the Verbose switch:

PS> Update-Help -Module DnsClient -Verbose
VERBOSE: Help was not updated for the module DnsClient, because the Update-Help command was run on this computer within the last 24 hours. 
To update help again, add the Force parameter to your command.

As described in the preceding message, using the Force switch parameter will ignore the time restriction. Importing help from a set of saved files uses the SourcePath parameter:

Update-Help -SourcePath C:\temp

The following error message may be generated when attempting to import help from another culture:

PS> Update-Help -SourcePath C:\Temp -Module DnsClient
Update-Help : Failed to update Help for the module(s) 'DnsClient' with UIculture(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.
At line:1 char:1
+ Update-Help -SourcePath C:\Temp -Module DnsClient -Verbose -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [Update-Help], Exception
    + FullyQualifiedErrorId : UnableToRetrieveHelpInfoXml,Microsoft.PowerShell.Commands.UpdateHelpCommand 

The culture of the computer in question is set to en-GB (Get-UICulture), but the help files are for en-US.

It is possible to work around this problem with the UICulture parameter for Update-Help, as follows:

Update-Help -SourcePath C:\Temp -Module DnsClient -UICulture en-US

About help files

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


PowerShell Core: Where is About? The PowerShell Core help files are not available as I write this at the time of writing. The examples that are shown here can only be applied to PowerShell 5.1 or lower.

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

Get-Help -Category HelpFile

These files cover a huge variety of topics from aliases, to modules, to WMI:

Name                                  Category Synopsis 
----                                  -------- -------- 
about_Aliases HelpFile                SHORT   DESCRIPTION 
about_Arithmetic_Operators HelpFile   SHORT   DESCRIPTION 
about_Arrays HelpFile                 SHORT   DESCRIPTION 
about_Assignment_Operators HelpFile   SHORT   DESCRIPTION 
about_Automatic_Variables HelpFile    SHORT   DESCRIPTION 
about_Break HelpFile                  SHORT   DESCRIPTION 
about_Classes HelpFile                SHORT   DESCRIPTION 
about_Command_Precedence HelpFile     SHORT   DESCRIPTION 
about_Command_Syntax HelpFile         SHORT   DESCRIPTION 
about_Comment_Based_Help HelpFile     SHORT   DESCRIPTION 
about_CommonParameters HelpFile       SHORT   DESCRIPTION 
about_Comparison_Operators HelpFile   SHORT   DESCRIPTION 
about_Continue HelpFile               SHORT   DESCRIPTION 
about_Core_Commands HelpFile          SHORT   DESCRIPTION 
about_Data_Sections HelpFile          SHORT   DESCRIPTION 

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 you to make educated guesses so that there is little need to memorize long lists of commands.


The list of verbs is maintained by Microsoft. This formal approach to naming commands greatly assists in discovery.

Verbs are words such as Add, Get, Set, and New. In addition to these, we have ConvertFrom and ConvertTo.

The list of verbs that are available in PowerShell can be accessed as follows:


Each verb has a group, such as data, life cycle, or 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.


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

It is possible to use verbs other than the approved list. However, if a command using an unapproved verb is part of a module, a warning will be shown every time the module is imported.


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, or Get-Help, or more than one word, as seen with Get-ChildItem, Invoke-WebRequest, or Send-MailMessage.

Finding commands

The verb-noun pairing can make it a lot easier to find commands (without resorting to search engines).

For example, if we want to list firewall rules and we already know of the NetSecurity module that's available in Windows PowerShell, we can run the following command, which shows the Get commands in that module:

PS> Get-Command Get-*Firewall* -Module NetSecurity

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 

From the previous list, Get-NetFirewallRule closely matches the requirement (to see a list of firewall rules) and should be explored.

Taking a broader approach, if the module was not known, we might still be able to guess by searching for commands containing specific nouns, for example, commands to get existing items that mention a firewall:

Get-Command Get-*Firewall*

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


NetSecurity and PowerShell Core The NetSecurity module is not available using PowerShell Core by default. Using modules such as NetSecurity in PowerShell Core is discussed in Chapter 2, Modules and Snap-ins.


An alias in PowerShell is an alternate name for a command. A command may have more than one alias.

The list of aliases may be viewed by using Get-Alias, as shown in the following example:

PS> Get-Alias

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

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

Get-Alias dir

It can also be used to find the aliases for a command name:

Get-Alias -Definition 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
  • man for help (and then Get-Help)

An alias does not change how a command is used. There is no practical difference between the following two commands:

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

New aliases are created with the New-Alias command; for example, we might choose to create an alias named grep for Select-String:

New-Alias grep -Value Select-String

Each alias exists until the PowerShell session is closed.


More information is available about aliases in the help file, which may be viewed using the following command: Get-Help about_Aliases.


Parameters and parameter sets

As we saw 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, we can see many different approaches to different parameters.

Optional parameters

Optional parameters are surrounded by square brackets. This denotes an optional parameter that requires a value when used:

    Get-Process [-ComputerName <String[]>] ...

In this case, if a value for a parameter is to be specified, the name of the parameter must also be specified, as shown in the following example:

Get-Process -ComputerName somecomputer

Optional positional parameters

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

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

In this example, we may use either of the following:

Get-Process -Name powershell 
Get-Process powershell

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 written 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"'

Mandatory positional parameters

Parameters that are mandatory and accept values based on position are written as follows:

    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. A command with more than one mandatory positional parameter may appear as follows:

    Add-Member [-NotePropertyName] <String> [-NotePropertyValue] <Object> ...

In this case, the command may be called as follows:

Add-Member -NotePropertyName Name -NotePropertyValue "value" 
Add-Member -NotePropertyValue "value" -NotePropertyName Name 
Add-Member Name -NotePropertyValue "value" 
Add-Member Name "value"

Switch parameters

Switch parameters have no arguments (values); the presence of a switch parameter is sufficient. For example, Recurse is a switch parameter for Get-ChildItem:

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

As with the other types of parameters, optional use is denoted by square brackets. Switch parameters, by default, are false (not set). If a switch parameter is true (set) by default, it is possible to set the value to false using the notation, as shown in the following code:

Get-ChildItem -Recurse:$false

In the case of Get-ChildItem, this does nothing; this technique is most widely used with the Confirm switch parameter, which we will discuss later in this chapter.

Common parameters

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

    Get-Process ... [<CommonParameters>]

These common parameters are documented inside PowerShell:

Get-Help about_CommonParameters

These parameters let you control some of the standardized functionality PowerShell provides, such as verbose output and actions to take when errors occur.

For example, Stop-Process does not explicitly state that it has a Verbose parameter, but as 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 verboseJust because a command supports a set of common parameters does not mean it must use them; for example, Get-Process supports the Verbose parameter, yet it does not write any verbose output.

Parameter values

Value types of arguments (the type of value expected by a parameter) are enclosed in angular brackets, as shown in the following example:


If a value is in the <string>form, a single value is expected. If the value is in the <string[]>form, an array (or list) of values is expected.

For example, Get-CimInstance accepts a single value only for the ClassName parameter:

    Get-CimInstance [-ClassName] <String> ...

The command may be called as follows:

Get-CimInstance -ClassName Win32_OperatingSystem

In comparison, Get-Process accepts multiple values for the Name parameter:

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

Get-Process may be called as follows:

Get-Process -Name powershell, explorer, smss 

Parameter sets

Many of the commands in PowerShell have more than one parameter set. This was seen while looking at the syntax section of help; for example, Stop-Process 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>] 

Each parameter set must have one or more parameters unique to that set. This allows each set to be distinguished from the other. In the previous example, Id, InputObject, and Name are used as differentiators.

The first parameter set expects a process ID, and this ID may be supplied with the parameter name or based on position; for example, both of these commands close the current PowerShell console:

Stop-Process -Id $PID 
Stop-Process $PID 

The second parameter set needs a value for InputObject. Again, this may be supplied as a positional parameter. In this case, it will be distinguished based on its type:

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


Pipeline inputGet-Help should help show which parameters accept pipeline input, and examples are likely to show how. If Get-Help is incomplete, Get-Command can be used to explore parameters:(Get-Command Stop-Process).Parameters.InputObject.Attributes.


Confirm, WhatIf, and Force

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

Confirm and WhatIf have associated preference variables. Preference variables have an about file, which may be viewed using the following command:

Get-Help about_Preference_Variables 

The Force parameter is not one of PowerShell's common parameters, that is, parameters that are automatically added by PowerShell itself.

Force is often seen in commands that might otherwise prompt for confirmation. There is no fixed use of the Force parameter. The effect of using Force is a choice a command developer must make. The Help documentation should state the effect of using Force, as is the case with the Remove-Item command in the following example:

Get-Help Remove-Item -Parameter Force 

Confirm parameter

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

PS> Set-Location $env:TEMP
PS> New-Item IMadeThisUp.txt -Force
PS> Remove-Item .\IMadeThisUp.txt -Confirm

Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\Users\whoami\AppData\Local\Temp\IMadeThisUp.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):

We have seen that a confirmation prompt may be forcefully requested in the previous example. In a similar manner, confirmation prompts may be suppressed; for example, the value of the Confirm parameter may be explicitly set to false, as shown in the following code:

Remove-Item .\IMadeThisUp.txt -Confirm:$false


There is more than one way of prompting There are two ways of requesting confirmation in PowerShell: Confirm and the associated ConfirmPreference; the variable only acts against one of these. Using the parameter or changing the variable will not suppress all prompts. For example, Remove-Item will always prompt if you attempt to delete a directory that is not empty without supplying the Recurse parameter.

This technique is useful for commands that prompt by default; for example, Clear-RecycleBin will prompt 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 will bypass the prompt and immediately empty the recycle bin:

Clear-RecycleBin -Confirm:$false 


Finding commands with a specific impact The following snippet will return a list of all commands that state they have a high impact:Get-Command -CommandType Cmdlet, Function | Where-Object {    $metadata = New-Object System.Management.Automation.CommandMetadata($_)    $metadata.ConfirmImpact -eq 'High'}


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

By default, the value of ConfirmPreference is High, as shown in the following code:

PS> $ConfirmPreference

By default, commands have a medium impact.


Finding ConfirmImpact In scripts and functions, the ConfirmImpact setting is part of the CmdletBinding attribute: [CmdletBinding(ConfirmImpact = 'High')]. If CmdletBinding or ConfirmImpact are not present, the impact is medium. The impact of a function or cmdlet may be viewed using the ConfirmImpact property of a command's metadata:New-Object System.Management.Automation.CommandMetadata(Get-Command Remove-Item).

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

A new value may be set by assigning it in the console; for example, it can be set to Low:

$ConfirmPreference = 'Low'  


ConfirmPreference and the Confirm parameter While ConfirmPreference may be set to None to suppress confirmation prompts, confirmation may still be explicitly requested. Let's look at an example:$ConfirmPreference = 'None'New-Item NewFile.txt -Confirm Since the Confirm parameter is supplied, the ConfirmPreference value within the scope of the command (New-Item) is Low, and therefore the prompt displays.


WhatIf parameter

The WhatIf parameter replaces the confirmation prompt with a simple statement that should state what would have been done, using Remove-Item as an example again:

PS> Set-Location $env:TEMP
PS> New-Item IMadeThisUp.txt -Force
PS> Remove-Item .\IMadeThisUp.txt -WhatIf

Are you sure you want to perform this action?
What If: Performing the operation "Remove File" on target "C:\Users\whoami\AppData\Local\Temp\IMadeThisUp.txt".

If both Confirm and WhatIf are used with a command, WhatIf takes precedence.

WhatIf may be unset on a per-command basis by supplying a value of false in the same manner as the Confirm parameter. Let's look at the following example:

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

The previous technique can be useful if a file (such as a log file) should be written to, irrespective of whether WhatIf is being used or not.


The WhatIfPreference variable holds a Boolean value (trueorfalse) and has a default value offalse.

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

$WhatIfPreference = $true 

The WhatIf preference variable takes precedence over the Confirm parameter. For example, the WhatIf dialog will be shown when running the followingNew-Item, but the Confirm prompt will not:

$WhatIfPreference = $true 
New-Item NewFile.txt -Confirm 

Force parameter

The Force parameter has a different purpose. With the Force parameter, New-Item will overwrite 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's generated when attempting to delete a Hidden file is shown in the following code:

PS> Set-Location $env:TEMP
PS> New-Item IMadeThisUp.txt -Force
PS> Set-ItemProperty .\IMadeThisUp.txt –Name Attributes –Value Hidden
PS> Remove-Item IMadeThisUp.txt

Remove-Item : Cannot remove item C:\Users\whoami\AppData\Local\Temp\IMadeThisUp.txt: You do not have sufficient access rights to perform this operation.
At line:1 char:1
+ Remove-Item .\IMadeThisUp.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : PermissionDenied: (C:\Users\uktpcd...IMadeThisUp.txt:FileInfo) [Remove-Item], IOException
 + FullyQualifiedErrorId : RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand

Adding the Force parameter allows the operation to continue without the error message:

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

Introduction to providers

Providers in PowerShell present access to data that is not normally easily accessible. There are providers for the filesystem, registry, certificate store, and so on. Each provider arranges data so that it resembles a filesystem.


PowerShell Core: What happened to provider help? PowerShell Core does not include Provider help files. Help may be viewed either online or in Windows PowerShell.

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

Get-Help about_Providers

The list of providers available in the current PowerShell session may be viewed 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. These can be accessed using the following code:

Get-Help -Name <ProviderName> -Category Provider

For example, the help file for the certificate provider may be viewed by running the following code:

Get-Help -Name Certificate -Category Provider

A list of all help files for providers may be seen by running the following code:

Get-Help -Category Provider

Drives using providers

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

Alternatively, you can see the list of drives (and the associated provider) using Get-PSDrive, as shown in the following code:

PS> Get-PSDrive

Name     Used (GB) Free (GB) Provider       Root
----     --------- --------- --------       ----
Alias                        Alias  
C 89.13      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 are presented as a filesystem, accessing a provider is similar to working with a drive. This example shows how Get-ChildItem changes when exploring the Cert drive:

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...

A similar approach may be taken to access the registry. By default, drives are available for the current user HKCU and local machine HKLM hives. Accessing HKEY_USERS is possible by adding a new drive with the following command:

New-PSDrive HKU -PSProvider Registry -Root HKEY_USERS 

After running the preceding command, a new drive may be used:

PS C:\> Get-ChildItem HKU:

    Hive: HKEY_USERS

Name                          Property 
----                          -------- 


Running HKCU or Cert: does not change the drive Running C: or D: in the PowerShell console changes to a new drive letter. This is possible because C: is a function that calls Set-Location: (Get-Command C:).Definition. Every letter of the alphabet (A to Z) has a predefined function (Get-Command*:) but the other drives (for example, Cert, HKCU, and so on) do not. Set-Location (or its alias cd) must be used to switch into these drives.

Using providers

As we saw previously, providers may be accessed in the same way as the filesystem. Commands we might traditionally think of as filesystem commands (such as Get-ChildItem, New and Remove-Item, Get and Set-Acl, and Get and Set-ItemProperty) can work with data presented by a provider.

The list of parameters for the filesystem commands changes depending on the provider. The affected parameters are detailed in the help files for individual providers.

If we look at the FileSystem provider help file (Get-Help FileSystem), we can see that Get-ChildItem has a file switch parameter that can be used to filter files only:

     -File <System.Management.Automation.SwitchParameter>
        Gets files. 

        The File parameter was introduced in Windows PowerShell 3.0.

        To get only files, use the File parameter and omit the 
        Directory parameter. To exclude files, use the Directory 
        parameter and omit the File parameter, or use the 
        Attributes parameter.

        Cmdlets Supported: Get-ChildItem 

Let's look at the following example:

Set-Location C: 
Get-ChildItem -File

Looking at the Certificate provider help file (Get-Help Certificate), a different set of parameters is available.


PowerShell Core: The certificate provider The parameters shown next have been removed from PowerShell Core but may return in time. In the meantime, the examples here are valid for Windows PowerShell.

For example, this excerpt shows the ExpiringInDays parameter for Get-ChildItem:

     -ExpiringInDays <System.Int32>
        Gets certificates that are expiring in or before 
        the specified number of days. Enter an integer. A   
        value of 0 (zero) gets certificates that have 

        This parameter is valid in all subdirectories of 
        the Certificate provider, but it is effective only 
        on certificates.

        This parameter was introduced in Windows 
        PowerShell 3.0.

        Cmdlets Supported: Get-ChildItem 

The previous parameter may be used to find the Root certificates expiring in the next two years, as shown in the following example:

Get-ChildItem Cert:\LocalMachine\Root -ExpiringInDays 730

Introduction to splatting

Splatting is a technique that was introduced all the way back in PowerShell 2. Splatting is a way of defining the parameters of a command before calling the command. This is an important and often underrated technique.

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 may be used with cmdlets, functions, and scripts. Splatting may be used when the call operator is present, for example:

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

Splatting to avoid escaped end-of-line

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

This first example uses the Windows PowerShell module ScheduledTasks to create a fairly 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'

It is possible to spread the command out, in an attempt to make it easier to read, by escaping the end-of-line character, for example:

$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'

The approach that's used here is relatively common, but it is fragile. It is easy to miss a tick from the end-of-line, or to accidentally add a space after a tick character. Both will break continuation, and the command will still execute but with an incomplete set of parameters; afterwards, 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 the Daily switch parameter:

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


What about switch parameters? 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 will apply to Confirm, Force, WhatIf, Verbose, and so on.

Splatting to avoid repetition

Splatting may be used to avoid repetition when a parameter must be optionally passed on to a number of 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.Add('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 a number of features:

  • It is possible to splat no parameters using an empty hashtable (@{})
  • It is possible to test conditions and dynamically add parameters at run time (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

So far, all of the parameters that have been used were given were names. It is possible, although rare, to splat positional parameters. This will be demonstrated using the Rename-Item command, which has two positional parameters: path and new name. It is possible to run Rename-Item as follows:

Rename-Item oldname.txt newname.txt

An array may be used to splat these positional parameters:

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


In this chapter, we explored the help system that's built into PowerShell. We took a brief look at syntax, examples, and parameters. We also looked at how help content may be moved between computers.

Command naming and discovery introduced how we might use the verb-noun pairing to discover commands that can be used. Aliases were introduced briefly.

Parameters and parameter sets were explored, as well as different types of parameters.

We took a basic look at providers and how they are used before taking a look at handling long command lines using splatting.

In Chapter 2, Modules and Snap-ins, we will explore the commands that are used to find, install, and load modules in PowerShell.

About the Author

  • Chris Dent

    Chris Dent is an automation specialist with a deep interest in the PowerShell language. Chris is often found lurking and answering questions about PowerShell in both the UK and virtual PowerShell user groups. Chris has been developing in PowerShell since 2007 and has released several modules over the years.

    Browse publications by this author

Latest Reviews

(1 reviews total)
It's OK for the beginner but at times it's get boring...

Recommended For You

Book Title
Access this book and the full library for FREE
Access now