Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Mastering PowerShell Scripting

You're reading from   Mastering PowerShell Scripting Automate repetitive tasks and simplify complex administrative tasks using PowerShell

Arrow left icon
Product type Paperback
Published in May 2024
Publisher Packt
ISBN-13 9781805120278
Length 826 pages
Edition 5th Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Chris Dent Chris Dent
Author Profile Icon Chris Dent
Chris Dent
Arrow right icon
View More author details
Toc

Table of Contents (23) Chapters Close

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

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.

Parameters

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.

SYNTAX
    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:

SYNTAX
    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:

SYNTAX
    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:

SYNTAX
    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:

SYNTAX
    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:

SYNTAX
    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:

SYNTAX
    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: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_commonparameters.

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
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
  
Confirm
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
High

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 |
    Start-Service

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

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime