PowerShell Scripting v7.3
PowerShell Scripting v7.3
Welcome to the PowerShell online documentation. This site contains cmdlet reference
for the
following versions of PowerShell:
The web page contains multiple elements that help you navigate the documentation.
Site level navigation - The site level navigation appears at the top of the page. It
contains
links to other content on the Microsoft Learn platform.
Related content navigation - The related content bar is immediately below the site
level
navigation. It contains links to content related to the current docuemntation
set, which is
PowerShell in this case.
Version selector - The version selector appears above the Table of Contents (TOC)
and
controls which version of the cmdlet reference appears in the TOC.
Table of Contents - The TOC on the left side of the page is divided into two
sections:
conceptual and reference. Notice the line between the Reference node of
the TOC. The
conceptual documents appear above the line. Reference content is
listed in Reference node
below the line.
Action buttons - The action buttons provide a way to add content to a collection,
provide
feedback, edit the content, or share the content with others.
PowerShell
$PSVersionTable.PSVersion
Output
5 1 22621 963
Finding articles
There are two ways to search for content in Docs. The simplest way is to use the filter
box under
the version selector. Just enter a word that appears in the title of an article.
The filter displays
a list of matching articles. You can also select the option to search the
entire site from that
list.
Downloading the documentation as a PDF
To download the documentation as a PDF, click the Download PDF button at the
bottom of the TOC.
If you are viewing a conceptual article, the Learn platform creates a PDF containing
all the
conceptual content for the selected version.
If you are viewing a reference article, the Learn platform creates a PDF containing
all the
reference content for the selected version.
PowerShell 3.0
PowerShell 4.0
PowerShell 5.0
PowerShell 6
PowerShell 7.0
PowerShell 7.1
PowerShell Workflows
PowerShell Web Access
What is PowerShell?
Article • 10/21/2022
Command-line Shell
PowerShell is a modern command shell that includes the best features of other popular
shells. Unlike
most shells that only accept and return text, PowerShell accepts and
returns .NET objects. The shell
includes the following features:
Scripting language
As a scripting language, PowerShell is commonly used for automating the management
of systems. It is
also used to build, test, and deploy solutions, often in CI/CD
environments. PowerShell is built on
the .NET Common Language Runtime (CLR). All
inputs and outputs are .NET objects. No need to parse
text output to extract information
from output. The PowerShell scripting language includes the
following features:
Automation platform
The extensible nature of PowerShell has enabled an ecosystem of PowerShell modules
to deploy and
manage almost any technology you work with. For example:
Microsoft
Azure
Windows
Exchange
SQL
Third-party
AWS
VMWare
Google Cloud
Configuration management
PowerShell Desired State Configuration (DSC) is a management framework in PowerShell
that
enables you to manage your enterprise infrastructure with configuration as code.
With DSC, you can:
Next steps
Getting started
Are you new to PowerShell and don't know where to start? Take a look at these
resources.
Installing PowerShell
PowerShell Bits tutorials
PowerShell 101
Microsoft Virtual Academy videos
PowerShell Learn modules
PowerShell in action
Take a look at how PowerShell is being used in different scenarios and on different
platforms.
What is a cmdlet?
Cmdlets are native PowerShell commands, not stand-alone executables. Cmdlets are
collected into
PowerShell modules that can be loaded on demand. Cmdlets can be
written in any compiled .NET
language or in the PowerShell scripting language itself.
Cmdlet names
PowerShell uses a Verb-Noun name pair to name cmdlets. For example, the Get-Command
cmdlet
included in PowerShell is used to get all the cmdlets that are registered in the
command shell. The
verb identifies the action that the cmdlet performs, and the noun
identifies the resource on which
the cmdlet performs its action.
Next steps
To learn more about PowerShell and how to find other cmdlets, see the PowerShell Bits
tutorial
Discover PowerShell.
For more information about creating your own cmdlets, see the following resources:
Script-based cmdlets
about_Functions_Advanced
about_Functions_CmdletBindingAttribute
about_Functions_Advanced_Methods
Cmdlet overview
Discover PowerShell
Article • 03/29/2023
The thing that makes PowerShell unique is that it accepts and returns .NET objects,
rather than
text. This feature makes it easier to connect different commands in a
pipeline.
There are many more areas of usage but the preceding list gives you a hint that
PowerShell has come
a long way.
PowerShell cmdlets
PowerShell comes with hundreds of preinstalled commands. PowerShell commands are
called cmdlets
(pronounced command-lets).
The name of each cmdlet consists of a Verb-Noun pair. For example, Get-Process . This
naming
convention makes it easier to understand what the cmdlet does. It also makes it
easier to find the
command you're looking for. When looking for a cmdlet to use, you
can filter on the verb or noun.
PowerShell includes cmdlets that help you discover PowerShell. Using these three
cmdlets, you can
discover what commands available, what they do, and what types they
operate on.
Get-Verb . Running this command returns a list of verbs that most commands
machine.
Get-Member . It operates on object based output and is able to discover what object,
properties
and methods are available for a command.
Get-Help . Invoking this command with the name of a command as an argument
displays a help page
describing various parts of a command.
Using these commands, you can discover almost anything you need to know about
PowerShell.
Verb
Verb is an important concept in PowerShell. It's a naming standard that most cmdlets
follow. It's
also a naming standard you're expected to follow when you write your own
commands. The idea is that
the Verb says what you're trying to do, like read or maybe
change data. PowerShell has a
standardized list of verbs. To get a full list of all possible
verbs, use the Get-Verb cmdlet:
PowerShell
Get-Verb
The cmdlet returns a long list of verbs. The Description provides context for what the
verb is
meant to do. Here's the first few rows of output:
Output
...
Filter on name
You can filter the output of Get-Command using different parameters. Filtering allows you
to find
commands that have certain properties. The Name parameter allows you to find
a specific command
by name.
PowerShell
Output
What if you want to find all the commands that work with processes? You can use a
wildcard *
to match other forms of the string. For example:
PowerShell
Output
PowerShell
This example lists all commands that use the verb Get .
Filter on noun. In the command Get-Process , the noun part is Process . To filter on
the
noun, use the Noun parameter. The following example returns all cmdlets the
have nouns
starting with the letter U .
PowerShell
Get-Command -Noun U*
Also, you can combine parameters to narrow down your search, for example:
PowerShell
Output
Select-Object . This versatile command helps you pick out specific properties from
one or more
objects. You can also limit the number of items you get back. The
following example returns the
Name and Source property values for the first 5
commands available in the current session.
PowerShell
Output
Name Source
---- ------
Add-AppPackage Appx
Add-AppPackageVolume Appx
Add-AppProvisionedPackage Dism
Add-AssertionOperator Pester
Add-ProvisionedAppPackage Dism
Where-Object . This cmdlet lets you filter the objects returned based on the values
of
properties. The command takes an expression that can test the value of a
property. The following
example returns all processes where the ProcessName starts
with p .
PowerShell
PowerShell
Get-Process | Get-Member
The result displays the returned type as TypeName and all the properties and methods of
the
object. Here's an excerpt of such a result:
Output
TypeName: System.Diagnostics.Process
...
Using the MemberType parameter you can limit the information returned.
PowerShell
By default PowerShell only displays a few properties. The previous example displayed
the Name ,
MemberType and Definition members. You can use Select-Object to specify
properties you want to
see. You For example, you want to display only the Name and
Definition properties:
PowerShell
ParameterType
parameter of Get-Command can be used to find other commands that
take Process objects as
input.
PowerShell
Output
Knowing the output type of a command can help narrow down your search for related
commands.
Additional resources
Get-Command
Get-Member
Select-Object
Install PowerShell on Windows, Linux,
and macOS
Learn about installing PowerShell on Windows, Linux, and macOS.
Windows
e OVERVIEW
macOS
e OVERVIEW
Install on macOS
Linux
e OVERVIEW
Linux overview
Alpine
Debian
Raspberry Pi OS
Ubuntu
Q&A
b GET STARTED
There are multiple ways to install PowerShell in Windows. Each install method is
designed to support
different scenarios and workflows. Choose the method that best
suits your needs.
7 Note
The installation commands in this article are for the latest stable release of
PowerShell. To
install a different version of PowerShell, adjust the command to
match the version you need. The
following links direct you to the release page for
each version in the PowerShell repository on
GitHub.
Download links for every package are found in the Assets section of the Release
page. The
Assets section may be collapsed, so you may need to click to expand it.
7 Note
See the winget documentation for a list of system requirements and install
instructions.
Winget doesn't currently run on Windows servers.
The following commands can be used to install PowerShell using the published winget
packages:
PowerShell
Output
--------------------------------------------------------------
PowerShell
7 Note
On Windows systems using X86 or X64 processor, winget installs the MSI package.
On systems using
the Arm64 processor, winget installs the Microsoft Store (MSIX)
package. For more information,
see Installing from the Microsoft Store.
Once downloaded, double-click the installer file and follow the prompts.
7 Note
PowerShell 7.3 installs to a new directory and runs side-by-side with Windows
PowerShell 5.1.
PowerShell 7.3 is an in-place upgrade that replaces PowerShell 7.0
and lower.
If you need to run PowerShell 7.3 side-by-side with other versions, use the ZIP
install
method to install the other version to a different folder.
Configuration Manager
0 - Don't opt into updating through Microsoft Update, WSUS, or Configuration
Manager
ENABLE_MU
1 (default) - Opts into using Microsoft Update for Automatic Updates
0 - Don't opt into using Microsoft Update
7 Note
adding the
Open PowerShell item to the context menu in Windows Explorer.
ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL - This property controls the option for
adding the
Run with PowerShell item to the context menu in Windows Explorer.
ENABLE_PSREMOTING - This property controls the option for enabling PowerShell
remoting during
installation.
REGISTER_MANIFEST - This property controls the option for registering the Windows
Event
Logging manifest.
ADD_PATH - This property controls the option for adding PowerShell to the
Windows PATH
environment variable.
DISABLE_TELEMETRY - This property controls the option for disabling PowerShell's
telemetry by
setting the POWERSHELL_TELEMETRY_OPTOUT environment variable.
The following example shows how to silently install PowerShell with all the install
options enabled.
PowerShell
PowerShell-7.3.4-win-x64.zip
PowerShell-7.3.4-win-x86.zip
PowerShell-7.3.4-win-arm64.zip
Depending on how you download the file you may need to unblock the file using the
Unblock-File
cmdlet. Unzip the contents to the location of your choice and run
Use this method to install the ARM-based version of PowerShell on computers like the
Microsoft
Surface Pro X. For best results, install PowerShell to the to
$env:ProgramFiles\PowerShell\7
folder.
Known limitations
By default, Windows Store packages run in an application sandbox that virtualizes access
to some
filesystem and registry locations. Changes to virtualized file and registry
locations don't persist
outside of the application sandbox.
This sandbox all blocks any changes to the application's root folder. Any system-level
configuration
settings stored in $PSHOME can't be modified. This includes the WSMAN
configuration. This prevents
remote sessions from connecting to Store-based installs of
PowerShell. User-level configurations and
SSH remoting are supported.
The following commands need write to $PSHOME . These commands aren't supported in a
Microsoft Store
instance of PowerShell.
Register-PSSessionConfiguration
Update-Help -Scope AllUsers
) Important
You must be running on Windows build 1903 or higher for this exemption to work.
7 Note
When the installed version isn't an LTS version, PowerShell upgrades to the latest
stable
version.
PowerShell
$zipfile = 'PowerShell-7.3.4-win-arm64.zip'
# There should be enough space for the zip file and the unzipped
contents.
Enter-PSSession $S
Set-Location u:\users\administrator\Downloads
Expand-Archive .\PowerShell-7.3.4-win-arm64.zip
.\Install-PowerShellRemoting.ps1 -PowerShellHome .
When you set up PowerShell Remoting you get an error message and are disconnected
from the device.
PowerShell has to restart WinRM. Now you can connect to PowerShell 7
endpoint on device.
PowerShell
# Be sure to use the -Configuration parameter. If you omit it, you connect
to Windows PowerShell 5.1
For adding the latest PowerShell in the shipping image, use Import-PSCoreRelease
command to
include the package in the workarea and add OPENSRC_POWERSHELL
feature to your image.
7 Note
For ARM64 architecture, Windows PowerShell isn't added when you include
IOT_POWERSHELL. So the
zip based install doesn't work. You need to use Import-
PSCoreRelease command to add it in
the image.
In both cases, you need the Windows x64 ZIP release package . Run the commands
within an
"Administrator" instance of PowerShell.
PowerShell
$zipfile = 'PowerShell-7.3.4-win-x64.zip'
Enter-PSSession $session
PowerShell remoting
PowerShell supports the PowerShell Remoting Protocol (PSRP) over both WSMan and
SSH. For more
information, see:
SSH Remoting in PowerShell
WSMan Remoting in PowerShell
The following prerequisites must be met to enable PowerShell remoting over WSMan on
older versions
of Windows.
Install the Windows Management Framework (WMF) 5.1 (as necessary). For more
information about WMF,
see WMF Overview.
Install the Universal C Runtime on Windows versions predating Windows 10. It's
available via
direct download or Windows Update. Fully patched systems already
have this package installed.
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
Windows 11
Windows 10 1607+
7 Note
Windows Server 2012 R2+ x64, x86 x64, x86 x64, x86
Windows Server Core 2012 R2+ x64, x86 x64, x86 x64, x86
Windows 10 or 11 Client x64, x86, Arm64 x64, x86, Arm64 x64, x86, Arm64
You can check the version that you are using by running winver.exe .
Installation support
Microsoft supports the installation methods in this document. There may be other third-
party methods
of installation available from other sources. While those tools and
methods may work, Microsoft
can't support those methods.
Install PowerShell on Linux
Article • 01/10/2023
PowerShell can be installed on different Linux distributions. Most Linux platforms and
distributions
have a major release each year, and provide a package manager that's
used to install PowerShell.
This article lists the currently supported Linux distributions
and package managers.
The rest of this article is a breakdown of each Linux distribution that PowerShell
supports. All
PowerShell releases remain supported until either the version of
PowerShell
reaches end-of-support or the Linux distribution reaches end-of-life.
Alpine
The following table lists the supported PowerShell releases and the versions of Alpine
they're
supported on. These versions are supported until either the version of
PowerShell reaches end-of-support or the version of
Alpine reaches end-of-life .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
3.15
3.14
Debian
Debian uses APT (Advanced Package Tool) as a package manager.
The following table is a list of currently supported PowerShell releases and the versions
of Debian
they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
Debian reaches end-of-
life .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
11
10
The following table is a list of currently supported versions of PowerShell and the
versions of RHEL
they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
RHEL reaches end-of-
support .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
Ubuntu
Ubuntu uses APT (Advanced Package Tool) as a package manager.
The following table is a list of currently supported PowerShell releases and the versions
of
Ubuntu they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
Ubuntu reaches end-of-
support .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
22.04 (LTS)
Ubuntu 7.2 (LTS-current) 7.3 7.4 (preview)
20.04 (LTS)
18.04 (LTS)
Only the LTS releases of Ubuntu are officially supported. Microsoft does not support
interim releases or their equivalent. Interim releases are community supported. For
more
information, see Community supported distributions.
Raspberry Pi OS
Raspberry Pi OS (formerly Raspbian) is a free operating system based on Debian.
) Important
CentOS and Fedora distributions are no longer supported. The versions of these
operating systems
that were supported have reached their end-of-life dates. We aren't
supporting any newer versions.
All packages are available on our GitHub releases page. After the package is installed,
run
pwsh from a terminal. Run pwsh-preview if you installed a preview release. Before
installing,
check the list of Supported versions below.
7 Note
If you need to run PowerShell 7.3 side-by-side with a previous version, reinstall the
previous
version using the binary archive method.
Installation steps
Installation on Alpine is based on downloading tar.gz package from the releases page.
The URL to the package depends on the version of PowerShell you want to install.
PowerShell 7.3.4 -
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-
7.3.4-linux-alpine-x64.tar.gz
PowerShell 7.2.11 -
https://github.com/PowerShell/PowerShell/releases/download/v7.2.11/powershell-
7.2.11-linux-alpine-x64.tar.gz
Then, in the terminal, execute the following shell commands to install PowerShell 7.3:
sh
ca-certificates \
less \
ncurses-terminfo-base \
krb5-libs \
libgcc \
libintl \
libssl1.1 \
libstdc++ \
tzdata \
userspace-rcu \
zlib \
icu-libs \
curl
lttng-ust
curl -L
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell
-7.3.4-linux-alpine-x64.tar.gz -o /tmp/powershell.tar.gz
# Start PowerShell
pwsh
PowerShell paths
$PSHOME is /opt/microsoft/powershell/7/
User profiles are read from ~/.config/powershell/profile.ps1
Default profiles are read from $PSHOME/profile.ps1
User modules are read from ~/.local/share/powershell/Modules
Shared modules are read from /usr/local/share/powershell/Modules
Default modules are read from $PSHOME/Modules
PSReadLine history is recorded to
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt
Supported versions
The following table lists the supported PowerShell releases and the versions of Alpine
they're
supported on. These versions are supported until either the version of
PowerShell reaches end-of-support or the version of
Alpine reaches end-of-life .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
3.15
3.14
Installation support
Microsoft supports the installation methods in this document. There may be other
methods of
installation available from other third-party sources. While those tools and
methods may work,
Microsoft can't support those methods.
Installing PowerShell on Debian Linux
Article • 05/30/2023
All packages are available on our GitHub releases page. After the package is installed,
run
pwsh from a terminal. Run pwsh-preview if you installed a preview release. Before
installing,
check the list of Supported versions below.
7 Note
If you need to run PowerShell 7.3 side-by-side with a previous version, reinstall the
previous
version using the binary archive method.
PowerShell 7.3.4 -
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell_7
.3.4-1.deb_amd64.deb
PowerShell 7.2.11 -
https://github.com/PowerShell/PowerShell/releases/download/v7.2.11/powershell-
lts_7.2.11-1.deb_amd64.deb
sh
# Install system components
sudo apt update && sudo apt install -y curl gnupg apt-transport-https
# Install PowerShell
# Start PowerShell
pwsh
sh
wget https://packages.microsoft.com/config/debian/10/packages-microsoft-
prod.deb
# Install PowerShell
# Start PowerShell
pwsh
Uninstallation
sh
PowerShell paths
$PSHOME is /opt/microsoft/powershell/7/
Supported versions
The following table is a list of currently supported PowerShell releases and the versions
of Debian
they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
Debian reaches end-of-
life .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
11
10
PowerShell is supported on Debian for the following processor architectures.
Installation support
Microsoft supports the installation methods in this document. There may be other
methods of
installation available from other third-party sources. While those tools and
methods may work,
Microsoft cannot support those methods.
Installing PowerShell on Raspberry Pi
OS
Article • 06/21/2023
All packages are available on our GitHub releases page. After the package is installed,
run
pwsh from a terminal. Run pwsh-preview if you installed a preview release.
7 Note
If you need to run PowerShell 7.3 side-by-side with a previous version, reinstall the
previous
version using the binary archive method.
Raspberry Pi OS
Raspberry Pi OS (formerly Raspbian) is a free operating system based on Debian.
) Important
Install on Raspberry Pi OS
Download the tar.gz package from the releases page onto your Raspberry Pi
computer. The links
to the current versions are:
PowerShell 7.3.4 -
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-
7.3.4-linux-arm32.tar.gz
PowerShell 7.2.11 -
https://github.com/PowerShell/PowerShell/releases/download/v7.2.11/powershell-
7.2.11-linux-arm32.tar.gz
Use the following shell commands to download and install the package. Change the URL
to match the
PowerShell version that you want to install.
sh
###################################
# Prerequisites
# Install dependencies
###################################
wget
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell
-7.3.4-linux-arm32.tar.gz
mkdir ~/powershell
# Start PowerShell
~/powershell/pwsh
Optionally, you can create a symbolic link to start PowerShell without specifying the
path to the
pwsh binary.
sh
Uninstallation - Raspberry Pi OS
sh
rm -rf ~/powershell
PowerShell paths
$PSHOME is /opt/microsoft/powershell/7/
Installation support
Microsoft supports the installation methods in this document. There may be other
methods of
installation available from other third-party sources. While those tools and
methods may work,
Microsoft can't support those methods.
The Raspberry Pi OS is available for Arm 64 processors. PowerShell hasn't been tested
on Arm 64
for the Raspberry Pi OS.
Installing PowerShell on Red Hat
Enterprise Linux (RHEL)
Article • 03/17/2023
All packages are available on our GitHub releases page. After the package is installed,
run
pwsh from a terminal. Run pwsh-preview if you installed a preview release. Before
installing,
check the list of Supported versions below.
7 Note
If you need to run PowerShell 7.3 side-by-side with a previous version, reinstall the
previous
version using the binary archive method.
RHEL 7 uses yum and RHEL 8 uses the dnf package manager.
On RHEL 7:
sh
# Install PowerShell
# Start PowerShell
pwsh
As superuser, register the Microsoft repository once. After registration, you can update
PowerShell
with sudo yum update powershell .
On RHEL 8:
sh
# Register the Microsoft RedHat repository
# Install PowerShell
# Start PowerShell
pwsh
As superuser, register the Microsoft repository once. After registration, you can update
PowerShell
with sudo dnf upgrade powershell .
PowerShell 7.3.4 -
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell-
7.3.4-1.rh.x86_64.rpm
PowerShell 7.2.11-
https://github.com/PowerShell/PowerShell/releases/download/v7.2.11/powershell-
lts-7.2.11-1.rh.x86_64.rpm
Use the following shell command to install the latest RPM package on the target version
of RHEL.
Change the URL in the following shell commands to match the version you
need.
On RHEL 7:
sh
On RHEL 8:
sh
PowerShell paths
$PSHOME is /opt/microsoft/powershell/7/
Supported versions
The following table is a list of currently supported versions of PowerShell and the
versions of RHEL
they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
RHEL reaches end-of-
support .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
Installation support
Microsoft supports the installation methods in this document. There may be other
methods of
installation available from other third-party sources. While those tools and
methods may work,
Microsoft cannot support those methods.
Installing PowerShell on Ubuntu
Article • 03/17/2023
All packages are available on our GitHub releases page. After the package is installed,
run pwsh from a terminal. Run pwsh-preview if you installed a preview release. Before
installing, check the list of Supported versions below.
7 Note
If you need to run PowerShell 7.3 side-by-side with a previous version, reinstall the
previous
version using the binary archive method.
Use the following shell commands to install PowerShell on the target OS.
7 Note
sh
wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -
rs)/packages-microsoft-prod.deb"
rm packages-microsoft-prod.deb
# Install PowerShell
# Start PowerShell
pwsh
As superuser, register the Microsoft repository once. After registration, you can update
PowerShell with sudo apt-get install powershell .
Use the following shell commands to install the package. Change the filename of the
package to match
the version you downloaded.
sh
7 Note
If the dpkg -i command fails with unmet dependencies, the next command, apt-
get install -f
resolves these issues then finishes configuring the PowerShell
package.
Uninstallation
sh
PowerShell paths
$PSHOME is /opt/microsoft/powershell/7/
User profiles are read from ~/.config/powershell/profile.ps1
Default profiles are read from $PSHOME/profile.ps1
User modules are read from ~/.local/share/powershell/Modules
Shared modules are read from /usr/local/share/powershell/Modules
Default modules are read from $PSHOME/Modules
PSReadLine history is recorded to
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt
Supported versions
The following table is a list of currently supported PowerShell releases and the versions
of
Ubuntu they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
Ubuntu reaches end-of-
support .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
22.04 (LTS)
20.04 (LTS)
18.04 (LTS)
Only the LTS releases of Ubuntu are officially supported. Microsoft does not support
interim releases or their equivalent. Interim releases are community supported. For
more
information, see Community supported distributions.
Installation support
Microsoft supports the installation methods in this document. There may be other
methods of
installation available from other third-party sources. While those tools and
methods may work,
Microsoft can't support those methods.
Community support for PowerShell on
Linux
Article • 06/29/2022
There are many distributions of Linux that are not officially supported by Microsoft. In
some cases,
PowerShell may be supported by the community for these releases.
To be supported by Microsoft, the Linux distribution must meet the following criteria:
The following distributions are supported by the community. Each distribution has its
own community
support mechanisms. Consult the distribution's website to find their
community resources. You may
also get help from these PowerShell Community
resources.
Arch Linux
7 Note
Kali
Kali support is not officially supported by Microsoft and is maintained by the
community.
Installation - Kali
sh
# Start PowerShell
pwsh
Uninstallation - Kali
sh
All packages are available on our GitHub releases page. After the package is installed,
run
pwsh from a terminal. Run pwsh-preview if you installed a preview release.
Snap Package
Snaps are application packages that are easy to install, secure, cross‐platform and
dependency‐free.
Snaps are discoverable and installable from the Snap Store. Snap
packages are supported the same as
the distribution you're running the package on.
) Important
The Snap Store contains PowerShell snap packages for many Linux distributions
that are not
officially supported by Microsoft. For support, see the list of available
Community Support
options.
Getting snapd
snapd is required to run snaps. Use these instructions to make sure you have snapd
installed.
sh
# Install PowerShell
# Start PowerShell
pwsh
sh
# Install PowerShell
# Start PowerShell
pwsh
sh
# Install PowerShell
# Start PowerShell
pwsh-preview
After installation, Snap will automatically upgrade. You can trigger an upgrade using
sudo snap refresh powershell or sudo snap refresh powershell-preview .
Uninstallation
sh
or
sh
Binary Archives
PowerShell binary tar.gz archives are provided for Linux platforms to enable advanced
deployment
scenarios.
7 Note
You can use this method to install any version of PowerShell including the latest:
Dependencies
PowerShell builds portable binaries for all Linux distributions. But, .NET Core runtime
requires
different dependencies on different distributions, and PowerShell does too.
It's possible that when you install PowerShell, specific dependencies may not be
installed, such as
when manually installing from the binary archives. The following list
details Linux distributions
that are supported by Microsoft and have dependencies you
may need to install. Check the
distribution page for more information:
Alpine
Debian
RHEL
SLES
Ubuntu
To deploy PowerShell binaries on Linux distributions that aren't officially supported, you
need to
install the necessary dependencies for the target OS in separate steps. For
example, our
Amazon Linux dockerfile installs dependencies first, and then extracts
the Linux tar.gz
archive.
) Important
This method can be used to install PowerShell on any version of Linux, including
distributions
that are not officially supported by Microsoft. Be sure to install any
necessary dependencies. For
support, see the list of available Community Support
options.
The following example shows the steps for installing the x64 binary archive. You must
choose the
correct binary archive that matches the processor type for your platform.
powershell-7.3.4-linux-arm32.tar.gz
powershell-7.3.4-linux-arm64.tar.gz
powershell-7.3.4-linux-x64.tar.gz
Use the following shell commands to download and install PowerShell from the tar.gz
binary
archive. Change the URL to match the version of PowerShell you want to install.
sh
curl -L -o /tmp/powershell.tar.gz
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell
-7.3.4-linux-x64.tar.gz
sh
The dotnet tool installer adds ~/.dotnet/tools to your PATH environment variable.
However, the
currently running shell does not have the updated PATH . You should be
able to start PowerShell
from a new shell by typing pwsh .
Installing PowerShell on macOS
Article • 04/17/2023
PowerShell 7.0 or higher require macOS 10.13 and higher. All packages are available on
our GitHub
releases page. After the package is installed, run pwsh from a terminal.
Before installing,
check the list of Supported versions below.
7 Note
If you need to run an older version of PowerShell side-by-side with PowerShell 7.3,
install
the version you want using the binary archive method.
If the brew command isn't found, you need to install Homebrew following
their
instructions .
Bash
sh
pwsh
When new versions of PowerShell are released, update Homebrew's formulae and
upgrade PowerShell:
sh
brew update
7 Note
The commands above can be called from within a PowerShell (pwsh) host, but then
the PowerShell
shell must be exited and restarted to complete the upgrade and
refresh the values shown in
$PSVersionTable .
sh
sh
sh
pwsh-preview
When new versions of PowerShell are released, update Homebrew's formulae and
upgrade PowerShell:
sh
brew update
7 Note
The commands above can be called from within a PowerShell (pwsh) host, but then
the PowerShell
shell must be exited and restarted to complete the upgrade. and
refresh the values shown in
$PSVersionTable .
Installing PowerShell using the Homebrew tap method is also supported for stable and
LTS versions.
sh
sh
pwsh
When new versions of PowerShell are released, run the following command.
sh
7 Note
Whether you use the cask or the tap method, when updating to a newer version of
PowerShell, use
the same method you used to initially install PowerShell. If you use
a different method, opening a
new pwsh session will continue to use the older
version of PowerShell.
If you do decide to use different methods, there are ways to correct the issue using
the
Homebrew link method .
Installation via Direct Download
Starting with version 7.2, PowerShell supports the Apple M1 processor. Download the
install package
from the releases page onto your computer. The links to the current
versions are:
PowerShell 7.3.4
x64 processors - powershell-7.3.4-osx-x64.pkg
M1 processors - powershell-7.3.4-osx-arm64.pkg
PowerShell 7.2.11
x64 processors - powershell-7.2.11-osx-x64.pkg
M1 processors - powershell-7.2.11-osx-arm64.pkg
You can double-click the file and follow the prompts, or install it from the terminal using
the
following commands. Change the name of the file to match the file you
downloaded.
sh
If you are running on macOS Big Sur 11.5 or higher you may receive the following error
message
when installing the package:
This is a known issue related to package notarization that will be addressed in the
future.
The dotnet tool installer adds ~/.dotnet/tools to your PATH environment variable.
However, the
currently running shell doesn't have the updated PATH . You should be able
to start PowerShell from
a new shell by typing pwsh .
Binary Archives
PowerShell binary tar.gz archives are provided for the macOS platform to enable
advanced
deployment scenarios. When you install using this method you must also
manually install any
dependencies.
7 Note
You can use this method to install any version of PowerShell including the latest:
PowerShell 7.3.4
x64 processors - powershell-7.3.4-osx-x64.tar.gz
M1 processors - powershell-7.3.4-osx-arm64.tar.gz
PowerShell 7.2.11
x64 processors - powershell-7.2.11-osx-x64.tar.gz
M1 processors - powershell-7.2.11-osx-arm64.tar.gz
Use the following commands to install PowerShell from the binary archive. Change the
download URL to
match the version you want to install.
sh
curl -L -o /tmp/powershell.tar.gz
https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershell
-7.3.4-osx-x64.tar.gz
Uninstalling PowerShell
If you installed PowerShell with Homebrew, use the following command to uninstall:
sh
If you installed PowerShell via direct download, PowerShell must be removed manually:
sh
To remove the additional PowerShell paths, refer to the paths section in this document
and
remove the paths using sudo rm .
7 Note
This isn't necessary if you installed with Homebrew.
Paths
$PSHOME is /usr/local/microsoft/powershell/7.3.4/
Because macOS is a derivation of BSD, the prefix /usr/local is used instead of /opt . So,
$PSHOME is /usr/local/microsoft/powershell/7.3.4/ , and the symbolic link is placed at
/usr/local/bin/pwsh .
Supported versions
The following table contains a list of PowerShell releases and the status of support for
versions of
macOS. These versions remain supported until either the version of
PowerShell reaches end-of-support or the version of macOS reaches end-of-support.
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
macOS Big Sur 11.5 x64, Arm64 x64, Arm64 x64, Arm64
Installation support
Microsoft supports the installation methods in this document. There may be other
methods of
installation available from other sources. While those tools and methods
may work, Microsoft can't
support those methods.
Additional Resources
Homebrew Web
Homebrew GitHub Repository
Homebrew-Cask
PowerShell on Arm processors
Article • 01/10/2023
Support for the Arm processor is based on the support policy of the version of .NET that
PowerShell
uses. While .NET supports many more operating systems and versions,
PowerShell support is limited to
the versions that have been tested.
PowerShell 7.3
PowerShell 7.3 is based on the .NET 7.0 Supported OS Lifecycle Policy and supports
the
following platforms:
OS Architectures Lifecycle
PowerShell 7.2
PowerShell 7.2 is based on the .NET 6.0 Supported OS Lifecycle Policy and supports
the
following platforms:
OS Architectures Lifecycle
Windows
Windows 10 on Arm
Windows 10 IoT Enterprise
Windows 10 IoT Core
macOS
Raspbery Pi
Raspberry Pi OS
Using PowerShell in Docker
Article • 05/31/2022
We publish Docker images with PowerShell preinstalled. This article shows you how to
get
started using PowerShell in the Docker container.
The release containers derive from the official distribution image, then install
dependencies, and
finally install the PowerShell package.
For more information about these Docker images, visit the PowerShell-Docker
repository on GitHub.
Console
Console
Telemetry
By default, PowerShell collects limited telemetry without personally identifiable
information to
help aid development of future versions of PowerShell. To opt-out of
sending telemetry, create an
environment variable called POWERSHELL_TELEMETRY_OPTOUT
set to a value of 1 before starting
PowerShell from the installed location. The telemetry
we collect falls under the
Microsoft Privacy Statement .
Microsoft Update for PowerShell
FAQ
FAQ
Beginning with PowerShell 7.2, when you install using the MSI package you have the
option of
enabling Microsoft Update support for PowerShell.
General Information
What is the Microsoft Update feature in
PowerShell?
The Microsoft Update feature of PowerShell allows you to get the latest PowerShell 7
updates in your traditional Microsoft Update (MU) management flow, whether that's
with
Windows Update for Business, WSUS, Microsoft Endpoint Configuration Manager,
or the
interactive MU dialog in Settings. Microsoft Update and the related services
enable you to
deploy updates:
On your schedule
After testing for your environment
At scale across your enterprise
If you need to deploy the update before it becomes available in Microsoft Update,
download
the update from the Releases page on
GitHub.
Configuration
What version of Windows is required to support
the Microsoft Update feature?
You must have Windows Version 1709 or newer installed on an x64-based system.
Version 1709
is the Windows 10 Fall Creators Update or the October update of Windows
Server 2016. Versions
prior to 1709 do not support Microsoft Update for PowerShell.
The second checkbox enables Microsoft Update on your system. This allows you to
receive
updates for any supported Microsoft software, not just Windows. If the box is
unchecked,
you will not receive the update from Microsoft Update, but you can receive
updates from
WSUS or SCCM.
7 Note
Troubleshooting
I haven't received an update for the new release.
Why not?
There can be several reasons for not receiving the update:
We may not have published the update yet. Our goal is to make the update
available to
Microsoft Update within two weeks of release, but there is no
guarantee for that
availability.
There are group policy settings that control Microsoft Update. Your system
administrator
may have policies set that prevent you from using Microsoft Update.
The checkbox in the
installer cannot override the Group Policy.
Make sure you have checked both checkboxes. When doing a repair installation,
the installer
doesn't show the check box options. To enable MU updates run the
following command:
PowerShell
For more information about running msiexec.exe from the command line, see
msiexec.
Introduction
Article • 12/09/2022
This content originally appeared in the book PowerShell 101 by Mike F Robbins. We
thank
Mike for granting us permission to reuse his content here. The content has been
edited from the
original publication. You can still get the original book from Leanpub at
PowerShell 101 .
This book focuses on PowerShell version 5.1 running on Windows 10 and Windows
Server 2016 in a
Microsoft Active Directory domain environment. However, the basic
concepts apply to all versions of
PowerShell running on any supported platform.
Lab environment
The examples in this book were designed and tested on Windows 10 Anniversary Edition
(build 1607)
and Windows Server 2016 using PowerShell version 5.1. If you're using a
different version of
PowerShell or operating system, your results may differ from those
shown here.
Chapter 1 - Getting Started with
PowerShell
Article • 11/17/2022
I often find that presenters at conferences and user group meetings already have
PowerShell running
when they start entry-level presentations. This book begins by
answering the questions I've heard
attendees who haven't previously used PowerShell
ask in those sessions.
Specifically, this chapter focuses on finding and launching PowerShell, and solving some
of the
initial pain points that new users experience with PowerShell. Be sure to follow
along and
walk through the examples shown in this chapter on your Windows 10 lab
environment computer.
I've launched the PowerShell console by clicking on the "Windows PowerShell" shortcut
as shown in
Figure 1-1.
Notice that the title bar of the PowerShell console says "Windows PowerShell" as shown
in Figure
1-4. Some commands run fine, but PowerShell can't participate in User Access
Control (UAC). That
means it's unable to prompt for elevation for tasks that require the
approval of an administrator.
The following error message is generated:
PowerShell
Output
At line:1 char:29
+ CategoryInfo : CloseError:
(System.ServiceProcess.ServiceController:ServiceController)
[Stop-Service], ServiceCommandException
+ FullyQualifiedErrorId :
CouldNotStopService,Microsoft.PowerShell.Commands.StopServiceCommand
The solution to this problem is to run PowerShell as a domain user who is a local
administrator.
This is how my second domain user account is configured. Using the
principle of least privilege,
this account should NOT be a domain administrator, or have
any elevated privileges in the domain.
Close PowerShell. Relaunch the PowerShell console, except this time right-click on the
Windows
PowerShell shortcut and select Run as administrator as shown in Figure 1-5.
If you're logged into Windows as a normal user, you'll be prompted for credentials. I'll
enter the
credentials for my user account who is a domain user and local admin as
shown in Figure 1-6.
Once PowerShell is relaunched as an administrator, the title bar should say
"Administrator: Windows
PowerShell" as shown in Figure 1-7.
Now that PowerShell is being run elevated as a local administrator, UAC will no longer
be a problem
when a command is run on the local computer that would normally
require a prompt for elevation. Keep
in mind though that any command run from this
elevated instance of the PowerShell console, also runs
elevated.
Search for PowerShell again, except this time right-click on it and select "Pin to taskbar"
as shown
in Figure 1-8.
Right-click on the PowerShell shortcut that's now pinned to the taskbar and select
properties as
shown in Figure 1-9.
PowerShell
$PSVersionTable
Output
Name Value
---- -----
PSVersion 5.1.19041.1
PSEdition Desktop
BuildVersion 10.0.19041.1
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Execution Policy
Contrary to popular belief, the execution policy in PowerShell is not a security boundary.
It's
designed to prevent a user from unknowingly running a script. A determined user
can easily bypass
the execution policy in PowerShell. Table 1-2 shows the default
execution policy for current
Windows operating systems.
Windows 10 Restricted
Regardless of the execution policy setting, any PowerShell command can be run
interactively. The
execution policy only affects commands running in a script. The Get-
ExecutionPolicy cmdlet is used
to determine what the current execution policy setting is
PowerShell
Get-ExecutionPolicy
Output
Restricted
PowerShell scripts can't be run at all when the execution policy is set to Restricted. This
is
the default setting on all Windows client operating systems. To demonstrate the
problem, save the
following code as a .ps1 file named Stop-TimeService.ps1 .
PowerShell
That command runs interactively without error as long as PowerShell is run elevated as
an
administrator. But as soon as it's saved as a script file and you try to execute the
script, it
generates an error:
PowerShell
.\Stop-TimeService.ps1
Output
about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\Stop-TimeService.ps1
+ FullyQualifiedErrorId : UnauthorizedAccess
Notice that the error shown in the previous set of results tells you exactly what the
problem is
(running scripts is disabled on this system). When you run a command in
PowerShell that generates an
error message, be sure to read the error message instead
of just rerunning the command and hoping
that it runs successfully.
PowerShell
Output
Execution Policy Change
The execution policy helps protect you from scripts that you do not trust.
Changing the execution
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is
"N"):y
Be sure to read the warning that's displayed when changing the execution policy. I also
recommend
taking a look at the about_Execution_Policies help topic to make sure you
understand the
security implications of changing the execution policy.
Now that the execution policy has been set to RemoteSigned, the Stop-TimeService.ps1
script
runs error free.
PowerShell
.\Stop-TimeService.ps1
Output
Be sure to start your Windows Time service before continuing otherwise you may run
into unforeseen
problems.
PowerShell
Summary
In this chapter, you've learned how to find and launch PowerShell, and how to create a
shortcut that
launches PowerShell as an administrator. You've also learned about the
default execution policy and
how to change it.
Review
1. How do you determine what PowerShell version a computer is running?
2. Why is it important to launch PowerShell elevated as an administrator?
3. How do you determine the current PowerShell execution policy?
4. What does the default PowerShell execution policy on Windows client computers
prevent from
occurring?
5. How do you change the PowerShell execution policy?
Recommended Reading
For those who want to know more information about the topics covered in this chapter,
I recommend
reading the following PowerShell help topics.
about_Automatic_Variables
about_Hash_Tables
about_Execution_Policies
In the next chapter, you'll learn about the discoverability of commands in PowerShell.
One of the
things that will be covered is how to update PowerShell so those help topics
can be viewed right
from within PowerShell instead of having to view them on the
internet.
Chapter 2 - The Help System
Article • 12/15/2022
Two groups of IT pros were given a written test without access to a computer to
determine their
skill level with PowerShell. PowerShell beginners were placed in one
group and experts in another.
Based on the results of the test, there didn't seem to be
much difference in the skill level between
the two groups. Both groups were given a
second test similar to the first one. This time they were
given access to a computer with
PowerShell that didn't have access to the internet. The results of
the second test showed
a huge difference in the skill level between the two groups. Experts don't
always know
the answers, but they know how to figure out the answers.
What was the difference in the results of the first and second test between these two
groups?
The differences observed in these two tests were because experts don't memorize how
to use thousands
of commands in PowerShell. They learn how to use the help system
within PowerShell extremely well.
This allows them to find the necessary commands
when needed and how to use those commands once
they've found them.
I've heard Jeffrey Snover, the inventor of PowerShell, tell a similar story a number of
times.
Mastering the help system is the key to being successful with PowerShell.
Discoverability
Compiled commands in PowerShell are called cmdlets. Cmdlet is pronounced
"command-let" (not
CMD-let). Cmdlets names have the form of singular "Verb-Noun"
commands to make them easily
discoverable. For example, the cmdlet for determining
what processes are running is Get-Process
and the cmdlet for retrieving a list of services
and their statuses is Get-Service . There are
other types of commands in PowerShell
such as aliases and functions that will be covered later in
this book. The term PowerShell
command is a generic term that's often used to refer to any type of
command in
PowerShell, regardless of whether or not it's a cmdlet, function, or alias.
One question I'm often asked is how do you figure out what the commands are in
PowerShell? Both
Get-Command and Get-Help can be used to determine the commands.
Get-Help
Get-Help is a multipurpose command. Get-Help helps you learn how to use commands
When Get-Help is used to locate commands, it first searches for wildcard matches of
command names
based on the provided input. If it doesn't find a match, it searches
through the help topics
themselves, and if no match is found an error is returned.
Contrary to popular belief, Get-Help
can be used to find commands that don't have
help topics.
The first thing you need to know about the help system in PowerShell is how to use the
Get-Help
cmdlet. The following command is used to display the help topic for Get-Help .
PowerShell
Output
The Update-Help cmdlet downloads the most current Help files for Windows
PowerShell
modules, and installs them on your computer. For more information about the
Update-Help
Beginning with PowerShell version 3, PowerShell help doesn't ship with the operating
system. The
first time Get-Help is run for a command, the previous message is
displayed. If the help
function or man alias is used instead of the Get-Help cmdlet, you
don't receive this prompt.
Answering yes by pressing Y runs the Update-Help cmdlet, which requires internet
access
by default. Y can be specified in either upper or lower case.
Once the help is downloaded and the update is complete, the help topic is returned for
the specified
command:
PowerShell
Take a moment to run that example on your computer, review the output, and take note
of how the
information is grouped:
NAME
SYNOPSIS
SYNTAX
DESCRIPTION
RELATED LINKS
REMARKS
As you can see, help topics can contain an enormous amount of information and this
isn't even the
entire help topic.
The syntax section of the help topic shown in the previous set of results lists all of the
parameters for Get-Help . At first glance, it appears the same parameters are listed six
different
times. Each of those different blocks in the syntax section is a parameter set.
This means the
Get-Help cmdlet has six different parameter sets. If you take a closer
look, you'll notice that at
least one parameter is different in each of the parameter sets.
Parameter sets are mutually exclusive. Once a unique parameter that only exists in one
of the
parameter sets is used, only parameters contained within that parameter set can
be used. For
example, both the Full and Detailed parameters couldn't be specified at
the same time
because they are in different parameter sets.
Full
Detailed
Examples
Online
Parameter
ShowWindow
All of the cryptic syntax such as square and angle brackets in the syntax section means
something
but will be covered in Appendix A of this book. While important, learning the
cryptic syntax is
often difficult to retain for someone who is new to PowerShell and may
not use it everyday.
For more information to better understand the cryptic syntax, see Appendix A.
For beginners, there's an easier way to figure out the same information except in plain
language.
When the Full parameter of Get-Help is specified, the entire help topic is returned.
PowerShell
Take a moment to run that example on your computer, review the output, and take note
of how the
information is grouped:
NAME
SYNOPSIS
SYNTAX
DESCRIPTION
PARAMETERS
INPUTS
OUTPUTS
NOTES
EXAMPLES
RELATED LINKS
Notice that using the Full parameter returned several additional sections, one of which
is the
PARAMETERS section that provides more information than the cryptic SYNTAX
section.
The Full parameter is a switch parameter. A parameter that doesn't require a value is
called a
switch parameter. When a switch parameter is specified, its value is true and
when it's not, its
value is false.
If you've been working through this chapter in the PowerShell console, you noticed that
the previous
command to display the full help topic for Get-Help flew by on the screen
without giving you a
chance to read it. There's a better way.
Help is a function that pipes Get-Help to a function named more , which is a wrapper for
the
more.com executable file in Windows. In the PowerShell console, help provides one
page of help
at a time. In the ISE, it works the same way as Get-Help . My
recommendation is to use the help
function instead of the Get-Help cmdlet since it
provides a better experience and it's less to
type.
Less typing isn't always a good thing, however. If you're going to save your commands
as a script or
share them with someone else, be sure to use full cmdlet and parameter
names. The full names are
self-documenting, which makes them easier to understand.
Think about the next person that has to
read and understand your commands. It could
be you. Your coworkers and future self will thank you.
Try running the following commands in the PowerShell console on your Windows 10 lab
environment
computer.
PowerShell
Did you notice any differences in the output from the previously listed commands when
you ran them
on your Windows 10 lab environment computer?
There aren't any differences other than the last two options return the results one page
at a time.
The spacebar is used to display the next page of content when using the Help
function
and Ctrl + C cancels commands that are running in the PowerShell console.
The first example uses the Get-Help cmdlet, the second uses the Help function, and the
third
omits the Name parameter when using the Help function. Name is a positional
parameter and
it's being used positionally in that example. This means the value can be
specified without
specifying the parameter name, as long as the value itself is specified
in the correct position. How
did I know what position to specify the value in? By reading
the help as shown in the following
example.
PowerShell
Output
-Name <String>
Gets help about the specified command or concept. Enter the name of a
cmdlet, function,
provider names, but you can't use wildcard characters to find the names
of function help and
To get help for a script that isn't located in a path that's listed in
the $env:Path
If you enter the exact name of a help article, Get-Help displays the
article contents.
If you enter a word or word pattern that appears in several help article
titles, Get-Help
If you enter a word that doesn't match any help article titles, Get-Help
displays a list of
Required? false
Position? 0
Notice that in the previous example, the Parameter parameter was used with the Help
function to
only return information from the help topic for the Name parameter. This is
much more concise
than trying to manually sift through what sometimes seems like a
hundred page help topic.
Based on those results, you can see that the Name parameter is positional and must be
specified
in position zero (the first position) when used positionally. The order that
parameters are
specified in doesn't matter if the parameter name is specified.
One other important piece of information is that the Name parameter expects the
datatype for its
value to be a single string, which is denoted by <String> . If it accepted
multiple strings, the
datatype would be listed as <String[]> .
Sometimes you simply don't want to display the entire help topic for a command. There
are a number
of other parameters besides Full that can be specified with Get-Help or
Help . Try running
the following commands on your Windows 10 lab environment
computer:
PowerShell
Get-Help -Name Get-Command -Full
I typically use help <command name> with the Full or Online parameter. If I'm only
interested in the examples, I'll use the Examples parameter and if I'm only interested in
a
specific parameter, I'll use the Parameter parameter. The ShowWindow parameter
opens the
help topic in a separate searchable window that can be placed on a different
monitor if you have
multiple monitors. I've avoided the ShowWindow parameter
because there's a known bug where it
doesn't display the entire help topic.
If you want help in a separate window, my recommendation is to either use the Online
parameter
or use the Full parameter and pipe the results to Out-GridView , as shown in
the following
example.
PowerShell
Both the Out-GridView cmdlet and the ShowWindow parameter of the Get-Help cmdlet
require an
operating system with a GUI (Graphical User Interface). They will generate an
error message if you
attempt to use either of them on Windows Server that's been
installed using the server core (no-GUI)
installation option.
To use Get-Help to find commands, use the asterisk ( * ) wildcard character with the
Name
parameter. Specify a term that you're searching for commands on as the value for
the Name
parameter as shown in the following example.
PowerShell
help *process*
Output
In the previous example, the * wildcard characters are not required and omitting them
produces the
same result. Get-Help automatically adds the wildcard characters behind
the scenes.
PowerShell
help process
The previous command produces the same results as specifying the * wildcard
character on each end
of process.
I prefer to add them since that's the option that always works consistently. Otherwise,
they are
required in certain scenarios and not others. As soon as you add a wildcard
character in the middle
of the value, they're no longer automatically added behind the
scenes to the value you specified.
PowerShell
help pr*cess
No results are returned by that command unless the * wildcard character is added to
the beginning,
end, or both the beginning and end of pr*cess .
If the value you specified begins with a dash, then an error is generated because
PowerShell
interprets it as a parameter name and no such parameter name exists for the
Get-Help cmdlet.
PowerShell
help -process
If what you're attempting to look for are commands that end with -process , you only
need to add
the * wildcard character to the beginning of the value.
PowerShell
help *-process
When searching for PowerShell commands with Get-Help , you want to be a little more
vague instead
of being too specific with what you're searching for.
Searching for process earlier found only commands that contained process in the
name of the
command and returned only those results. When Get-Help is used to
search for processes , it
doesn't find any matches for command names, so it performs a
search of every help topic in
PowerShell on your system and returns any matches it
finds. This causes it to return an enormous
number of results.
PowerShell
Get-Help processes
Output
about_Arithmetic_Operators HelpFile
Describes the op...
about_Arrays HelpFile
Describes arrays...
about_Debuggers HelpFile
Describes the Wi...
about_Execution_Policies HelpFile
Describes the Wi...
about_ForEach-Parallel HelpFile
Describes the Fo...
about_Foreach HelpFile
Describes a lang...
about_Functions HelpFile
Describes how to...
about_Language_Keywords HelpFile
Describes the ke...
about_Methods HelpFile
Describes how to...
about_Objects HelpFile
Provides essenti...
about_Parallel HelpFile
Describes the Pa...
about_Pipelines HelpFile
Combining comman...
about_Preference_Variables HelpFile
Variables that c...
about_Remote HelpFile
Describes how to...
about_Remote_Output HelpFile
Describes how to...
about_Sequence HelpFile
Describes the Se...
about_Session_Configuration_Files HelpFile
Describes sessio...
about_Variables HelpFile
Describes how va...
about_Windows_PowerShell_5.0 HelpFile
Describes new fe...
about_WQL HelpFile
Describes WMI Qu...
about_WS-Management_Cmdlets HelpFile
Provides an over...
about_ForEach-Parallel HelpFile
Describes the Fo...
about_Parallel HelpFile
Describes the Pa...
about_Sequence HelpFile
Describes the Se...
Using Help to search for process returned 10 results and using it to search for
processes
returned 68 results. If only one result is found, the help topic itself will be
displayed instead of
a list of commands.
PowerShell
get-help *hotfix*
Output
NAME
Get-HotFix
SYNOPSIS
Gets the hotfixes that have been applied to the local and remote
computers.
SYNTAX
<String[]>] [<CommonParameters>]
<PSCredential>] [<CommonParameters>]
DESCRIPTION
The Get-Hotfix cmdlet gets hotfixes (also called updates) that have been
installed
RELATED LINKS
Win32_QuickFixEngineering http://go.microsoft.com/fwlink/?LinkID=145071
Get-ComputerRestorePoint
Add-Content
REMARKS
Now to debunk the myth that Help in PowerShell can only find commands that have
help topics.
PowerShell
help *more*
Output
NAME
more
SYNTAX
ALIASES
None
REMARKS
None
Notice in the previous example that more doesn't have a help topic, yet the Help system
in
PowerShell was able to find it. It only found one match and returned the basic syntax
information
that you'll see when a command doesn't have a help topic.
PowerShell contains numerous conceptual (About) help topics. The following command
can be used to
return a list of all About help topics on your system.
PowerShell
help About_*
Limiting the results to one single About help topic displays the actual help topic instead
of
returning a list.
PowerShell
help about_Updatable_Help
The help system in PowerShell has to be updated in order for the About help topics to
be
present. If for some reason the initial update of the help system failed on your
computer, the files
will not be available until the Update-Help cmdlet has been run
successfully.
Get-Command
Get-Command is designed to help you locate commands. Running Get-Command without
any parameters
returns a list of all the commands on your system. The following
example demonstrates using the
Get-Command cmdlet to determine what commands
exist for working with processes:
PowerShell
Output
Notice in the previous example where Get-Command was run, the Noun parameter is used
and
Process is specified as the value for the Noun parameter. What if you didn't know
how to use
the Get-Command cmdlet? You could use Get-Help to display the help topic
for Get-Command .
The Name, Noun, and Verb parameters accept wildcards. The following example shows
wildcards being used with the Name parameter:
PowerShell
Output
Application AgentService.exe
10.0.14... C:\Windo...
Application SensorDataService.exe
10.0.14... C:\Windo...
Application services.exe
10.0.14... C:\Windo...
Application TieringEngineService.exe
10.0.14... C:\Windo...
I'm not a fan of using wildcards with the Name parameter of Get-Command since it also
returns
executable files that are not native PowerShell commands.
If you are going to use wildcard characters with the Name parameter, I recommend
limiting the
results with the CommandType parameter.
PowerShell
A better option is to use either the Verb or Noun parameter or both of them since only
PowerShell commands have both verbs and nouns.
Found something wrong with a help topic? The good news is the help topics for
PowerShell have been
open-sourced and available in the PowerShell-Docs repository
on GitHub. Pay it forward by not
only fixing the incorrect information for yourself, but
everyone else as well. Simply fork the
PowerShell documentation repository on GitHub,
update the help topic, and submit a pull request.
Once the pull request is accepted, the
corrected documentation is available for everyone.
Updating Help
The local copy of the PowerShell help topics was previously updated the first-time help
on a command
was requested. It's recommended to periodically update the help system
because there can be updates
to the help content from time to time. The Update-Help
cmdlet is used to update the help topics.
It requires internet access by default and for
you to be running PowerShell elevated as an
administrator.
PowerShell
Update-Help
Output
{en-US} : Unable to retrieve the HelpInfo XML file for UI culture en-US.
Make sure the HelpInfoUri
At line:1 char:1
+ Update-Help
+ FullyQualifiedErrorId :
InvalidHelpInfoUri,Microsoft.PowerShell.Commands.UpdateHel
pCommand
for UI culture en-US. 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
+ FullyQualifiedErrorId :
UnableToRetrieveHelpInfoXml,Microsoft.PowerShell.Commands.
UpdateHelpCommand
A couple of the modules returned errors, which is not uncommon. If the machine didn't
have internet
access, you could use the Save-Help cmdlet on another machine that does
have internet access to
first save the updated help information to a file share on your
network and then use the
SourcePath parameter of Update-Help to specify this network
location for the help topics.
Consider setting up a scheduled task or adding some logic to your profile script in
PowerShell to
periodically update the help content on your computer. Profile scripts will
be discussed in an
upcoming chapter.
Summary
In this chapter you've learned how to find commands with both Get-Help and Get-
Command . You've
learned how to use the help system to figure out how to use commands
once you find them. You've also
learned how to update the content of the help topics
when updates are available.
PowerShell
Review
1. Is the DisplayName parameter of Get-Service positional?
2. How many parameter sets does the Get-Process cmdlet have?
3. What PowerShell commands exist for working with event logs?
4. What is the PowerShell command for returning a list of PowerShell processes
running on your
computer?
5. How do you update the PowerShell help content that's stored on your computer?
Recommended Reading
If you want to know more information about the topics covered in this chapter, I
recommend
reading the following PowerShell help topics.
Get-Help
Get-Command
Update-Help
Save-Help
about_Updatable_Help
about_Command_Syntax
In the next chapter, you'll learn about the Get-Member cmdlet as well as objects,
properties, and
methods.
Chapter 3 - Discovering objects,
properties, and methods
Article • 12/09/2022
My first introduction to computers was a Commodore 64, but my first modern computer
was a 286 12-Mhz
IBM clone with 1 megabyte of memory, a 40-megabyte hard drive,
and one 5-1/4 inch floppy disk drive
with a CGA monitor running Microsoft DOS 3.3.
Many IT Pros, like myself, are no stranger to the command line, but when the subject of
objects,
properties, and methods comes up, they get the deer in the headlights look and
say, "I'm not a
developer." Guess what? You don't have to be a developer to be
successful with PowerShell. Don't get
bogged down in the terminology. Not everything
may make sense initially, but after a little hands-on
experience you'll start to have those
"light bulb" moments. "Aha! So that's what the book was
talking about."
Be sure to try the examples on your computer to gain some of that hands-on
experience.
Requirements
The Active Directory PowerShell module is required by some of the examples shown in
this chapter.
The module is part of the Remote Server Administration Tools (RSAT) for
Windows. For the 1809 (or
higher) build of Windows, the RSAT tools are installed as a
Windows feature. Support for Active Directory
is not available on Windows Home.
For information about installing the RSAT tools, see Windows Management
modules.
For older versions of Windows, see RSAT for Windows .
Get-Member
Get-Member helps you discover what objects, properties, and methods are available for
commands.
Any command that produces object-based output can be piped to Get-
Member . A property is a
characteristic about an item. Your drivers license has a property
called eye color and the most
common values for that property are blue and brown. A
method is an action that can be taken on an
item. In staying with the drivers license
example, one of the methods is "Revoke" because the
department of motor vehicles can
revoke your drivers license.
Properties
In the following example, I'll retrieve information about the Windows Time service
running on my
computer.
PowerShell
Output
Status, Name, and DisplayName are examples of properties as shown in the previous
set of
results. The value for the Status property is Running , the value for the Name
property is
w32time , and the value for DisplayName is Windows Time .
PowerShell
Output
TypeName: System.ServiceProcess.ServiceController
DependentServices Property
System.ServiceProcess.ServiceController[] Depe...
ServiceHandle Property
System.Runtime.InteropServices.SafeHandle Serv...
ServicesDependedOn Property
System.ServiceProcess.ServiceController[] Serv...
StartType Property
System.ServiceProcess.ServiceStartMode StartTy...
Status Property
System.ServiceProcess.ServiceControllerStatus ...
The first line of the results in the previous example contains one piece of very important
information. TypeName tells you what type of object was returned. In this example, a
System.ServiceProcess.ServiceController object was returned. This is often abbreviated
as the
portion of the TypeName just after the last period; ServiceController in this
example.
Once you know what type of object a command produces, you can use this information
to find commands
that accept that type of object as input.
PowerShell
Output
All of those commands have a parameter that accepts a ServiceController object type
by
pipeline, parameter input, or both.
Notice that there are more properties than are displayed by default. Although these
additional
properties aren't displayed by default, they can be selected from the pipeline
by piping the command
to the Select-Object cmdlet and using the Property
parameter. The following example selects
all of the properties by piping the results of
Get-Service to Select-Object and specifying the
* wildcard character as the value for
PowerShell
Output
Name : w32time
RequiredServices : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : w32time
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Specific properties can also be selected using a comma-separated list for the value of
the
Property parameter.
PowerShell
Output
By default, four properties are returned in a table and five or more are returned in a list.
Some
commands use custom formatting to override how many properties are displayed
by default in a table.
There are several Format-* cmdlets that can be used to manually
override these defaults. The most
common ones are Format-Table and Format-List ,
both of which will be covered in an upcoming
chapter.
Wildcard characters can be used when specifying the property names with Select-
Object .
PowerShell
Output
Status : Running
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
In the previous example, Can* was used as one of the values for the Property parameter
to
return all the properties that start with Can . These include CanPauseAndContinue,
CanShutdown, and CanStop.
Methods
Methods are an action that can be taken. Use the MemberType parameter to narrow
down the results
of Get-Member to only show the methods for Get-Service .
PowerShell
Output
TypeName: System.ServiceProcess.ServiceController
As you can see, there are many methods. The Stop method can be used to stop a
Windows service.
PowerShell
Now to verify the Windows time service has indeed been stopped.
PowerShell
Output
Status Name DisplayName
I rarely find myself using methods, but they're something you need to be aware of.
There are times
that you'll come across a Get-* command without a corresponding
command to modify that item.
Often, a method can be used to perform an action that
modifies it. The Get-SqlAgentJob cmdlet in
the SqlServer PowerShell module is a good
example of this. The module installs as part of
SQL Server Management Studio (SMSS).
No corresponding Set-* cmdlet exists, but a
method can be used to complete the same
task.
A better option is to use a cmdlet to perform the action if one exists. Go ahead and start
the
Windows Time service, except this time use the cmdlet for starting services.
PowerShell
Output
By default, Start-Service doesn't return any results just like the start method of Get-
Service .
But one of the benefits of using a cmdlet is that many times the cmdlet offers
additional
functionality that isn't available with a method. In the previous example, the
PassThru
parameter was used. This causes a cmdlet that doesn't normally produce
output, to produce output.
Be careful with assumptions about the output of a cmdlet. We all know what happens
when you assume
things. I'll retrieve information about the PowerShell process running
on my Windows 10 lab
environment computer.
PowerShell
Output
PowerShell
Output
TypeName: System.Diagnostics.Process
PM AliasProperty PM = PagedMemorySize64
SI AliasProperty SI = SessionId
VM AliasProperty VM = VirtualMemorySize64
WS AliasProperty WS = WorkingSet64
ErrorDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
OutputDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
Modules Property
System.Diagnostics.ProcessModuleCollection M...
PriorityClass Property
System.Diagnostics.ProcessPriorityClass Prio...
SafeHandle Property
Microsoft.Win32.SafeHandles.SafeProcessHandl...
StartInfo Property
System.Diagnostics.ProcessStartInfo StartInf...
SynchronizingObject Property
System.ComponentModel.ISynchronizeInvoke Syn...
Threads Property
System.Diagnostics.ProcessThreadCollection T...
Notice that there are more properties listed than are displayed by default. A number of
the default
properties displayed don't show up as properties when viewing the results of
Get-Member . This is
because many of the displayed values, such as NPM(K) , PM(K) , WS(K) ,
PowerShell
Output
At line:1 char:31
+ FullyQualifiedErrorId :
NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMembe
rCommand
The PassThru parameter can be specified with the Start-Service cmdlet make it
produce output,
which is then piped to Get-Member without error.
PowerShell
Output
TypeName: System.ServiceProcess.ServiceController
DependentServices Property
System.ServiceProcess.ServiceController[] Depe...
ServiceHandle Property
System.Runtime.InteropServices.SafeHandle Serv...
ServicesDependedOn Property
System.ServiceProcess.ServiceController[] Serv...
StartType Property
System.ServiceProcess.ServiceStartMode StartTy...
Status Property
System.ServiceProcess.ServiceControllerStatus ...
PowerShell
Output
At line:1 char:40
+ FullyQualifiedErrorId :
NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
Out-Host writes directly to the PowerShell host, but it doesn't produce object-based
output for
the pipeline. So it can't be piped to Get-Member .
Active Directory
7 Note
The Remote Server Administration Tools listed in the requirements section of this
chapter are
required to complete this section. Also, as mentioned in the
introduction to this book, your
Windows 10 lab environment computer must be a
member of the lab environment domain.
Use Get-Command with the Module parameter to determine what commands were added
as part of the
ActiveDirectory PowerShell module when the remote server administration
tools were installed.
PowerShell
Output
...
A total of 147 commands were added as part of the ActiveDirectory PowerShell module.
Some commands
of these commands only return a portion of the available properties
by default.
Did you notice anything different about the names of the commands in this module?
The noun portion
of the commands has an AD prefix. This is common to see on the
commands of most modules. The prefix
is designed to help prevent naming conflicts.
PowerShell
Output
TypeName: Microsoft.ActiveDirectory.Management.ADUser
GetEnumerator Method
System.Collections.IDictionaryEnumerator GetEn...
Item ParameterizedProperty
Microsoft.ActiveDirectory.Management.ADPropert...
SID Property
System.Security.Principal.SecurityIdentifier S...
Even if you're only vaguely familiar with Active Directory, you're probably aware that a
user
account has more properties than are shown in this example.
The Get-ADUser cmdlet has a Properties parameter that is used to specify the additional
(non-default) properties you want to return. Specifying the * wildcard character returns
all of
them.
PowerShell
Output
TypeName: Microsoft.ActiveDirectory.Management.ADUser
GetEnumerator Method
System.Collections.IDiction...
Item ParameterizedProperty
Microsoft.ActiveDirectory.M...
AuthenticationPolicy Property
Microsoft.ActiveDirectory.M...
AuthenticationPolicySilo Property
Microsoft.ActiveDirectory.M...
Certificates Property
Microsoft.ActiveDirectory.M...
CN Property System.String CN
{get;}
CompoundIdentitySupported Property
Microsoft.ActiveDirectory.M...
dSCorePropagationData Property
Microsoft.ActiveDirectory.M...
KerberosEncryptionType Property
Microsoft.ActiveDirectory.M...
MemberOf Property
Microsoft.ActiveDirectory.M...
nTSecurityDescriptor Property
System.DirectoryServices.Ac...
ObjectGUID Property
System.Nullable`1[[System.G...
objectSid Property
System.Security.Principal.S...
PrincipalsAllowedToDelegateToAccount Property
Microsoft.ActiveDirectory.M...
ServicePrincipalNames Property
Microsoft.ActiveDirectory.M...
SID Property
System.Security.Principal.S...
SIDHistory Property
Microsoft.ActiveDirectory.M...
sn Property System.String sn
{get;set;}
userCertificate Property
Microsoft.ActiveDirectory.M...
Can you think of a reason why the properties of an Active Directory user account would
be so limited
by default? Imagine if you returned every property for every user account
in your production Active
Directory environment. Think of the performance degradation
that you could cause, not only to the
domain controllers themselves, but also to your
network. It's doubtful that you'll actually need
every property anyway. Returning all of
the properties for a single user account is perfectly
acceptable when you're trying to
determine what properties exist.
It's not uncommon to run a command many times when prototyping it. If you're going
to perform
some huge query, query it once and store the results in a variable. Then work
with the contents of
the variable instead of repeatedly using some expensive query.
PowerShell
Use the contents of the $Users variable instead of running the previous command
numerous times.
Keep in mind that the contents of the variable aren't updated when
changes are made to that user in
Active Directory.
You could pipe the $Users variable to Get-Member to discover the available properties.
PowerShell
$Users | Get-Member
Then select the individual properties by piping $Users to Select-Object , all without ever
having
to query Active Directory more than one time.
PowerShell
If you are going to query Active Directory more than once, use the Properties parameter
to
specify any non-default properties you want.
PowerShell
Output
Enabled : True
GivenName : Mike
ObjectClass : user
ObjectGUID : a82a8c58-1332-4a57-a6e2-68e0c750ea56
SamAccountName : mike
SID : S-1-5-21-2989741381-570885089-3319121794-1108
Surname : Robbins
UserPrincipalName : [email protected]
Summary
In this chapter, you've learned how to determine what type of object a command
produces, how to
determine what properties and methods are available for a command,
and how to work with commands
that limit the properties that are returned by default.
Review
1. What type of object does the Get-Process cmdlet produce?
2. How do you determine what the available properties are for a command?
3. If a command exists for getting something but not for setting the same thing, what
should you
check for?
4. How can certain commands that don't produce output by default be made to
produce output?
5. If you're going to be working with the results of a command that produces an
enormous amount of
output, what should you consider doing?
Recommended Reading
Get-Member
Viewing Object Structure (Get-Member)
about_Objects
about_Properties
about_Methods
No PowerShell Cmdlet to Start or Stop Something? Don't Forget to Check for
Methods on the Get Cmdlets
Chapter 4 - One-liners and the pipeline
Article • 12/09/2022
When I first started learning PowerShell, if I couldn't accomplish a task with a PowerShell
one-liner, I went back to the GUI. Over time, I built my skills up to writing scripts,
functions,
and modules. Don't allow yourself to become overwhelmed by some of the
more advanced examples you
may see on the internet. No one is a natural expert with
PowerShell. We were all beginners at
one time.
I have a bit of advice to offer those of you who are still using the GUI for administration:
install the management tools on your admin workstation and manage your servers
remotely. This way it
won't matter if the server is running a GUI or Server Core
installation of the operating system.
It's going to help prepare you for managing servers
remotely with PowerShell.
As with previous chapters, be sure to follow along on your Windows 10 lab environment
computer.
One-Liners
A PowerShell one-liner is one continuous pipeline and not necessarily a command that's
on one
physical line. Not all commands that are on one physical line are one-liners.
Even though the following command is on multiple physical lines, it's a PowerShell one-
liner because
it's one continuous pipeline. It could be written on one physical line, but
I've chosen to line
break at the pipe symbol. The pipe symbol is one of the characters
where a natural line break is
allowed in PowerShell.
PowerShell
Get-Service |
Select-Object -Property *
Output
Name : LanmanWorkstation
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Workstation
DependentServices : {SessionEnv, Netlogon, Browser}
MachineName : .
ServiceName : LanmanWorkstation
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :
Name : Netlogon
RequiredServices : {LanmanWorkstation}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Netlogon
DependentServices : {}
MachineName : .
ServiceName : Netlogon
ServicesDependedOn : {LanmanWorkstation}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :
Name : vmicheartbeat
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : vmicheartbeat
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmickvpexchange
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : vmickvpexchange
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmicrdv
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : vmicrdv
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmicshutdown
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : vmicshutdown
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmictimesync
RequiredServices : {VmGid}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : vmictimesync
ServicesDependedOn : {VmGid}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Name : vmicvss
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : vmicvss
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
Name : Winmgmt
RequiredServices : {RPCSS}
CanPauseAndContinue : True
CanShutdown : True
CanStop : True
MachineName : .
ServiceName : Winmgmt
ServicesDependedOn : {RPCSS}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :
Natural line breaks can occur at commonly used characters including comma ( , ) and
opening brackets
( [ ), braces ( { ), and parenthesis ( ( ). Others that aren't so common
include the semicolon
( ; ), equals sign ( = ), and both opening single and double quotes
( ' , " ).
PowerShell
Output
Name : w32time
RequiredServices : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
DependentServices : {}
MachineName : .
ServiceName : w32time
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :
The commands shown in the previous two examples work fine in the PowerShell
console. But if you try
to run them in the console pane of the PowerShell ISE, they'll
generate an error. The console pane
of the PowerShell ISE doesn't wait for the rest of
the command to be entered on the next line like
the PowerShell console does. To avoid
this problem in the console pane of the PowerShell ISE, use
Shift + Enter instead of just
pressing Enter when continuing a
command on another line.
This next example isn't a PowerShell one-liner because it's not one continuous pipeline.
It's two
separate commands on one line, separated by a semicolon.
PowerShell
Output
Many programming and scripting languages require a semicolon at the end of each line.
While they can
be used that way in PowerShell, it's not recommended because they're
not needed.
Filtering Left
The results of the commands shown in this chapter have been filtered down to a subset.
For example,
Get-Service was used with the Name parameter to filter the list of services
that were returned
to only the Windows Time service.
In the pipeline, you always want to filter the results down to what you're looking for as
early as
possible. This is accomplished using parameters on the first command or, the
one to the far left.
This is sometimes called filtering left.
The following example uses the Name parameter of Get-Service to immediately filter
the results
to the Windows Time service only.
PowerShell
Output
It's not uncommon to see examples where the command is piped to Where-Object to
perform the
filtering.
PowerShell
Output
The first example filters at the source and only returns the results for the Windows Time
service.
The second example returns all the services then pipes them to another
command to perform the
filtering. While this may not seem like a big deal in this
example, imagine if you were querying a
list of Active Directory users. Do you really
want to return the information for many thousands of
user accounts from Active
Directory only to pipe them to another command that filters them down to a
tiny
subset? My recommendation is to always filter left even when it doesn't seem to matter.
You'll
be so use to it that you'll automatically filter left when it really does matter.
I once had someone tell me that the order you specify the commands in doesn't matter.
That couldn't
be further from the truth. The order that the commands are specified in
does indeed matter when
performing filtering. For example, consider the scenario where
you are using Select-Object to
select only a few properties and Where-Object to filter
on properties that won't be in the
selection. In that scenario, the filtering must occur
first, otherwise the property won't exist
in the pipeline when try to perform the filtering.
PowerShell
Get-Service |
Where-Object CanPauseAndContinue
The command in the previous example doesn't return any results because the
CanStopAndContinue
property doesn't exist when the results of Select-Object are
piped to Where-Object . That
particular property wasn't "selected". In essence, it was
filtered out. Reversing the order of
Select-Object and Where-Object produces the
desired results.
PowerShell
Get-Service |
Where-Object CanPauseAndContinue |
Output
DisplayName Status
----------- ------
Workstation Running
Netlogon Running
The Pipeline
As you've seen in many of the examples shown so far throughout this book, many times
the output of
one command can be used as input for another command. In Chapter 3,
Get-Member was used to
determine what type of object a command produces. Chapter 3
also showed using the ParameterType
parameter of Get-Command to determine what
commands accepted that type of input, although not
necessarily by pipeline input.
Depending on how thorough a commands help is, it may include an INPUTS and
OUTPUTS section.
PowerShell
Output
...
INPUTS
System.ServiceProcess.ServiceController, System.String
You can pipe a service object or a string that contains the name of
a service
to this cmdlet.
OUTPUTS
None, System.ServiceProcess.ServiceController
...
Only the relevant section of the help is shown in the previous results. As you can see,
the
INPUTS section states that a ServiceController or a String object can be piped to
the
Stop-Service cmdlet. It doesn't tell you which parameters accept that type of input.
One of the
easiest ways to determine that information is to look through the different
parameters in the full
version of the help for the Stop-Service cmdlet.
PowerShell
Output
...
-DisplayName <String[]>
permitted.
Required? true
Position? named
-InputObject <ServiceController[]>
objects.
Required? true
Position? 0
-Name <String[]>
permitted.
Required? true
Position? 0
...
Once again, I've only shown the relevant portion of the help in the previous set of
results. Notice
that the DisplayName parameter doesn't accept pipeline input, the
InputObject parameter
accepts pipeline input by value for ServiceController objects,
and the Name parameter
accepts pipeline input by value for string objects. It also
accepts pipeline input by
property name.
When a parameter accepts pipeline input by both property name and by value, it always
tries by
value first. If by value fails, then it tries by property name. By value is a little
misleading. I prefer to call it by type. This means if you pipe the results of a command
that
produces a ServiceController object type to Stop-Service , it binds that input to the
InputObject parameter. But if you pipe the results of a command that produces String
output
to Stop-Service , it binds it to the Name parameter. If you pipe the results of a
command that
doesn't produce a ServiceController or String object to Stop-Service ,
but it does produce
output containing a property called Name, then it binds the Name
property from the output to
the Name parameter of Stop-Service .
Output
TypeName: System.ServiceProcess.ServiceController
As you previously saw in the help, the InputObject parameter of Stop-Service accepts
ServiceController objects via the pipeline by value (by type). This means that when the
results of the Get-Service cmdlet are piped to Stop-Service , they bind to the
InputObject
parameter of Stop-Service .
PowerShell
Now to try string input. Pipe w32time to Get-Member just to confirm that it's a string.
PowerShell
'w32time' | Get-Member
Output
TypeName: System.String
As previously shown in the help, piping a string to Stop-Service binds it by value to the
Name parameter of Stop-Service . Test this by piping w32time to Stop-Service .
PowerShell
'w32time' | Stop-Service
Notice that in the previous example, I used single quotes around the string w32time . In
PowerShell, you should always use single quotes instead of double quotes unless the
contents of the
quoted string contains a variable that needs to be expanded to its actual
value. By using single
quotes, PowerShell doesn't have to parse the contents contained
within the quotes so your code runs
a little faster.
Create a custom object to test pipeline input by property name for the Name parameter
of
Stop-Service .
PowerShell
$CustomObject = [pscustomobject]@{
Name = 'w32time'
PowerShell
$CustomObject | Get-Member
Output
TypeName: System.Management.Automation.PSCustomObject
If you were to surround the $CustomObject variable with quotes, you want to use double
quotes.
Otherwise, using single quotes, the literal string $CustomObject is piped to Get-
Member instead
of the value contained by the variable.
In this example, I create another custom object using a different property name, such as
Service.
PowerShell
$CustomObject = [pscustomobject]@{
Service = 'w32time'
PowerShell
$CustomObject | Stop-Service
Output
At line:1 char:17
+ $CustomObject | Stop-Service
, ServiceCommandException
+ FullyQualifiedErrorId :
NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.S
topServiceCommand
If the output of one command doesn't line up with the pipeline input options for
another command,
Select-Object can be used to rename the property so that the
properties lineup correctly.
PowerShell
$CustomObject |
Stop-Service
In this example, Select-Object was used to rename the Service property to a property
named
Name.
The syntax this example may seem a little complicated at first. What I have learned is
that you'll
never learn the syntax by copy and pasting code. Take the time to type the
code in. After a few
times, it becomes second nature. Having multiple monitors is a huge
benefit because you can display
the example code on one screen and type it in on
another one.
Occasionally, you may want to use a parameter that doesn't accept pipeline input. The
following
example demonstrates using the output of one command as input for
another. First save the display
name for a couple of Windows services into a text file.
PowerShell
You can run the command that provides the needed output within parentheses as the
value for the
parameter of the command requiring the input.
PowerShell
This is just like order of operations in Algebra for those of you who remember how it
works. The
command within parentheses always runs prior to the outer portion of the
command.
PowerShellGet
PowerShellGet is a PowerShell module that contains commands for discovering,
installing, publishing,
and updating PowerShell modules (and other artifacts) to or from
a NuGet repository. PowerShellGet
ships with PowerShell version 5.0 and higher. It is
available as a separate download for PowerShell
version 3.0 and higher.
Most companies will want to host their own internal private NuGet repository where
they can post
their internal use only modules as well as modules that they've
downloaded from other sources once
they've validated them as being non-malicious.
Use the Find-Module cmdlet that's part of the PowerShellGet module to find a module in
the
PowerShell Gallery that I wrote named MrToolkit.
PowerShell
Output
NuGet provider is required to continue
Files\PackageManagement\ProviderAssemblies' or
'C:\Users\MrAdmin\AppData\Local\PackageManagement\ProviderAssemblies'. You
can also
The first time you use one of the commands from the PowerShellGet module, you'll be
prompted to
install the NuGet provider.
PowerShell
Output
Untrusted repository
You are installing the modules from an untrusted repository. If you trust
this
'https://www.powershellgallery.com/api/v2/'?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "N"): y
Since the PowerShell Gallery is an untrusted repository, it prompts you to approve the
installation
of the module.
PowerShell
Output
As you can see, the same information we previously determined by sifting through the
help can easily
be determined with this function.
Summary
In this chapter, you've learned about PowerShell one-liners. You've learned that the
number of
physical lines that a command is on has nothing to do with whether or not
it's a PowerShell
one-liner. You've also learned about filtering left, the pipeline, and
PowerShellGet.
Review
1. What is a PowerShell one-liner?
2. What are some of the characters where natural line breaks can occur in
PowerShell?
3. Why should you filter left?
4. What are the two ways that a PowerShell command can accept pipeline input?
5. Why shouldn't you trust commands found in the PowerShell Gallery?
Recommended Reading
about_Pipelines
about_Command_Syntax
about_Parameters
PowerShellGet: The BIG EASY way to discover, install, and update PowerShell
modules
Chapter 5 - Formatting, aliases,
providers, comparison
Article • 11/17/2022
Requirements
The SQL Server PowerShell module is required by some of the examples shown in this
chapter. The
module installs as part of SQL Server Management Studio (SSMS). It's also
used in
subsequent chapters. Download and install it on your Windows 10 lab
environment computer.
Format Right
In Chapter 4, you learned to filter as far to the left as possible. The rule for manually
formatting
a command's output is similar to that rule except it needs to occur as far to
the right as possible.
The most common format commands are Format-Table and Format-List . Format-Wide
and
Format-Custom can also be used, but are less common.
As mentioned in Chapter 3, a command that returns more than four properties defaults
to a list
unless custom formatting is used.
PowerShell
Output
Status : Running
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
Use the Format-Table cmdlet to manually override the formatting and show the output
in a table
instead of a list.
PowerShell
Get-Service -Name w32time | Select-Object -Property Status, DisplayName,
Can* |
Format-Table
Output
PowerShell
Output
Use the Format-List cmdlet to override the default formatting and return the results in
a list.
PowerShell
Output
Name : w32time
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
ServiceType : Win32ShareProcess
PowerShell
Output
TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
autosizeInfo Property
Microsoft.PowerShell.Commands.Inter...
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...
pageFooterEntry Property
Microsoft.PowerShell.Commands.Inter...
pageHeaderEntry Property
Microsoft.PowerShell.Commands.Inter...
shapeInfo Property
Microsoft.PowerShell.Commands.Inter...
TypeName: Microsoft.PowerShell.Commands.Internal.Format.GroupStartData
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...
shapeInfo Property
Microsoft.PowerShell.Commands.Inter...
TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
formatEntryInfo Property
Microsoft.PowerShell.Commands.Inter...
writeStream Property
Microsoft.PowerShell.Commands.Inter...
TypeName: Microsoft.PowerShell.Commands.Internal.Format.GroupEndData
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...
TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEndData
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...
What this means is format commands can't be piped to most other commands. They
can be piped to some
of the Out-* commands, but that's about it. This is why you want
to perform any formatting at the
very end of the line (format right).
Aliases
An alias in PowerShell is a shorter name for a command. PowerShell includes a set of
built-in
aliases and you can also define your own aliases.
The Get-Alias cmdlet is used to find aliases. If you already know the alias for a
command, the
Name parameter is used to determine what command the alias is
associated with.
PowerShell
Output
Multiple aliases can be specified for the value of the Name parameter.
PowerShell
Output
You'll often see the Name parameter omitted since it's a positional parameter.
PowerShell
Get-Alias gm
Output
If you want to find aliases for a command, you'll need to use the Definition parameter.
PowerShell
Output
Aliases can save you a few keystrokes and they're fine when you're typing commands
into the console.
They shouldn't be used in scripts or any code that you're saving or
sharing with others. As
mentioned earlier in this book, using full cmdlet and parameter
names is self-documenting and easier
to understand.
Use caution when creating your own aliases because they'll only exist in your current
PowerShell
session on your computer.
Providers
A provider in PowerShell is an interface that allows file system like access to a datastore.
There
are a number of built-in providers in PowerShell.
PowerShell
Get-PSProvider
Output
As you can see in the previous results, there are built-in providers for the registry,
aliases,
environment variables, the file system, functions, variables, certificates, and
WSMan.
The actual drives that these providers use to expose their datastore can be determined
with the
Get-PSDrive cmdlet. The Get-PSDrive cmdlet not only displays drives exposed
by providers, but it
also displays Windows logical drives including drives mapped to
network shares.
PowerShell
Get-PSDrive
Output
A FileSystem A:\
Alias Alias
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
Variable Variable
WSMan WSMan
Third-party modules such as the Active Directory PowerShell module and the SQLServer
PowerShell
module both add their own PowerShell provider and PSDrive.
PowerShell
PowerShell
Get-PSProvider
Output
Notice that in the previous set of results, two new PowerShell providers now exist, one
for Active
Directory and another one for SQL Server.
PowerShell
Get-PSDrive
Output
A FileSystem A:\
AD ActiveDire... //RootDSE/
Alias Alias
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
Variable Variable
WSMan WSMan
PowerShell
Output
PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\CA
Thumbprint Subject
---------- -------
D559A586669B08F46A30A133F8A9ED3D038E2EA8 OU=www.verisign.com/CPS
Incorporated LIABI...
Comparison Operators
PowerShell contains a number of comparison operators that are used to compare values
or find values
that match certain patterns. Table 5-1 contains a list of comparison
operators in PowerShell.
Operator Definition
-eq Equal to
Proper case "PowerShell" is equal to lower case "powershell" using the equals
comparison operator.
PowerShell
Output
True
It's not equal using the case-sensitive version of the equals comparison operator.
PowerShell
Output
False
PowerShell
Output
False
Greater than, greater than or equal to, less than, and less than or equal all work with
string or
numeric values.
PowerShell
5 -gt 5
Output
False
Using greater than or equal to instead of greater than with the previous example returns
the
Boolean true since five is equal to five.
PowerShell
5 -ge 5
Output
True
Based on the results from the previous two examples, you can probably guess how both
less than and
less than or equal to work.
PowerShell
5 -lt 10
Output
True
The -Like and -Match operators can be confusing, even for experienced PowerShell
users. -Like
is used with wildcard the characters * and ? to perform "like" matches.
PowerShell
Output
True
PowerShell
Output
True
PowerShell
$Numbers = 1..10
Output
PowerShell
$Numbers -contains 15
Output
False
PowerShell
$Numbers -contains 10
Output
True
-NotContains reverses the logic to see if the $Numbers variable doesn't contain a value.
PowerShell
$Numbers -notcontains 15
Output
True
The previous example returns the Boolean true because it's true that the $Numbers
variable
doesn't contain 15. It does however contain the number 10 so it's false when it's
tested.
PowerShell
$Numbers -notcontains 10
Output
False
The "in" comparison operator was first introduced in PowerShell version 3.0. It's used to
determine
if a value is "in" an array. The $Numbers variable is an array since it contains
multiple values.
PowerShell
15 -in $Numbers
Output
False
In other words, -in performs the same test as the contains comparison operator except
from the
opposite direction.
PowerShell
10 -in $Numbers
Output
True
PowerShell
15 -in $Numbers
Output
False
Just like the -contains operator, not reverses the logic for the -in operator.
PowerShell
10 -notin $Numbers
Output
False
The previous example returns false because the $Numbers array does include 10 and the
condition
was testing to determine if it didn't contain 10.
PowerShell
15 -notin $Numbers
Output
True
The -replace operator does just want you would think. It's used to replace something.
Specifying
one value replaces that value with nothing. In the following example, I
replace "Shell" with nothing.
PowerShell
Output
Power
If you want to replace a value with a different value, specify the new value after the
pattern you
want to replace. SQL Saturday in Baton Rouge is an event that I try to speak
at every year. In the
following example, I replace the word "Saturday" with the
abbreviation "Sat".
PowerShell
Output
There are also methods like Replace() that can be used to replace things similar to the
way the
replace operator works. However, the -Replace operator is case-insensitive by
default, and the
Replace() method is case-sensitive.
PowerShell
Output
Notice that the word "Saturday" wasn't replaced in the previous example. This is
because it was
specified in a different case than the original. When the word "Saturday"
is specified in the same
case as the original, the Replace() method does replace it as
expected.
PowerShell
Output
Be careful when using methods to transform data because you can run into unforeseen
problems, such
as failing the Turkey Test. For an example, see the blog article titled
Using Pester to Test PowerShell Code with Other Cultures . My recommendation is to
use an
operator instead of a method whenever possible to avoid these types of
problems.
While the comparison operators can be used as shown in the previous examples, I
normally find myself
using them with the Where-Object cmdlet to perform some type of
filtering.
Summary
In this chapter, you've learned a number of different topics to include Formatting Right,
Aliases,
Providers, and Comparison Operators.
Review
1. Why is it necessary to perform Formatting as far to the right as possible?
2. How do you determine what the actual cmdlet is for the % alias?
3. Why shouldn't you use aliases in scripts you save or code you share with others?
4. Perform a directory listing on the drives that are associated with one of the registry
providers.
5. What's one of the main benefits of using the replace operator instead of the
replace method?
Recommended Reading
Format-Table
Format-List
Format-Wide
about_Aliases
about_Providers
about_Comparison_Operators
about_Arrays
Chapter 6 - Flow control
Article • 12/09/2022
Scripting
When you move from writing PowerShell one-liners to writing scripts, it sounds a lot
more
complicated than it really is. A script is nothing more than the same or similar
commands that you
would run interactively in the PowerShell console, except they're
saved as a .PS1 file. There are
some scripting constructs that you may use such as a
foreach loop instead of the ForEach-Object
cmdlet. To beginners, the differences can
be confusing especially when you consider that foreach
is both a scripting construct
and an alias for the ForEach-Object cmdlet.
Looping
One of the great things about PowerShell is, once you figure out how to do something
for one item,
it's almost as easy to do the same task for hundreds of items. Simply loop
through the items using
one of the many different types of loops in PowerShell.
ForEach-Object
ForEach-Object is a cmdlet for iterating through items in a pipeline such as with
PowerShell
one-liners. ForEach-Object streams the objects through the pipeline.
Although the Module parameter of Get-Command accepts multiple values that are strings,
it only
accepts them via pipeline input by property name or via parameter input. In the
following scenario,
if I want to pipe two strings by value to Get-Command for use with the
Module parameter, I
would need to use the ForEach-Object cmdlet.
PowerShell
'ActiveDirectory', 'SQLServer' |
Output
Count Name
----- ----
147 ActiveDirectory
82 SqlServer
In the previous example, $_ is the current object. Beginning with PowerShell version 3.0,
$PSItem can be used instead of $_ . But I find that most experienced PowerShell users
still
prefer using $_ since it's backward compatible and less to type.
When using the foreach keyword, you must store all of the items in memory before
iterating through
them, which could be difficult if you don't know how many items
you're working with.
PowerShell
Output
DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :
DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
PowerShell
Output
At line:1 char:26
+ ~~~~~~~~~~~~~~~
eption
+ FullyQualifiedErrorId :
CannotConvertArgument,Microsoft.ActiveDirectory.Management
.Commands.GetADComputer
Other times, you can get the same results while eliminating the loop altogether. Consult
the cmdlet
help to understand your options.
PowerShell
Output
DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :
DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
As you can see in the previous examples, the Identity parameter for Get-ADComputer
only accepts a
single value when provided via parameter input, but it allows for multiple
items when the input is
provided via pipeline input.
For
A for loop iterates while a specified condition is true. The for loop is not something
that I
use often, but it does have its uses.
PowerShell
Start-Sleep -Seconds $i
Output
In the previous example, the loop will iterate four times by starting off with the number
one and
continue as long as the counter variable $i is less than 5. It will sleep for a total
of 10
seconds.
Do
There are two different do loops in PowerShell. Do Until runs while the specified
condition is
false.
PowerShell
do {
Output
Too low!
Too low!
The previous example is a numbers game that continues until the value you guess
equals the same
number that the Get-Random cmdlet generated.
Do While is just the opposite. It runs as long as the specified condition evaluates to true.
PowerShell
do {
Output
Too low!
Too low!
Too low!
The same results are achieved with a Do While loop by reversing the test condition to
not equals.
Do loops always run at least once because the condition is evaluated at the end of the
loop.
While
Similar to the Do While loop, a While loop runs as long as the specified condition is
true. The
difference however, is that a While loop evaluates the condition at the top of
the loop before any
code is run. So it doesn't run if the condition evaluates to false.
PowerShell
$date = Get-Date -Date 'November 22'
$date = $date.AddDays(1)
Write-Output $date
Output
The previous example calculates what day Thanksgiving Day is on in the United States.
It's always on
the fourth Thursday of November. So the loop starts with the 22nd day of
November and adds a day
while the day of the week isn't equal to Thursday. If the 22nd
is a Thursday, the loop doesn't run
at all.
PowerShell
Start-Sleep -Seconds $i
break
Output
The break statement shown in the previous example causes the loop to exit on the first
iteration.
PowerShell
$i += 1
if ($i -eq 3) {
continue
Write-Output $i
Output
The previous example will output the numbers 1, 2, 4, and 5. It skips number 3 and
continues with
the next iteration of the loop. Similar to break , continue breaks out of
the loop except only
for the current iteration. Execution continues with the next iteration
instead of breaking out of
the loop and stopping.
PowerShell
$number = 1..10
if ($n -ge 4) {
Return $n
Output
Notice that in the previous example, return outputs the first result and then exits out of
the
loop. A more thorough explanation of the result statement can be found in one of
my blog articles:
"The PowerShell return keyword" .
Summary
In this chapter, you've learned about the different types of loops that exist in PowerShell.
Review
1. What is the difference in the ForEach-Object cmdlet and the foreach scripting
construct?
2. What is the primary advantage of using a While loop instead of a Do While or Do
Until loop.
3. How do the break and continue statements differ?
Recommended Reading
ForEach-Object
about_ForEach
about_For
about_Do
about_While
about_Break
about_Continue
about_Return
Chapter 7 - Working with WMI
Article • 12/09/2022
PowerShell has had cmdlets for working with WMI since the beginning. Get-Command can
be used to
determine what WMI cmdlets exist in PowerShell. The following results are
from my Windows 10 lab
environment computer that is running PowerShell version 5.1.
Your results may differ depending on
what PowerShell version you're running.
PowerShell
Output
Common Information Model (CIM) cmdlets were introduced in PowerShell version 3.0.
The CIM cmdlets
are designed so they can be used on both Windows and non-Windows
machines. The WMI cmdlets are
deprecated so my recommendation is to use the CIM
cmdlets instead of the older WMI ones.
The CIM cmdlets are all contained within a module. To obtain a list of the CIM cmdlets,
use
Get-Command with the Module parameter as shown in the following example.
PowerShell
Output
The CIM cmdlets still allow you to work with WMI so don't be confused when someone
makes the
statement "When I query WMI with the PowerShell CIM cmdlets..."
VB
strComputer = "."
Next
You can take the WQL query from that VBScript and use it with the Get-CimInstance
cmdlet without
any modifications.
PowerShell
Output
SMBIOSBIOSVersion : 090006
SerialNumber : 3810-1995-1654-4615-2295-2755-89
That's not how I typically query WMI with PowerShell. But it does work and allows you to
easily
migrate existing VBScripts to PowerShell. When I start out writing a one-liner to
query WMI, I use
the following syntax.
PowerShell
Output
SMBIOSBIOSVersion : 090006
SerialNumber : 3810-1995-1654-4615-2295-2755-89
If I only want the serial number, I can pipe the output to Select-Object and specify only
the
SerialNumber property.
PowerShell
Output
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89
By default, there are several properties that are retrieved behind the scenes that are
never used.
It may not matter much when querying WMI on the local computer. But
once you start querying remote
computers, it's not only additional processing time to
return that information, but also additional
unnecessary information to have to pull
across the network. Get-CimInstance has a Property
parameter that limits the
information that's retrieved. This makes the query to WMI more efficient.
PowerShell
Output
SerialNumber
------------
3810-1995-1654-4615-2295-2755-89
The previous results returned an object. To return a simple string, use the
ExpandProperty
parameter.
PowerShell
Output
3810-1995-1654-4615-2295-2755-89
You could also use the dotted style of syntax to return a simple string. This eliminates
the need to
pipe to Select-Object .
PowerShell
Output
3810-1995-1654-4615-2295-2755-89
PowerShell
Output
At line:1 char:1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied:
(root\cimv2:Win32_BIOS:String) [Get-CimI
nstance], CimException
+ FullyQualifiedErrorId : HRESULT
0x80070005,Microsoft.Management.Infrastructure.Cim
Cmdlets.GetCimInstanceCommand
+ PSComputerName : dc01
Many people have security concerns when it comes to PowerShell, but the truth is you
have exactly
the same permissions in PowerShell as you do in the GUI. No more and no
less. The problem in the
previous example is that the user running PowerShell doesn't
have rights to query WMI information
from the DC01 server. I could relaunch PowerShell
as a domain administrator since Get-CimInstance
doesn't have a Credential parameter.
But, trust me, that isn't a good idea because then anything
that I run from PowerShell
would be running as a domain admin. That could be dangerous from a
security
standpoint depending on the situation.
Using the principle of least privilege, I elevate to my domain admin account on a per
command basis
using the Credential parameter, if a command has one. Get-
CimInstance doesn't have a
Credential parameter so the solution in this scenario is to
PowerShell
Output
Credential
The CIM session was stored in a variable named $CimSession . Notice that I also specified
the
Get-Credential cmdlet in parentheses so that it executes first, prompting me for
alternate
credentials, before creating the new session. I'll show you another more
efficient way to specify
alternate credentials later in this chapter, but it's important to
understand this basic concept
before making it more complicated.
The CIM session created in the previous example can now be used with the Get-
CimInstance cmdlet to
query the BIOS information from WMI on the remote computer.
PowerShell
Output
SMBIOSBIOSVersion : 090006
SerialNumber : 0986-6980-3916-0512-6608-8243-13
PSComputerName : dc01
There are several additional benefits to using CIM sessions instead of just specifying a
computer
name. When running multiple queries to the same computer, using a CIM
session is more efficient than
using the computer name for each query. Creating a CIM
session only sets up the connection once.
Then, multiple queries use that same session
to retrieve information. Using the computer name
requires the cmdlets to set up and
tear down the connection with each individual query.
The Get-CimInstance cmdlet uses the WSMan protocol by default, which means the
remote computer
needs PowerShell version 3.0 or higher to connect. It's actually not the
PowerShell version that
matters, it's the stack version. The stack version can be
determined using the Test-WSMan cmdlet.
It needs to be version 3.0. That's the version
you'll find with PowerShell version 3.0 and higher.
PowerShell
Output
wsmid :
http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
The older WMI cmdlets use the DCOM protocol, which is compatible with older versions
of Windows. But
DCOM is typically blocked by the firewall on newer versions of
Windows. The New-CimSessionOption
cmdlet allows you to create a DCOM protocol
connection for use with New-CimSession . This allows
the Get-CimInstance cmdlet to be
used to communicate with versions of Windows as old as Windows
Server 2000. This
also means that PowerShell is not required on the remote computer when using the
Get-CimInstance cmdlet with a CimSession that's configured to use the DCOM protocol.
Create the DCOM protocol option using the New-CimSessionOption cmdlet and store it in
a variable.
PowerShell
For efficiency, you can store your domain administrator or elevated credentials in a
variable so you
don't have to constantly enter them for each command.
PowerShell
$Cred = Get-Credential
Output
Credential
I have a server named SQL03 that runs Windows Server 2008 (non-R2). It's the newest
Windows Server
operating system that doesn't have PowerShell installed by default.
PowerShell
Notice in the previous command, this time I specified the variable named $Cred as the
value for
the Credential parameter instead of having to enter them manually again.
The output of the query is the same regardless of the underlying protocol being used.
PowerShell
Output
SMBIOSBIOSVersion : 090006
SerialNumber : 7237-7483-8873-8926-7271-5004-86
PSComputerName : sql03
The Get-CimSession cmdlet is used to see what CimSessions are currently connected
and what
protocols they're using.
PowerShell
Get-CimSession
Output
Id : 1
Name : CimSession1
InstanceId : 80742787-e38e-41b1-a7d7-fa1369cf1402
ComputerName : dc01
Protocol : WSMAN
Id : 2
Name : CimSession2
InstanceId : 8fcabd81-43cf-4682-bd53-ccce1e24aecb
ComputerName : sql03
Protocol : DCOM
Retrieve and store both of the previously created CimSessions in a variable named
$CimSession .
PowerShell
$CimSession = Get-CimSession
Query both of the computers with one command, one using the WSMan protocol and
the other one with
DCOM.
PowerShell
Output
SMBIOSBIOSVersion : 090006
SerialNumber : 0986-6980-3916-0512-6608-8243-13
PSComputerName : dc01
SMBIOSBIOSVersion : 090006
SerialNumber : 7237-7483-8873-8926-7271-5004-86
PSComputerName : sql03
I've written numerous blog articles about the WMI and CIM cmdlets. One of the most
useful ones is
about a function that I created to automatically determine if WSMan or
DCOM should be used and set
up the CIM session automatically without having to
figure out which one manually. That blog article
is titled PowerShell Function to Create
CimSessions to Remote Computers with Fallback to Dcom .
When you're finished with the CIM sessions, you should remove them with the Remove-
CimSession
cmdlet. To remove all CIM sessions, simply pipe Get-CimSession to Remove-
CimSession .
PowerShell
Get-CimSession | Remove-CimSession
Summary
In this chapter, you've learned about using PowerShell to work with WMI on both local
and remote
computers. You've also learned how to use the CIM cmdlets to work with
remote computers with both
the WSMan or DCOM protocol.
Review
1. What is the difference in the WMI and CIM cmdlets?
2. By default, what protocol does the Get-CimInstance cmdlet use?
3. What are some of the benefits of using a CIM session instead of specifying a
computer name with
Get-CimInstance ?
4. How do you specify an alternate protocol other than the default one for use with
Get-CimInstance ?
Recommended Reading
about_WMI
about_WMI_Cmdlets
about_WQL
CimCmdlets Module
Video: Using CIM Cmdlets and CIM Sessions
Chapter 8 - PowerShell remoting
Article • 12/09/2022
PowerShell has many different ways to run commands against remote computers. In the
last chapter,
you saw how to remotely query WMI using the CIM cmdlets. PowerShell
also includes several cmdlets
that have a built-in ComputerName parameter.
As shown in the following example, Get-Command can be used with the ParameterName
parameter to
determine what commands have a ComputerName parameter.
PowerShell
Output
To use the PowerShell remoting commands that are demonstrated in this chapter,
PowerShell remoting
must be enabled on the remote computer. Use the Enable-
PSRemoting cmdlet to enable PowerShell
remoting.
PowerShell
Enable-PSRemoting
Output
WinRM has been updated to receive requests.
One-To-One Remoting
If you want your remote session to be interactive, then one-to-one remoting is what you
want.
This type of remoting is provided via the Enter-PSSession cmdlet.
In the last chapter, I stored my domain admin credentials in a variable named $Cred . If
you
haven't already done so, go ahead and store your domain admin credentials in the
$Cred variable.
This allows you to enter the credentials once and use them on a per command basis as
long as your
current PowerShell session is active.
PowerShell
$Cred = Get-Credential
Create a one-to-one PowerShell remoting session to the domain controller named dc01.
PowerShell
Output
[dc01]: PS C:\Users\Administrator\Documents>
Notice that in the previous example that the PowerShell prompt is preceded by [dc01] .
This means
you're in an interactive PowerShell session to the remote computer named
dc01. Any commands you
execute run on dc01, not on your local computer. Also, keep
in mind that you only have access to the
PowerShell commands that exist on the remote
computer and not the ones on your local computer. In
other words, if you've installed
additional modules on your computer, they aren't accessible on the
remote computer.
PowerShell
Output
TypeName: System.Diagnostics.Process
PM AliasProperty PM = PagedMemorySize64
SI AliasProperty SI = SessionId
VM AliasProperty VM = VirtualMemorySize64
WS AliasProperty WS = WorkingSet64
ErrorDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
OutputDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
Modules Property
System.Diagnostics.ProcessModuleCollection M...
PriorityClass Property
System.Diagnostics.ProcessPriorityClass Prio...
SafeHandle Property
Microsoft.Win32.SafeHandles.SafeProcessHandl...
StartInfo Property
System.Diagnostics.ProcessStartInfo StartInf...
SynchronizingObject Property
System.ComponentModel.ISynchronizeInvoke Syn...
Threads Property
System.Diagnostics.ProcessThreadCollection T...
[dc01]:
When you're done working with the remote computer, exit the one-to-one remoting
session by using the
Exit-PSSession cmdlet.
PowerShell
[dc01]: Exit-PSSession
One-To-Many Remoting
Sometimes you may need to perform a task interactively on a remote computer. But
remoting is much
more powerful when performing a task on multiple remote computers
at the same time. Use the
Invoke-Command cmdlet to run a command against one or
more remote computers at the same time.
PowerShell
Output
In the previous example, three servers were queried for the status of the Windows Time
service. The
Get-Service cmdlet was placed inside the script block of Invoke-Command .
Get-Service actually
runs on the remote computer and the results are returned to your
Piping the previous command to Get-Member shows that the results are indeed
deserialized objects.
PowerShell
Output
TypeName: Deserialized.System.ServiceProcess.ServiceController
RequiredServices NoteProperty
Deserialized.System.ServiceProcess.ServiceController[...
DependentServices Property
Deserialized.System.ServiceProcess.ServiceController[...
ServicesDependedOn Property
Deserialized.System.ServiceProcess.ServiceController[...
Notice that the majority of the methods are missing on deserialized objects. This means
they're not
live objects; they're inert. You can't start or stop a service using a deserialized
object because
it's a snapshot of the state of that object the point when the command
ran on the remote computer.
That doesn't mean you can't start or stop a service using a method with Invoke-Command
though. It
just means that the method has to be called in the remote session.
I'll stop the Windows Time service on all three of those remote servers using the Stop()
method
to prove this point.
PowerShell
Output
PowerShell Sessions
In the last example in the previous section, I ran two commands using the Invoke-
Command cmdlet.
That means two separate sessions had to be set up and torn down to
Create a PowerShell session to each of the three computers we've been working with in
this chapter,
DC01, SQL02, and WEB01.
PowerShell
Now use the variable named $Session to start the Windows Time service using a
method and check the
status of the service.
PowerShell
Output
Once the session is created using alternate credentials, it's no longer necessary to
specify the
credentials each time a command is run.
PowerShell
Get-PSSession | Remove-PSSession
Summary
In this chapter you've learned about PowerShell remoting, how to run commands in an
interactive
session with one remote computer, and how to run commands against
multiple computers using
one-to-many remoting. You've also learned the benefits of
using a PowerShell session when running
multiple commands against the same remote
computer.
Review
1. How do you enable PowerShell remoting?
2. What is the PowerShell command for starting an interactive session with a remote
computer?
3. What is a benefit of using a PowerShell remoting session versus just specifying the
computer name
with each command?
4. Can a PowerShell remoting session be used with a one-to-one remoting session?
5. What is the difference in the type of objects that are returned by cmdlets versus
those returned
when running those same cmdlets against remote computers with
Invoke-Command ?
Recommended Reading
about_Remote
about_Remote_Output
about_Remote_Requirements
about_Remote_Troubleshooting
about_Remote_Variables
PowerShell Remoting FAQ
Chapter 9 - Functions
Article • 11/17/2022
If you're writing PowerShell one-liners or scripts and find yourself often having to
modify them for
different scenarios, there's a good chance that it's a good candidate to
be turned into a function
that can be reused.
Whenever possible, I prefer to write functions because they are more tool oriented. I can
put the
functions in a script module, put that module in the $env:PSModulePath , and call
the functions
without needing to physically locate where they're saved. Using the
PowerShellGet module, it's easy
to share those modules in a NuGet repository.
PowerShellGet ships with PowerShell version 5.0 and
higher. It is available as a separate
download for PowerShell version 3.0 and higher.
Don't over complicate things. Keep it simple and use the most straight forward way to
accomplish a
task. Avoid aliases and positional parameters in any code that you reuse.
Format your code for
readability. Don't hardcode values; use parameters and variables.
Don't write unnecessary code even
if it doesn't hurt anything. It adds unnecessary
complexity. Attention to detail goes a long
way when writing any PowerShell code.
Naming
When naming your functions in PowerShell, use a Pascal case name with an approved
verb and a
singular noun. I also recommend prefixing the noun. For example:
<ApprovedVerb>-<Prefix><SingularNoun> .
In PowerShell, there's a specific list of approved verbs that can be obtained by running
Get-Verb .
PowerShell
Output
Verb Group
---- -----
Add Common
Approve Lifecycle
Assert Lifecycle
Backup Data
Block Security
Checkpoint Data
Clear Common
Close Common
Compare Data
Complete Lifecycle
Compress Data
Confirm Lifecycle
Connect Communications
Convert Data
ConvertFrom Data
ConvertTo Data
Copy Common
Debug Diagnostic
Deny Lifecycle
Disable Lifecycle
Disconnect Communications
Dismount Data
Edit Data
Enable Lifecycle
Enter Common
Exit Common
Expand Data
Export Data
Find Common
Format Common
Get Common
Grant Security
Group Data
Hide Common
Import Data
Initialize Data
Install Lifecycle
Invoke Lifecycle
Join Common
Limit Data
Lock Common
Measure Diagnostic
Merge Data
Mount Data
Move Common
New Common
Open Common
Optimize Common
Out Data
Ping Diagnostic
Pop Common
Protect Security
Publish Data
Push Common
Read Communications
Receive Communications
Redo Common
Register Lifecycle
Remove Common
Rename Common
Repair Diagnostic
Request Lifecycle
Reset Common
Resize Common
Resolve Diagnostic
Restart Lifecycle
Restore Data
Resume Lifecycle
Revoke Security
Save Data
Search Common
Select Common
Send Communications
Set Common
Show Common
Skip Common
Split Common
Start Lifecycle
Step Common
Stop Lifecycle
Submit Lifecycle
Suspend Lifecycle
Switch Common
Sync Data
Test Diagnostic
Trace Diagnostic
Unblock Security
Undo Common
Uninstall Lifecycle
Unlock Common
Unprotect Security
Unpublish Data
Unregister Lifecycle
Update Data
Use Other
Wait Lifecycle
Watch Common
Write Communications
In the previous example, I've sorted the results by the Verb column. The Group column
gives
you an idea of how these verbs are used. It's important to choose an approved
verb in PowerShell
when functions are added to a module. The module generates a
warning message at load time if you
choose an unapproved verb. That warning message
makes your functions look unprofessional. Unapproved
verbs also limit the
discoverability of your functions.
A simple function
A function in PowerShell is declared with the function keyword followed by the function
name and
then an open and closing curly brace. The code that the function will execute
is contained within
those curly braces.
PowerShell
function Get-Version {
$PSVersionTable.PSVersion
The function shown is a simple example that returns the version of PowerShell.
PowerShell
Get-Version
Output
5 1 14393 693
There's a good chance of name conflict with functions named something like Get-
Version and default
commands in PowerShell or commands that others may write. This
is why I recommend prefixing the noun
portion of your functions to help prevent
naming conflicts. In the following example, I'll use the
prefix "PS".
PowerShell
function Get-PSVersion {
$PSVersionTable.PSVersion
Other than the name, this function is identical to the previous one.
PowerShell
Get-PSVersion
Output
5 1 14393 693
Even when prefixing the noun with something like PS, there's still a good chance of
having a name
conflict. I typically prefix my function nouns with my initials. Develop a
standard and stick to it.
PowerShell
function Get-MrPSVersion {
$PSVersionTable.PSVersion
This function is no different than the previous two other than using a more sensible
name to try to
prevent naming conflicts with other PowerShell commands.
PowerShell
Get-MrPSVersion
Output
5 1 14393 693
Once loaded into memory, you can see functions on the Function PSDrive.
PowerShell
Output
Function Get-Version
Function Get-PSVersion
Function Get-MrPSVersion
If you want to remove these functions from your current session, you'll have to remove
them from the
Function PSDrive or close and reopen PowerShell.
PowerShell
PowerShell
If the functions were loaded as part of a module, the module can be unloaded to
remove them.
PowerShell
The Remove-Module cmdlet removes modules from memory in your current PowerShell
session, it
doesn't remove them from your system or from disk.
Parameters
Don't statically assign values! Use parameters and variables. When it comes to naming
your
parameters, use the same name as the default cmdlets for your parameter names
whenever possible.
PowerShell
function Test-MrParameter {
param (
$ComputerName
Write-Output $ComputerName
Why did I use ComputerName and not Computer, ServerName, or Host for my
parameter
name? It's because I wanted my function standardized like the default
cmdlets.
I'll create a function to query all of the commands on a system and return the number of
them that
have specific parameter names.
PowerShell
function Get-MrParameterCount {
param (
[string[]]$ParameterName
[pscustomobject]@{
ParameterName = $Parameter
NumberOfCmdlets = $Results.Count
As you can see in the results shown below, 39 commands that have a ComputerName
parameter. There
aren't any cmdlets that have parameters such as Computer,
ServerName, Host, or
Machine.
PowerShell
Output
ParameterName NumberOfCmdlets
------------- ---------------
ComputerName 39
Computer 0
ServerName 0
Host 0
Machine 0
I also recommend using the same case for your parameter names as the default cmdlets.
Use
ComputerName , not computername . This makes your functions look and feel like the
default
cmdlets. People who are already familiar with PowerShell will feel right at home.
The param statement allows you to define one or more parameters. The parameter
definitions are
separated by a comma ( , ). For more information, see
about_Functions_Advanced_Parameters.
Advanced Functions
Turning a function in PowerShell into an advanced function is really simple. One of the
differences
between a function and an advanced function is that advanced functions
have a number of common
parameters that are added to the function automatically.
These common parameters include parameters
such as Verbose and Debug.
I'll start out with the Test-MrParameter function that was used in the previous section.
PowerShell
function Test-MrParameter {
param (
$ComputerName
Write-Output $ComputerName
What I want you to notice is that the Test-MrParameter function doesn't have any
common
parameters. There are a couple of different ways to see the common
parameters. One is by viewing the
syntax using Get-Command .
PowerShell
Output
PowerShell
Output
ComputerName
PowerShell
function Test-MrCmdletBinding {
param (
$ComputerName
Write-Output $ComputerName
PowerShell
Output
Drilling down into the parameters with Get-Command shows the actual parameter names
including the
common ones.
PowerShell
Output
ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
SupportsShouldProcess
SupportsShouldProcess adds WhatIf and Confirm parameters. These are only needed for
PowerShell
function Test-MrSupportsShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param (
$ComputerName
Write-Output $ComputerName
PowerShell
Output
Once again, you can also use Get-Command to return a list of the actual parameter names
including
the common ones along with WhatIf and Confirm.
PowerShell
Output
ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
WhatIf
Confirm
Parameter Validation
Validate input early on. Why allow your code to continue on a path when it's not
possible to
run without valid input?
Always type the variables that are being used for your parameters (specify a datatype).
PowerShell
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[string]$ComputerName
Write-Output $ComputerName
In the previous example, I've specified String as the datatype for the ComputerName
parameter. This causes it to allow only a single computer name to be specified. If more
than one
computer name is specified via a comma-separated list, an error is generated.
PowerShell
Output
At line:1 char:42
umentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Test-
MrParameterValidation
The problem with the current definition is that it's valid to omit the value of the
ComputerName
parameter, but a value is required for the function to complete
successfully. This is where the
Mandatory parameter attribute comes in handy.
PowerShell
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$ComputerName
Write-Output $ComputerName
The syntax used in the previous example is PowerShell version 3.0 and higher
compatible.
[Parameter(Mandatory=$true)] could be specified instead to make the
function compatible with
PowerShell version 2.0 and higher. Now that the
ComputerName is required, if one isn't
specified, the function will prompt for one.
PowerShell
Test-MrParameterValidation
Output
ComputerName:
If you want to allow for more than one value for the ComputerName parameter, use the
String
datatype but add open and closed square brackets to the datatype to allow for
an array of strings.
PowerShell
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string[]]$ComputerName
Write-Output $ComputerName
Maybe you want to specify a default value for the ComputerName parameter if one isn't
specified.
The problem is that default values can't be used with mandatory parameters.
Instead, you'll need to
use the ValidateNotNullOrEmpty parameter validation attribute
with a default value.
PowerShell
function Test-MrParameterValidation {
[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
Write-Output $ComputerName
Even when setting a default value, try not to use static values. In the previous example,
$env:COMPUTERNAME is used as the default value, which is automatically translated into the
local
computer name if a value is not provided.
Verbose Output
While inline comments are useful, especially if you're writing some complex code, they
never get
seen by users unless they look into the code itself.
The function shown in the following example has an inline comment in the foreach
loop. While this
particular comment may not be that difficult to locate, imagine if the
function included hundreds of
lines of code.
PowerShell
function Test-MrVerboseOutput {
[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
Write-Output $Computer
PowerShell
function Test-MrVerboseOutput {
[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
Write-Output $Computer
When the function is called without the Verbose parameter, the verbose output won't
be
displayed.
PowerShell
When it's called with the Verbose parameter, the verbose output will be displayed.
PowerShell
Pipeline Input
When you want your function to accept pipeline input, some additional coding is
necessary. As
mentioned earlier in this book, commands can accept pipeline input by
value (by type) or by
property name. You can write your functions just like the native
commands so that they accept
either one or both of these types of input.
Pipeline input comes in one item at a time similar to the way items are handled in a
foreach loop.
At a minimum, a process block is required to process each of these items
if you're accepting an
array as input. If you're only accepting a single value as input, a
process block isn't necessary,
but I still recommend specifying it for consistency.
PowerShell
function Test-MrPipelineInput {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline)]
[string[]]$ComputerName
PROCESS {
Write-Output $ComputerName
Accepting pipeline input by property name is similar except it's specified with the
ValueFromPipelineByPropertyName parameter attribute and it can be specified for any
number of
parameters regardless of datatype. The key is that the output of the
command that's being piped in
has to have a property name that matches the name of
the parameter or a parameter alias of your
function.
PowerShell
function Test-MrPipelineInput {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
PROCESS {
Write-Output $ComputerName
BEGIN and END blocks are optional. BEGIN would be specified before the PROCESS block
and is
used to perform any initial work prior to the items being received from the
pipeline. This is
important to understand. Values that are piped in are not accessible in
the BEGIN block. The END
block would be specified after the PROCESS block and is used
for cleanup once all of the items
that are piped in have been processed.
Error Handling
The function shown in the following example generates an unhandled exception when a
computer can't
be contacted.
PowerShell
function Test-MrErrorHandling {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
PROCESS {
There are a couple of different ways to handle errors in PowerShell. Try/Catch is the
more modern
way to handle errors.
PowerShell
function Test-MrErrorHandling {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
PROCESS {
try {
catch {
Although the function shown in the previous example uses error handling, it also
generates an
unhandled exception because the command doesn't generate a
terminating error. This is also important
to understand. Only terminating errors are
caught. Specify the ErrorAction parameter with
Stop as the value to turn a non-
terminating error into a terminating one.
PowerShell
function Test-MrErrorHandling {
[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
PROCESS {
try {
catch {
Comment-Based Help
It's considered to be a best practice to add comment based help to your functions so
the people
you're sharing them with will know how to use them.
PowerShell
function Get-MrAutoStoppedService {
<#
.SYNOPSIS
Returns a list of services that are set to start automatically, are not
currently running, excluding the services that are set to delayed start.
.DESCRIPTION
currently running, and it excludes the services that are set to start
automatically
.PARAMETER ComputerName
.PARAMETER Credential
Specifies a user account that has permission to perform this action. The
default
.EXAMPLE
.EXAMPLE
.EXAMPLE
.INPUTS
String
.OUTPUTS
PSCustomObject
.NOTES
Website: http://mikefrobbins.com
Twitter: @mikefrobbins
#>
[CmdletBinding()]
param (
#Function Body
When you add comment based help to your functions, help can be retrieved for them
just like the
default built-in commands.
All of the syntax for writing a function in PowerShell can seem overwhelming especially
for someone
who is just getting started. Often times if I can't remember the syntax for
something, I'll open a
second copy of the ISE on a separate monitor and view the
"Cmdlet (advanced function) - Complete"
snippet while typing in the code for my
function. Snippets can be accessed in the PowerShell ISE
using the Ctrl + J key
combination.
Summary
In this chapter you've learned the basics of writing functions in PowerShell to include
how to turn
a function into an advanced function and some of the more important
elements that you should
consider when writing PowerShell functions such as parameter
validation, verbose output, pipeline
input, error handling, and comment based help.
Review
1. How do you obtain a list of approved verbs in PowerShell?
2. How do you turn a PowerShell function into an advanced function?
3. When should WhatIf and Confirm parameters be added to your PowerShell
functions?
4. How do you turn a non-terminating error into a terminating one?
5. Why should you add comment based help to your functions?
Recommended Reading
about_Functions
about_Functions_Advanced_Parameters
about_CommonParameters
about_Functions_CmdletBindingAttribute
about_Functions_Advanced
about_Try_Catch_Finally
about_Comment_Based_Help
Video: PowerShell Toolmaking with Advanced Functions and Script Modules
Chapter 10 - Script modules
Article • 12/09/2022
Turning your one-liners and scripts in PowerShell into reusable tools becomes even
more important if
it's something that you're going to use frequently. Packaging your
functions in a script module
makes them look and feel more professional and makes
them easier to share.
Dot-Sourcing Functions
Something that we didn't talk about in the previous chapter is dot-sourcing functions.
When a
function in a script isn't part of a module, the only way to load it into memory is
to dot-source
the .PS1 file that it's saved in.
PowerShell
function Get-MrPSVersion {
$PSVersionTable
PowerShell
.\Get-MrPSVersion.ps1
PowerShell
Get-MrPSVersion
Output
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.
At line:1 char:1
+ Get-MrPSVersion
ndException
+ FullyQualifiedErrorId : CommandNotFoundException
You can determine if functions are loaded into memory by checking to see if they exist
on the
Function PSDrive.
PowerShell
Output
At line:1 char:1
ItemNotFoundException
+ FullyQualifiedErrorId :
PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
The problem with calling the script that contains the function is that the functions are
loaded in
the Script scope. When the script completes, that scope is removed and the
function is removed
with it.
The function needs to be loaded into the Global scope. That can be accomplished by
dot-sourcing
the script that contains the function. The relative path can be used.
PowerShell
. .\Get-MrPSVersion.ps1
PowerShell
. C:\Demo\Get-MrPSVersion.ps1
If a portion of the path is stored in a variable, it can be combined with the remainder of
the path.
There's no reason to use string concatenation to combine the variable
together with the remainder of
the path.
PowerShell
$Path = 'C:\'
. $Path\Get-MrPSVersion.ps1
Now when I check the Function PSDrive, the Get-MrPSVersion function exists.
PowerShell
Output
Function Get-MrPSVersion
Script Modules
A script module in PowerShell is simply a file containing one or more functions that's
saved as a
.PSM1 file instead of a .PS1 file.
How do you create a script module? You're probably guessing with a command named
something like
New-Module . Your assumption would be wrong. While there is a
command in PowerShell named
New-Module , that command creates a dynamic module,
not a script module. Always be sure to read the
help for a command even when you
think you've found the command you need.
PowerShell
help New-Module
Output
NAME
New-Module
SYNOPSIS
SYNTAX
[<CommonParameters>]
DESCRIPTION
The New-Module cmdlet creates a dynamic module from a script block. The
members of
the session and remain available until you close the session.
exported and the variables and aliases are not. However, you can use the
the session.
Dynamic modules exist only in memory, not on disk. Like all modules, the
members of
Get-Module cannot get a dynamic module, but Get-Command can get the
exported members.
This action adds the dynamic module to the Get-Module list, but it does
not save the
RELATED LINKS
Export-ModuleMember
Get-Module
Import-Module
Remove-Module
REMARKS
In the previous chapter, I mentioned that functions should use approved verbs
otherwise they'll
generate a warning message when the module is imported. The
following code uses the New-Module
cmdlet to create a dynamic module in memory. This
module demonstrates the unapproved verb warning.
PowerShell
function Return-MrOsVersion {
} | Import-Module
Output
WARNING: The names of some imported commands from the module 'MyModule'
include
unapproved verbs that might make them less discoverable. To find the
commands with
unapproved verbs, run the Import-Module command again with the Verbose
parameter. For a
Just to reiterate, although the New-Module cmdlet was used in the previous example,
that's not the
command for creating script modules in PowerShell.
PowerShell
function Get-MrPSVersion {
$PSVersionTable
function Get-MrComputerName {
$env:COMPUTERNAME
PowerShell
Get-MrComputerName
Output
if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-MrComputerName
FoundException
+ FullyQualifiedErrorId : CommandNotFoundException
An error message is generated saying the function can't be found. You could also check
the
Function PSDrive just like before and you'll find that it doesn't exist there either.
You could manually import the file with the Import-Module cmdlet.
PowerShell
Import-Module C:\MyScriptModule.psm1
PowerShell
$env:PSModulePath
Output
C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules;C:\Program
Files\WindowsPowerShell\
Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files
(x86)\Microsof
t SQL Server\130\Tools\PowerShell\Modules\
The results are difficult to read. Since the paths are separated by a semicolon, you can
split the
results to return each path on a separate line. This makes them easier to read.
PowerShell
$env:PSModulePath -split ';'
Output
C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules
The first three paths in the list are the default. When SQL Server Management Studio
was installed,
it added the last path. For module autoloading to work, the
MyScriptModule.psm1 file needs to be
located in a folder named MyScriptModule directly
inside one of those paths.
Not so fast. For me, my current user path isn't the first one in the list. I almost never use
that
path since I log into Windows with a different user than the one I use to run
PowerShell. That means
it's not located in my normal Documents folder.
The second path is the AllUsers path. This is the location where I store all of my
modules.
Once the .PSM1 file is located in the correct path, the module will load automatically
when one of
its commands is called.
Module Manifests
All modules should have a module manifest. A module manifest contains metadata
about your module.
The file extension for a module manifest file is .PSD1 . Not all files
with a .PSD1 extension are
module manifests. They can also be used for things such as
storing the environmental portion of a
DSC configuration. New-ModuleManifest is used to
create a module manifest. Path is the only
value that's required. However, the module
won't work if RootModule isn't specified. It's a good
idea to specify Author and
Description in case you decide to upload your module to a NuGet
repository with
PowerShellGet since those values are required in that scenario.
The version of a module without a manifest is 0.0. This is a dead giveaway that the
module doesn't
have a manifest.
PowerShell
Get-Module -Name MyScriptModule
Output
The module manifest can be created with all of the recommended information.
PowerShell
New-ModuleManifest -Path
$env:ProgramFiles\WindowsPowerShell\Modules\MyScriptModule\MyScriptModule.ps
d1 -RootModule MyScriptModule -Author 'Mike F Robbins' -Description
'MyScriptModule' -CompanyName 'mikefrobbins.com'
If any of this information is missed during the initial creation of the module manifest, it
can be
added or updated later using Update-ModuleManifest . Don't recreate the
manifest using
New-ModuleManifest once it's already created because the GUID will
change.
If you're not following the best practices and only have a .PSM1 file, then your only
option is to
use the Export-ModuleMember cmdlet.
PowerShell
function Get-MrPSVersion {
$PSVersionTable
function Get-MrComputerName {
$env:COMPUTERNAME
In the previous example, only the Get-MrPSVersion function is available to the users of
your
module, but the Get-MrComputerName function is available to other functions within
the module
itself.
PowerShell
Output
If you've added a module manifest to your module (and you should), then I recommend
specifying the
individual functions you want to export in the FunctionsToExport section
of the module manifest.
PowerShell
FunctionsToExport = 'Get-MrPSVersion'
It's not necessary to use both Export-ModuleMember in the .PSM1 file and the
FunctionsToExport section of the module manifest. One or the other is sufficient.
Summary
In this chapter you've learned how to turn your functions into a script module in
PowerShell. You've
also learned some of the best practices for creating script modules
such as creating a module
manifest for your script module.
Review
1. How do you create a script module in PowerShell?
2. Why is it important for your functions to use an approved verb?
3. How do you create a module manifest in PowerShell?
4. What are the two options for exporting only certain functions from your module?
5. What is required for your modules to load automatically when a command is
called?
Recommended Reading
How to Create PowerShell Script Modules and Module Manifests
about_Modules
New-ModuleManifest
Export-ModuleMember
Appendix A - Help Syntax
Article • 11/17/2022
The following example shows the SYNTAX section of the help for the Get-EventLog
cmdlet.
PowerShell
help Get-EventLog
Output
NAME
Get-EventLog
SYNOPSIS
Gets the events in an event log, or a list of the event logs, on the
local or remote
computers.
SYNTAX
[<CommonParameters>]
The syntax is primarily made up of several sets of opening and closing brackets ( [] ).
These have
two different meanings depending on how they're used. Anything contained
within square brackets is
optional unless they're a set of empty square brackets [] .
Empty square brackets only appear
after a datatype such as <string[]> . This means that
particular parameter can accept more than
one value of that type.
The first parameter in the first parameter set of Get-EventLog is LogName. LogName is
surrounded by square brackets which means that it's a positional parameter. In other
words,
specifying the name of the parameter itself is optional as long as it's specified in
the correct
position. The information in the angle brackets ( <> ) after the parameter
name indicates that it
needs a single string value. The entire parameter name and
datatype are not surrounded by square
brackets so the LogName parameter is required
when using this parameter set.
PowerShell
The second parameter is InstanceId. Notice that the parameter name and the datatype
are both
completely surrounded by square brackets. This means that the InstanceId
parameter is optional,
not mandatory. Also notice that InstanceId is surrounded by its
own set of square brackets. As
with the LogName parameter, this means the parameter
is positional. There's one last set of
square brackets after the datatype. This means that
it can accept more than one value in the form of
an array or a comma-separated list.
[[-InstanceId] <Int64[]>]
The second parameter set has a List parameter. It's a switch parameter because there's
no
datatype following the parameter name. When the List parameter is specified, the
value is
True. When it's not specified, the value is False.
[-List]
The syntax information for a command can also be retrieved using Get-Command using
the Syntax
parameter. This is a handy shortcut that I use all the time. It allows me to
quickly learn how to
use a command without having to sift through multiple pages of
help information. If I end up needing
more information, then I'll revert to using the
actual help content.
PowerShell
Output
[<CommonParameters>]
The more you use the help system in PowerShell, the easier remembering all of the
different nuances
becomes. Before you know it, using it becomes second nature.
Optimizing your shell experience
Article • 12/01/2022
Similar to other shells like bash or cmd.exe , PowerShell allows you to run any command
available
on your system, not just PowerShell commands.
Types of commands
For any shell in any operating system there are three types of commands:
Shell language keywords can only be used within the runtime environment of the
shell. There is no
executable file, external to the shell, that provides the keyword's
functionality.
OS-native commands are executable files installed in the operating system. The
executables can
be run from any command-line shell, like PowerShell. This includes
script files that may require
other shells to work properly. For example, if you run a
Windows batch script ( .cmd file) in
PowerShell, PowerShell runs cmd.exe and
passes in the batch file for execution.
Bash
sdwheeler@circumflex:~$ grep sdwheeler /etc/passwd
sdwheeler:x:1000:1000:,,,:/home/sdwheeler:/bin/bash
sdwheeler@circumflex:~$ pwsh
PowerShell 7.2.6
https://aka.ms/powershell
After starting PowerShell on Ubuntu, you can run the same command from the
PowerShell command line:
PowerShell
sdwheeler:x:1000:1000:,,,:/home/sdwheeler:/bin/bash
Each shell has its own way of handling and evaluating strings on the command line.
When running
native commands in PowerShell that expect strings to be quoted in a
specific way, you may need
adjust how you pass those strings.
about_Parsing
about_Quoting_Rules
When an native command has a non-zero exit code, $? is set to $false . If the exit code
is zero,
$? is set to $true .
However, this changed in PowerShell 7.2. Error records redirected from native
commands, like when
using redirection operators ( 2>&1 ), aren't written to PowerShell's
$Error variable and the
preference variable $ErrorActionPreference doesn't affect the
redirected output.
PSnativeCommandErrorActionPreference.
The Start-Process cmdlet can be used to run native commands, but should only be
used when you need
to control how the command is executed. The cmdlet has
parameters to support the following
scenarios:
The following example runs the native command sort.exe with redirected input and
output streams.
PowerShell
$processOptions = @{
FilePath = "sort.exe"
RedirectStandardInput = "TestSort.txt"
RedirectStandardOutput = "Sorted.txt"
RedirectStandardError = "SortError.txt"
UseNewEnvironment = $true
Start-Process @processOptions
On Windows, the Invoke-Item cmdlet performs the default action for the specified item.
For
example, it runs an executable file or opens a document file using the application
associated with
the document file type. The default action depends on the type of item
and is resolved by the
PowerShell provider that provides access to the item.
The following example opens the PowerShell source code repository in your default web
browser.
PowerShell
Invoke-Item https://github.com/PowerShell/PowerShell
PowerShell provides completions on input to provide hints, enable discovery, and speed
up input
entry. Command names, parameter names, argument values and file paths can
all be completed by
pressing the Tab key.
The Tab key is the default key binding on Windows. PSReadLine also provides a
MenuComplete function that's bound to Ctrl + Space . The MenuComplete
function displays
These keybindings can be changed using PSReadLine cmdlets or the application that's
hosting
PowerShell. Keybindings can be different on non-Windows platforms. For more
information, see
about_PSReadLine_Functions.
Filename completion
To fill in a filename or path from the available choices automatically, type part of the
name and
press the Tab key. PowerShell automatically expands the name to the first
match that it
finds. Pressing the Tab key again cycles through all the available choices
with each key
press.
PowerShell 7.0
Tab completion resolves variable assignments that are enums or are type
constrained
Tab completion expands abbreviated cmdlets and functions. For example, i-
psdf<tab> returns
Import-PowerShellDataFile
PowerShell 7.2
PowerShell 7.3
Fix tab completion within the script block specified for the
ValidateScriptAttribute
Added tab completion for loop labels after break and continue
Improve Hashtable completion in multiple scenarios
Parameter splatting
Arguments parameter for Invoke-CimMethod
FilterHashtable parameter for Get-WinEvent
Property parameter for the CIM cmdlets
Removes duplicates from member completion scenarios
Support forward slashes in network share (UNC path) completion
Improve member auto completion
Prioritize ValidateSet completions over enums for parameters
Add type inference support for generic methods with type parameters
Improve type inference and completions
Allows methods to be shown in completion results for ForEach-Object -
MemberName
Prevents completion on expressions that return void like ( [void]("") )
Allows non-default Class constructors to show up when class completion is
based on the AST
ArgumentCompletions
ValidateSet
The ArgumentCompleter attribute allows you to register a function that provides tab
completion
values to for the parameter. The argument completer function must be
available to the function
containing the parameter with the ArgumentCompleter attribute.
Usually, the function is defined in
the same script or module.
PSReadLine 2.2.2 extends the power of Predictive IntelliSense by adding support for
plug-in modules
that use advanced logic to provide suggestions for full commands. The
Az.Tools.Predictor module
was the first plug-in for Predictive IntelliSense. It uses
Machine Learning to predict what Azure
PowerShell command you want to run and the
parameters you want to use.
The previous images shows the default InlineView of the suggestion. Pressing
RightArrow
key accepts an inline suggestion. After accepting the suggestion, you can
edit the command line
before hitting Enter to run the command.
When in the list view, you can use the arrow keys to scroll through the available
suggestions. List
view also shows the source of the prediction.
PSReadLine defaults to InlineView . You can switch between InlineView and ListView
by
pressing the F2 key. You can also use the PredictionViewStyle parameter of
Set-
PSReadLineOption to change the view.
PowerShell
PowerShell
PowerShell
You can change the prediction source using the Set-PSReadLineOption cmdlet with the
PredictionSource parameter. The PredictionSource can be set to:
None
History
Plugin
HistoryAndPlugin
7 Note
about_PSReadLine.
PowerShell
Or you can create your own. The default light-grey prediction text color can be restored
using the
following ANSI escape sequence.
PowerShell
For more information about setting prediction color and other PSReadLine settings, see
Set-PSReadLineOption.
Changing keybindings
PSReadLine contains functions to navigate and accept predictions. For example:
default
AcceptNextSuggestionWord is built within the function ForwardWord , which can be
bound to
Ctrl + f
PowerShell
With this binding, pressing Ctrl + f accepts the next word of an inline
suggestion when
the cursor is at the end of current editing line. You can bind other keys to
AcceptSuggestion and AcceptNextSuggestionWord for similar functionalities. For example,
you may
want to make RightArrow accept the next word of the inline suggestion, instead
of the
whole suggestion line.
PowerShell
The CompletionPredictor module adds an IntelliSense experience for anything that can
be
tab-completed in PowerShell. With PSReadLine set to InlineView , you get the
normal tab
completion experience. When you switch to ListView , you get the
IntelliSense experience. You can
install the CompletionPredictor module from the
PowerShell Gallery.
As previously noted, ListView shows you the source of the prediction. If you have
multiple
plug-ins installed the predictions are grouped by source with History listed first
followed by
each plug-in in the order that they were loaded.
Dynamic Help provides just-in-time help that allows you to stay focused on your work
without losing
your place typing on the command line.
When the cursor is at the end of a fully expanded cmdlet name, pressing F1
displays the
help for that cmdlet.
When the cursor is at the end of a fully expanded parameter name, pressing F1
displays
the help for the cmdlet beginning at the parameter.
The pager in PSReadLine allows you to scroll the displayed help using the up and down
arrow
keys. Pressing Q exits the alternative screen buffer and returns to the current
cursor
position on the command line on the primary screen.
Choosing keybindings
Not all keybindings work for all operating systems and terminal applications. For
example,
keybindings for the Alt key don't work on macOS by default. On Linux,
Ctrl
To work around these quirks, map the PSReadLine function to an available key
combination. For
example:
PowerShell
Set-PSReadLineKeyHandler -chord 'Ctrl+l' -Function ShowParameterHelp
For more information about keybindings and workarounds, see Using PSReadLine key
handlers.
Using aliases
Article • 11/17/2022
PowerShell
Output
Use the Get-Alias cmdlet to list the aliases available in your environment. To list the
aliases for a single cmdlet, use the Definition parameter and specify the executable
name.
PowerShell
Output
CommandType Name
----------- ----
PowerShell
Output
CommandType Name
----------- ----
md mkdir New-Item ni
The aliases in this table are Windows-specific. Some aliases aren't available on
other platforms.
This is to allow the native command to work in a PowerShell
session. For example, ls isn't
defined as a PowerShell alias on macOS or Linux so
that the native command is run instead of
Get-ChildItem .
In addition to parameter aliases, PowerShell lets you specify the parameter name using
the fewest
characters needed to uniquely identify the parameter. For example, the Get-
ChildItem cmdlet has
the Recurse and ReadOnly parameters. To uniquely identify the
Recurse parameter you only
need to provide -rec . If you combine that with the
command alias, Get-ChildItem -Recurse can be
shortened to dir -rec .
A PowerShell profile is a script that runs when PowerShell starts. You can use the profile
to
customize the environment. You can:
Putting these settings in your profile ensures that they're available whenever you start
PowerShell
on your system.
7 Note
There are four possible profiles available to support different user scopes and different
PowerShell
hosts. The fully qualified paths for each profile script are stored in the
following member
properties of $PROFILE .
AllUsersAllHosts
AllUsersCurrentHost
CurrentUserAllHosts
CurrentUserCurrentHost
You can create profile scripts that run for all users or just one user, the CurrentUser.
CurrentUser profiles are stored in the user's home directory.
There are also profiles that run for all PowerShell hosts or specific hosts. The profile
script
for each PowerShell host has a name unique for that host. For example, the
filename for the standard
Console Host on Windows or the default terminal application
on other platforms is
Microsoft.PowerShell_profile.ps1 . For Visual Studio Code (VS
Code), the filename is
Microsoft.VSCode_profile.ps1 .
By default, referencing the $PROFILE variable returns the path to the "Current User,
Current Host"
profile. The other profiles path can be accessed through the properties of
the $PROFILE variable.
For example:
PowerShell
PS> $PROFILE
C:\Users\user1\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
PS> $PROFILE.AllUsersAllHosts
C:\Program Files\PowerShell\7\profile.ps1
PowerShell
The Force parameter of New-Item cmdlet creates the necessary folders when they don't
exist.
Once you have created the script file, you can use your favorite editor to
customize your shell
environment.
The simplest way to edit your profile script is to open the file in your favorite code
editor. For
example, the following command opens the profile in VS Code .
PowerShell
code $PROFILE
You could also use notepad.exe on Windows, vi on Linux, or any other text editor.
The following profile script has examples for many of the customizations mentioned in
the
previous articles. You can use any of these settings in your own profile.
PowerShell
if (!(Test-Path HKCR:)) {
function prompt {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal] $identity
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator
else { '' })
$esc = [char]0x1b
$PSStyle = [pscustomobject]@{
Foreground = @{
Magenta = "${esc}[35m"
BrightYellow = "${esc}[93m"
Background = @{
BrightBlack = "${esc}[100m"
$PSROptions = @{
Colors = @{
Operator = $PSStyle.Foreground.Magenta
Parameter = $PSStyle.Foreground.Magenta
Selection = $PSStyle.Background.BrightBlack
InLinePrediction = $PSStyle.Foreground.BrightYellow +
$PSStyle.Background.BrightBlack
Set-PSReadLineOption @PSROptions
$scriptblock = {
ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_,
'ParameterValue', $_)
Adds two new PSDrives for the other root registry hives.
Creates a customized prompt that changes if you are running in an elevated
session.
Configures PSReadLine and adds keybinding. The color settings use the $PSStyle
feature to
define the ANSI color settings.
Adds tab completion for the dotnet CLI tool. The tool provides parameters to help
resolve the
command-line arguments. The script block for Register-
ArgumentCompleter uses that
feature to provide the tab completion.
Using PSReadLine key handlers
Article • 03/27/2023
The PSReadLine module provides key handlers that map PSReadLine functions to
keyboard
chords. Keyboard chords are a sequence of one or more keystrokes that are
pressed at the same time.
For example, the chord Ctrl + Spacebar is the combination of
the Ctrl
and Spacebar keys pressed at the same time. A PSReadLine function is a
predefined
action that can be performed on a command line. For example, the
MenuComplete function allows you
to choose from a list of options from a menu
complete the input on the command line.
PSReadLine has several predefined key handlers that are bound by default. You can also
define
your own custom key handlers. Run the following command to list the key
handlers that are currently
defined.
PowerShell
Get-PSReadLineKeyHandler
You can also get a list of all unbound PSReadLine functions that are available to be
bound to a key chord.
PowerShell
Get-PSReadLineKeyHandler -Unbound
You can use the Set-PSReadLineKeyHandler cmdlet to bind a function to a key handler.
The following
command binds the MenuComplete function to the chord Ctrl + Spacebar .
PowerShell
[System.Console]::ReadKey()
The following output shows the information returned by the ReadKey() method for the
Output
D2 Control
For the PSReadLine key handler cmdlets, this chord is represented as Ctrl+D2 . The
following
example binds this chord to a function.
PowerShell
You can bind multiple cords to a single function. By default, the BackwardDeleteChar
function is
bound to two chords.
PowerShell
Output
7 Note
The Chord parameter is case-sensitive. Meaning, you can create different bindings
for
Ctrl + X and Ctrl + x .
On Windows, you can also use the Alt + ? key chord to show the function bound to
the next key chord you enter. When you type Alt + ? you see the following
prompt:
Output
what-is-key:
When you hit the Backspace key you get the following response:
Output
macOS
The Macintosh keyboard doesn't have an Alt key like Windows and Linux systems.
Instead,
it has the ⌥ Option key. macOS uses this key differently than the Alt
key on
other systems. However, you can configure the terminal and iTerm2 applications on
macOS to
treat it as an Alt key.
Open the Settings window from the App bar in Terminal.app. Select Profiles and choose
the
profile you want to configure. Select the Keyboard tab of the configuration options.
Below the
list of keys, select the Use Option as Meta Key setting. This setting allows the
⌥
Option key to act as Alt in the Terminal application.
Configuring the iTerm2 application
Open the Settings window from the App Bar in iTerm.app. Select Profiles and choose
the
profile you want to configure. Select the Keys tab of the configuration options.
Select the
Esc+ option for both the Left Option Key and Right Option Key settings. This
setting
allows the ⌥ Option key to act as Alt in the iTerm application.
7 Note
The exact steps may vary depending on the versions of macOS and the terminal
applications. These
examples were captured on macOS Ventura 13.2.1 and iTerm2
v3.4.16.
Linux
On Linux platforms, the key code generated can be different than other systems. For
example:
PowerShell
Use the ReadKey() method to verify the key codes generated by your keyboard.
MenuComplete
Complete the input by selecting from a menu of possible completion values.
The following example shows the menu of possible completions for commands
beginning with select .
Output
PS C:\> select<Ctrl+Spacebar>
Select-Object
Use the arrow keys to select the completion you want. Press the Enter key to complete
the
input. As you move through the selections, help for the selected command is
displayed below the
menu.
ClearScreen
This function clears the screen similar to the cls or clear commands.
SelectCommandArgument
Selects the next argument on the command line.
You may have command in your history that you want to run again with different
parameter values. You
can use the chord to cycle through each parameter and change
the value as needed.
GotoBrace
Moves the cursor to the matching brace.
This functions moves your cursor to the closing brace that matches the brace at the
current cursor
position on the command line. The function works for brackets ( [] ),
braces ( {} ), and
parentheses, ( () ).
DigitArgument
Start or accumulate a numeric argument use to repeat a keystroke the specified number
of times.
See also
Get-PSReadLineKeyHandler
Set-PSReadLineKeyHandler
Configuring a light colored theme
Article • 03/07/2023
The default colors for both PowerShell and PSReadLine are selected for a dark
background
terminal. However, some users may choose to use a light background with
dark text. Since most of the
default colors don't set the background, using light
foreground colors on a light background
produces unreadable text.
PSReadLine allows you to define colors for 18 different syntax elements. You can view
the
current settings using the Get-PSReadLineOption cmdlet.
Output
EditMode : Windows
AddToHistoryHandler :
System.Func`2[System.String,System.Object]
HistoryNoDuplicates : True
HistorySavePath :
C:\Users\user1\AppData\Roaming\Microsoft\Wind...
HistorySaveStyle : SaveIncrementally
HistorySearchCaseSensitive : False
HistorySearchCursorMovesToEnd : False
MaximumHistoryCount : 4096
ContinuationPrompt : >>
ExtraPromptLineCount : 0
PromptText : {> }
BellStyle : Audible
DingDuration : 50
DingTone : 1221
CommandValidationHandler :
CompletionQueryItems : 100
MaximumKillRingCount : 10
ShowToolTips : True
ViModeIndicator : None
WordDelimiters : ;:,.[]{}()/\|^&*-=+'"-—―
AnsiEscapeTimeout : 100
PredictionSource : HistoryAndPlugin
PredictionViewStyle : InlineView
CommandColor : "`e[93m"
CommentColor : "`e[32m"
ContinuationPromptColor : "`e[37m"
DefaultTokenColor : "`e[37m"
EmphasisColor : "`e[96m"
ErrorColor : "`e[91m"
InlinePredictionColor : "`e[38;5;238m"
KeywordColor : "`e[92m"
ListPredictionColor : "`e[33m"
ListPredictionSelectedColor : "`e[48;5;238m"
MemberColor : "`e[97m"
NumberColor : "`e[97m"
OperatorColor : "`e[90m"
ParameterColor : "`e[90m"
SelectionColor : "`e[30;47m"
StringColor : "`e[36m"
TypeColor : "`e[37m"
VariableColor : "`e[92m"
The color settings are stored as strings containing ANSI escape sequences that change
the color in
your terminal. Using the Set-PSReadLineOption cmdlet you can change the
colors to values that work
better for a light-colored background.
The following hashtable defines colors for PSReadLine that mimic the colors in the
PowerShell
ISE.
PowerShell
$ISETheme = @{
Command = $PSStyle.Foreground.FromRGB(0x0000FF)
Comment = $PSStyle.Foreground.FromRGB(0x006400)
ContinuationPrompt = $PSStyle.Foreground.FromRGB(0x0000FF)
Default = $PSStyle.Foreground.FromRGB(0x0000FF)
Emphasis = $PSStyle.Foreground.FromRGB(0x287BF0)
Error = $PSStyle.Foreground.FromRGB(0xE50000)
InlinePrediction = $PSStyle.Foreground.FromRGB(0x93A1A1)
Keyword = $PSStyle.Foreground.FromRGB(0x00008b)
ListPrediction = $PSStyle.Foreground.FromRGB(0x06DE00)
Member = $PSStyle.Foreground.FromRGB(0x000000)
Number = $PSStyle.Foreground.FromRGB(0x800080)
Operator = $PSStyle.Foreground.FromRGB(0x757575)
Parameter = $PSStyle.Foreground.FromRGB(0x000080)
String = $PSStyle.Foreground.FromRGB(0x8b0000)
Type = $PSStyle.Foreground.FromRGB(0x008080)
Variable = $PSStyle.Foreground.FromRGB(0xff4500)
ListPredictionSelected = $PSStyle.Background.FromRGB(0x93A1A1)
Selection = $PSStyle.Background.FromRGB(0x00BFFF)
7 Note
In PowerShell 7.2 and higher you can use the FromRGB() method of $PSStyle to
create the ANSI
escape sequences for the colors you want.
For more information about ANSI escape sequences, see the ANSI escape code
article in
Wikipedia.
Add the $ISETheme variable and the following Set-PSReadLineOption command to your
profile.
PowerShell
Beginning in PowerShell 7.2, PowerShell adds colorized output to the default console
experience. The
colors used are defined in the $PSStyle variable and are designed for a
dark background. The
following settings work better for a light background terminal.
PowerShell
$PSStyle.Formatting.FormatAccent = "`e[32m"
$PSStyle.Formatting.TableHeader = "`e[32m"
$PSStyle.Formatting.ErrorAccent = "`e[36m"
$PSStyle.Formatting.Error = "`e[31m"
$PSStyle.Formatting.Warning = "`e[33m"
$PSStyle.Formatting.Verbose = "`e[33m"
$PSStyle.Formatting.Debug = "`e[33m"
$PSStyle.Progress.Style = "`e[33m"
$PSStyle.FileInfo.Directory =
$PSStyle.Background.FromRgb(0x2f6aff) +
$PSStyle.Foreground.BrightWhite
$PSStyle.FileInfo.SymbolicLink = "`e[36m"
$PSStyle.FileInfo.Executable = "`e[95m"
$PSStyle.FileInfo.Extension['.ps1'] = "`e[36m"
$PSStyle.FileInfo.Extension['.ps1xml'] = "`e[36m"
$PSStyle.FileInfo.Extension['.psd1'] = "`e[36m"
$PSStyle.FileInfo.Extension['.psm1'] = "`e[36m"
The World Wide Web Consortium (W3C) has recommendations for using colors for
accessibility.
The Web Content Accessibility Guidelines (WCAG) 2.1 recommends that
"visual presentation of text and
images of text has a contrast ratio of at least 4.5:1." For
more information, see
Success Criterion 1.4.3 Contrast (Minimum) .
The Contrast Ratio website provides a tool that lets you pick foreground and
background
colors and measure the contrast. You can use this tool to find color
combinations that work best for
you.
Deep dive articles
Article • 11/17/2022
The articles in this section are designed to be an in-depth look into PowerShell topics.
These
articles don't replace the reference articles, but provide diverse examples,
illustrate edge
cases, and warn about pitfalls and common mistakes.
This collection is also a showcase for community contributions. The inaugural set of
articles come
from @KevinMarquette and were originally published at
PowerShellExplained.com .
7 Note
What is an array?
I'm going to start with a basic technical description of what arrays are and how they are
used by
most programming languages before I shift into the other ways PowerShell
makes use of them.
An array is a data structure that serves as a collection of multiple items. You can iterate
over the
array or access individual items using an index. The array is created as a
sequential chunk of
memory where each value is stored right next to the other.
Basic usage
Because arrays are such a basic feature of PowerShell, there is a simple syntax for
working with
them in PowerShell.
Create an array
An empty array can be created by using @()
PowerShell
PS> $data.count
We can create an array and seed it with values just by placing them in the @()
parentheses.
PowerShell
PS> $data.count
PS> $data
Zero
One
Two
Three
This array has 4 items. When we call the $data variable, we see the list of our items. If
it's an
array of strings, then we get one line per string.
We can declare an array on multiple lines. The comma is optional in this case and
generally left
out.
PowerShell
$data = @(
'Zero'
'One'
'Two'
'Three'
I prefer to declare my arrays on multiple lines like that. Not only does it get easier to
read when
you have multiple items, it also makes it easier to compare to previous
versions when using source
control.
Other syntax
It's commonly understood that @() is the syntax for creating an array, but comma-
separated lists
work most of the time.
PowerShell
$data = 'Zero','One','Two','Three'
PowerShell
This is handy because you don't have to put quotes around the strings when the
parameter accepts
strings. I would never do this in a script but it's fair game in the
console.
Accessing items
Now that you have an array with items in it, you may want to access and update those
items.
Offset
To access individual items, we use the brackets [] with an offset value starting at 0. This
is
how we get the first item in our array:
PowerShell
PS> $data[0]
Zero
The reason why we use zero here is because the first item is at the beginning of the list
so we use
an offset of 0 items to get to it. To get to the second item, we would need to
use an offset of 1 to
skip the first item.
PowerShell
PS> $data[1]
One
PowerShell
PS> $data[3]
Three
Index
Now you can see why I picked the values that I did for this example. I introduced this as
an offset
because that is what it really is, but this offset is more commonly referred to as
an index. An
index that starts at 0 . For the rest of this article I will call the offset an
index.
PowerShell
PS> $data[0,2,3]
Zero
Two
Three
The items are returned based on the order of the indexes provided. If you duplicate an
index,
you get that item both times.
PowerShell
PS> $data[3,0,3]
Three
Zero
Three
PowerShell
PS> $data[1..3]
One
Two
Three
PS> $data[3..1]
Three
Two
One
You can use negative index values to offset from the end. So if you need the last item in
the list,
you can use -1 .
PowerShell
PS> $data[-1]
Three
One word of caution here with the .. operator. The sequence 0..-1 and -1..0
evaluate to the
values 0,-1 and -1,0 . It's easy to see $data[0..-1] and think it would
enumerate all items if
you forget this detail. $data[0..-1] gives you the same value as
$data[0,-1] by giving you the
first and last item in the array (and none of the other
values). Here is a larger example:
PowerShell
PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
PowerShell
PS> $a[2,1,0,-1]
Out of bounds
In most languages, if you try to access an index of an item that is past the end of the
array, you
would get some type of error or an exception. PowerShell silently returns
nothing.
PowerShell
True
PowerShell
PS> $empty[0]
So make sure your arrays are not $null before you try to access elements inside them.
Count
Arrays and other collections have a count property that tells you how many items are in
the array.
PowerShell
PS> $data.count
PowerShell 3.0 added a count property to most objects. you can have a single object
and it should
give you a count of 1 .
PowerShell
PS> $date.count
PowerShell
PS> $null.count
There are some traps here that I will revisit when I cover checking for $null or empty
arrays
later on in this article.
Off-by-one errors
A common programming error is created because arrays start at index 0. Off-by-one
errors can be
introduced in two ways.
The first is by mentally thinking you want the second item and using an index of 2 and
really getting
the third item. Or by thinking that you have four items and you want last
item, so you use the count
to access the last item.
PowerShell
$data[ $data.count ]
PowerShell is perfectly happy to let you do that and give you exactly what item exists at
index 4:
$null . You should be using $data.count - 1 or the -1 that we learned about
above.
PowerShell
Three
This is where you can use the -1 index to get the last element.
PowerShell
PS> $data[ -1 ]
Three
Lee Dailey also pointed out to me that we can use $data.GetUpperBound(0) to get the
max index
number.
PowerShell
PS> $data.GetUpperBound(0)
Three
The second most common way is when iterating the list and not stopping at the right
time. I'll
revisit this when we talk about using the for loop.
Updating items
We can use the same index to update existing items in the array. This gives us direct
access to
update individual items.
PowerShell
$data[2] = 'dos'
$data[3] = 'tres'
If we try to update an item that is past the last element, then we get an
Index was
outside the bounds of the array. error.
PowerShell
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ FullyQualifiedErrorId : System.IndexOutOfRangeException
I'll revisit this later when I talk about how to make an array larger.
Iteration
At some point, you might need to walk or iterate the entire list and perform some action
for each
item in the array.
Pipeline
Arrays and the PowerShell pipeline are meant for each other. This is one of the simplest
ways to
process over those values. When you pass an array to a pipeline, each item
inside the array is
processed individually.
PowerShell
PS> $data = 'Zero','One','Two','Three'
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]
If you have not seen $PSItem before, just know that it's the same thing as $_ . You can
use either
one because they both represent the current object in the pipeline.
ForEach loop
The ForEach loop works well with collections. Using the syntax:
foreach ( <variable> in
<collection> )
PowerShell
"Item: [$node]"
ForEach method
I tend to forget about this one but it works well for simple operations. PowerShell allows
you to
call .ForEach() on a collection.
PowerShell
Item [Zero]
Item [One]
Item [Two]
Item [Three]
The .foreach() takes a parameter that is a script block. You can drop the parentheses
and just
provide the script block.
PowerShell
$data.foreach{"Item [$PSItem]"}
This is a lesser known syntax but it works just the same. This foreach method was added
in
PowerShell 4.0.
For loop
The for loop is used heavily in most other languages but you don't see it much in
PowerShell. When
you do see it, it's often in the context of walking an array.
PowerShell
The first thing we do is initialize an $index to 0 . Then we add the condition that $index
must
be less than $data.count . Finally, we specify that every time we loop that we must
increase the
index by 1 . In this case $index++ is short for $index = $index + 1 . The
format operator
( -f ) is used to insert the value of $data[$index] in the output string.
Whenever you're using a for loop, pay special attention to the condition. I used
$index
-lt $data.count here. It's easy to get the condition slightly wrong to get an off-by-one
error in your logic. Using $index -le $data.count or $index -lt ($data.count - 1) are
ever so
slightly wrong. That would cause your result to process too many or too few
items. This is the
classic off-by-one error.
Switch loop
This is one that is easy to overlook. If you provide an array to a switch statement, it
checks
each item in the array.
PowerShell
$data = 'Zero','One','Two','Three'
switch( $data )
'One'
'Tock'
'Three'
'Tock'
Default
'Tick'
Output
Tick
Tock
Tick
Tock
There are a lot of cool things that we can do with the switch statement. I have another
article
dedicated to this.
Updating values
When your array is a collection of string or integers (value types), sometimes you may
want to
update the values in the array as you loop over them. Most of the loops above
use a variable in the
loop that holds a copy of the value. If you update that variable, the
original value in the array is
not updated.
The exception to that statement is the for loop. If you want to walk an array and
update values
inside it, then the for loop is what you're looking for.
PowerShell
This example takes a value by index, makes a few changes, and then uses that same
index to assign
it back.
Arrays of Objects
So far, the only thing we've placed in an array is a value type, but arrays can also contain
objects.
PowerShell
$data = @(
[pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
[pscustomobject]@{FirstName='John'; LastName='Doe'}
Many cmdlets return collections of objects as arrays when you assign them to a variable.
PowerShell
$processList = Get-Process
All of the basic features we already talked about still apply to arrays of objects with a
few
details worth pointing out.
Accessing properties
We can use an index to access an individual item in a collection just like with value
types.
PowerShell
PS> $data[0]
FirstName LastName
----- ----
Kevin Marquette
PowerShell
PS> $data[0].FirstName
Kevin
PS> $data[0]
FirstName LastName
----- ----
Jay Marquette
Array properties
Normally you would have to enumerate the whole list like this to access all the
properties:
PowerShell
Marquette
Doe
PowerShell
Marquette
Doe
But PowerShell offers us the ability to request LastName directly. PowerShell enumerates
them
all for us and returns a clean list.
PowerShell
PS> $data.LastName
Marquette
Doe
The enumeration still happens but we don't see the complexity behind it.
Where-Object filtering
This is where Where-Object comes in so we can filter and select what we want out of the
array
based on the properties of the object.
PowerShell
FirstName LastName
----- ----
Kevin Marquette
We can write that same query to get the FirstName we are looking for.
PowerShell
Where()
Arrays have a Where() method on them that allows you to specify a scriptblock for the
filter.
PowerShell
PowerShell
foreach($person in $data)
$person.FirstName = 'Kevin'
This loop is walking every object in the $data array. Because objects are reference types,
the
$person variable references the exact same object that is in the array. So updates to
its
properties do update the original.
You still can't replace the whole object this way. If you try to assign a new object to the
$person variable, you're updating the variable reference to something else that no
longer points
to the original object in the array. This doesn't work like you would expect:
PowerShell
foreach($person in $data)
$person = [pscustomobject]@{
FirstName='Kevin'
LastName='Marquette'
Operators
The operators in PowerShell also work on arrays. Some of them work slightly differently.
-join
The -join operator is the most obvious one so let's look at it first. I like the -join
operator and use it often. It joins all elements in the array with the character or string
that
you specify.
PowerShell
1-2-3-4
1,2,3,4
One of the features that I like about the -join operator is that it handles single items.
PowerShell
PowerShell
Data is 1,2,3,4.
-join $array
Here is a clever trick that Lee Dailey pointed out to me. If you ever want to join
everything
without a delimiter, instead of doing this:
PowerShell
PS> $data = @(1,2,3,4)
1234
You can use -join with the array as the parameter with no prefix. Take a look at this
example to
see that I'm talking about.
PowerShell
1234
PowerShell
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03
-contains
The -contains operator allows you to check an array of values to see if it contains a
specified
value.
PowerShell
True
-in
When you have a single value that you would like to verify matches one of several
values, you can
use the -in operator. The value would be on the left and the array on
the right-hand side of the
operator.
PowerShell
True
This can get expensive if the list is large. I often use a regex pattern if I'm checking more
than
a few values.
PowerShell
PS> $pattern
^(red|green|blue)$
True
PowerShell
green
When you use the -ne operator, we get all the values that are not equal to our value.
PowerShell
red
blue
When you use this in an if() statement, a value that is returned is a True value. If no
value is
returned, then it's a False value. Both of these next statements evaluate to
True .
PowerShell
$data = @('red','green','blue')
I'll revisit this in a moment when we talk about testing for $null .
-match
The -match operator tries to match each item in the collection.
PowerShell
PS> $servers = @(
'LAX-SQL-01'
'LAX-API-01'
'ATX-SQL-01'
'ATX-API-01'
LAX-SQL-01
ATX-SQL-01
When you use -match with a single value, a special variable $Matches gets populated
with match
info. This isn't the case when an array is processed this way.
PowerShell
I take a closer look at Select-String , -match and the $matches variable in another post
called
The many ways to use regex .
$null or empty
Testing for $null or empty arrays can be tricky. Here are the common traps with arrays.
'Array is $null'
But I just went over how -eq checks each item in the array. So we can have an array of
several
items with a single $null value and it would evaluate to $true
PowerShell
$array = @('one',$null,'three')
This is why it's a best practice to place the $null on the left side of the operator. This
makes
this scenario a non-issue.
PowerShell
A $null array isn't the same thing as an empty array. If you know you have an array,
check the
count of objects in it. If the array is $null , the count is 0 .
PowerShell
if ( $array.count -gt 0 )
There is one more trap to watch out for here. You can use the count even if you have a
single
object, unless that object is a PSCustomObject . This is a bug that is fixed in
PowerShell 6.1.
That's good news, but a lot of people are still on 5.1 and need to watch
out for it.
PowerShell
PS> $object = [PSCustomObject]@{Name='TestObject'}
PS> $object.count
$null
If you're still on PowerShell 5.1, you can wrap the object in an array before checking the
count to
get an accurate count.
PowerShell
if ( @($array).count -gt 0 )
To fully play it safe, check for $null , then check the count.
PowerShell
All -eq
I recently saw someone ask how to verify that every value in an array matches a given
value .
Reddit user /u/bis had this clever solution that checks for any incorrect values
and then
flips the result.
PowerShell
$results = Test-Something
Adding to arrays
At this point, you're starting to wonder how to add items to an array. The quick answer
is that you
can't. An array is a fixed size in memory. If you need to grow it or add a
single item to it, then
you need to create a new array and copy all the values over from
the old array. This sounds like a
lot of work, however, PowerShell hides the complexity of
creating the new array. PowerShell
implements the addition operator ( + ) for arrays.
7 Note
Array addition
We can use the addition operator with arrays to create a new array. So given these two
arrays:
PowerShell
$first = @(
'Zero'
'One'
$second = @(
'Two'
'Three'
PowerShell
Zero
One
Two
Three
Plus equals +=
We can create a new array in place and add an item to it like this:
PowerShell
$data = @(
'Zero'
'One'
'Two'
'Three'
$data += 'four'
Just remember that every time you use += that you're duplicating and creating a new
array. This
is a not an issue for small datasets but it scales extremely poorly.
Pipeline assignment
You can assign the results of any pipeline into a variable. It's an array if it contains
multiple
items.
PowerShell
"ATX-SQL-$PSItem"
Normally when we think of using the pipeline, we think of the typical PowerShell one-
liners. We can
leverage the pipeline with foreach() statements and other loops. So
instead of adding items to an
array in a loop, we can drop items onto the pipeline.
PowerShell
"ATX-SQL-$node"
Array Types
By default, an array in PowerShell is created as a [PSObject[]] type. This allows it to
contain
any type of object or value. This works because everything is inherited from the
PSObject type.
PowerShell
PS> [int[]] $numbers = 1,2,3
ERROR: Cannot convert value "one" to type "System.Int32". Input string was
not in a correct format."
ArrayList
Adding items to an array is one of its biggest limitations, but there are a few other
collections
that we can turn to that solve this problem.
The ArrayList is commonly one of the first things that we think of when we need an
array that is
faster to work with. It acts like an object array every place that we need it,
but it handles adding
items quickly.
PowerShell
$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')
We are calling into .NET to get this type. In this case, we are using the default
constructor to
create it. Then we call the Add method to add an item to it.
The reason I'm using [void] at the beginning of the line is to suppress the return code.
Some .NET
calls do this and can create unexpected output.
If the only data that you have in your array is strings, then also take a look at using
StringBuilder . It's almost the same thing but has some methods that are just for
dealing with
strings. The StringBuilder is specially designed for performance.
It's common to see people move to ArrayList from arrays. But it comes from a time
where C# didn't
have generic support. The ArrayList is deprecated in support for the
generic List[]
Generic List
A generic type is a special type in C# that defines a generalized class and the user
specifies the
data types it uses when created. So if you want a list of numbers or strings,
you would define that
you want list of int or string types.
Here is how you create a List for strings.
PowerShell
$mylist = [System.Collections.Generic.List[string]]::new()
PowerShell
$mylist = [System.Collections.Generic.List[int]]::new()
We can cast an existing array to a list like this without creating the object first:
PowerShell
$mylist = [System.Collections.Generic.List[int]]@(1,2,3)
We can shorten the syntax with the using namespace statement in PowerShell 5 and
newer. The
using statement needs to be the first line of your script. By declaring a
namespace, PowerShell
lets you leave it off of the data types when you reference them.
PowerShell
$myList = [List[int]]@(1,2,3)
You have a similar Add method available to you. Unlike the ArrayList, there is no return
value on
the Add method so we don't have to void it.
PowerShell
$myList.Add(10)
PowerShell
PS> $myList[-1]
10
List[PSObject]
You can have a list of any type, but when you don't know the type of objects, you can
use
[List[PSObject]] to contain them.
PowerShell
$list = [List[PSObject]]::new()
Remove()
The ArrayList and the generic List[] both support removing items from the
collection.
PowerShell
$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three
When working with value types, it removes the first one from the list. You can call it over
and over
again to keep removing that value. If you have reference types, you have to
provide the object that
you want removed.
PowerShell
[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])
PowerShell
$delete = $drives[2]
$drives.remove($delete)
The remove method returns true if it was able to find and remove the item from the
collection.
More collections
There are many other collections that can be used but these are the good generic array
replacements.
If you're interested in learning about more of these options, take a look at
this Gist that
Mark Kraus put together.
Other nuances
Now that I have covered all the major functionality, here are a few more things that I
wanted to
mention before I wrap this up.
Pre-sized arrays
I mentioned that you can't change the size of an array once it's created. We can create
an array of
a pre-determined size by calling it with the new($size) constructor.
PowerShell
$data = [Object[]]::new(4)
$data.count
Multiplying arrays
An interesting little trick is that you can multiply an array by an integer.
PowerShell
PS> $data * 3
red
green
blue
red
green
blue
red
green
blue
Initialize with 0
A common scenario is that you want to create an array with all zeros. If you're only
going to have
integers, a strongly typed array of integers defaults to all zeros.
PowerShell
PS> [int[]]::new(4)
PowerShell
PS> $data
The nice thing about the multiplying trick is that you can use any value. So if you would
rather
have 255 as your default value, this would be a good way to do it.
PowerShell
PS> $data
255
255
255
255
Nested arrays
An array inside an array is called a nested array. I don't use these much in PowerShell
but I have
used them more in other languages. Consider using an array of arrays when
your data fits in a grid
like pattern.
PowerShell
$data = @(@(1,2,3),@(4,5,6),@(7,8,9))
$data2 = @(
@(1,2,3),
@(4,5,6),
@(7,8,9)
The comma is very important in those examples. I gave an earlier example of a normal
array on
multiple lines where the comma was optional. That isn't the case with a multi-
dimensional array.
The way we use the index notation changes slightly now that we've a nested array. Using
the
$data above, this is how we would access the value 3.
PowerShell
PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
Add a set of bracket for each level of array nesting. The first set of brackets is for the
outer
most array and then you work your way in from there.
Write-Output -NoEnumerate
PowerShell likes to unwrap or enumerate arrays. This is a core aspect of the way
PowerShell uses the
pipeline but there are times that you don't want that to happen.
I commonly pipe objects to Get-Member to learn more about them. When I pipe an array
to it, it
gets unwrapped and Get-Member sees the members of the array and not the
actual array.
PowerShell
TypeName: System.String
...
To prevent that unwrap of the array, you can use Write-Output -NoEnumerate .
PowerShell
TypeName: System.Object[]
...
I have a second way that's more of a hack (and I try to avoid hacks like this). You can
place a
comma in front of the array before you pipe it. This wraps $data into another
array where it is
the only element, so after the unwrapping the outer array we get back
$data unwrapped.
PowerShell
TypeName: System.Object[]
...
Return an array
This unwrapping of arrays also happens when you output or return values from a
function. You can
still get an array if you assign the output to a variable so this isn't
commonly an issue.
The catch is that you have a new array. If that is ever a problem, you can use
Write-
Output -NoEnumerate $array or return ,$array to work around it.
Anything else?
I know this is all a lot to take in. My hope is that you learn something from this article
every
time you read it and that it turns out to be a good reference for you for a long
time to come. If
you found this to be helpful, please share it with others you think may
get value out of it.
From here, I would recommend you check out a similar post that I wrote about
hashtables.
Everything you wanted to know about
hashtables
Article • 11/17/2022
I want to take a step back and talk about hashtables. I use them all the time now. I was
teaching someone about them after our user group meeting last night and I realized I
had the same
confusion about them as he had. Hashtables are really important in
PowerShell so it's good to have a
solid understanding of them.
7 Note
What is an array?
Before I jump into what a Hashtable is, I need to mention arrays first. For the purpose of
this discussion, an array is a list or collection of values or objects.
PowerShell
$array = @(1,2,3,5,7,11)
Once you have your items into an array, you can either use foreach to iterate over the
list or use
an index to access individual elements in the array.
PowerShell
foreach($item in $array)
Write-Output $item
Write-Output $array[3]
You can also update values using an index in the same way.
PowerShell
$array[2] = 13
I just scratched the surface on arrays but that should put them into the right context as I
move
onto hashtables.
What is a hashtable?
I'm going to start with a basic technical description of what hashtables are, in the
general sense,
before I shift into the other ways PowerShell uses them.
A hashtable is a data structure, much like an array, except you store each value (object)
using a
key. It's a basic key/value store. First, we create an empty hashtable.
PowerShell
$ageList = @{}
Notice that braces, instead of parentheses, are used to define a hashtable. Then we add
an item
using a key like this:
PowerShell
$key = 'Kevin'
$value = 36
$ageList.add( 'Alex', 9 )
The person's name is the key and their age is the value that I want to save.
$ageList['Kevin']
$ageList['Alex']
When I want Kevin's age, I use his name to access it. We can use this approach to add or
update
values into the hashtable too. This is just like using the add() function above.
PowerShell
$ageList = @{}
$key = 'Kevin'
$value = 36
$ageList[$key] = $value
$ageList['Alex'] = 9
There's another syntax you can use for accessing and updating values that I'll cover in a
later
section. If you're coming to PowerShell from another language, these examples
should fit in with
how you may have used hashtables before.
PowerShell
$ageList = @{
Kevin = 36
Alex = 9
As a lookup table
The real value of this type of a hashtable is that you can use them as a lookup table.
Here is a
simple example.
PowerShell
$environments = @{
Prod = 'SrvProd05'
QA = 'SrvQA02'
Dev = 'SrvDev12'
$server = $environments[$env]
In this example, you specify an environment for the $env variable and it will pick the
correct
server. You could use a switch($env){...} for a selection like this but a
hashtable is a nice
option.
This gets even better when you dynamically build the lookup table to use it later. So
think about
using this approach when you need to cross reference something. I think we
would see this even more
if PowerShell wasn't so good at filtering on the pipe with
Where-Object . If you're ever in a
situation where performance matters, this approach
needs to be considered.
I won't say that it's faster, but it does fit into the rule of If performance matters, test it .
Multiselection
Generally, you think of a hashtable as a key/value pair, where you provide one key and
get one
value. PowerShell allows you to provide an array of keys to get multiple values.
PowerShell
$environments[@('QA','DEV')]
$environments[('QA','DEV')]
$environments['QA','DEV']
In this example, I use the same lookup hashtable from above and provide three different
array styles
to get the matches. This is a hidden gem in PowerShell that most people
aren't aware of.
Iterating hashtables
Because a hashtable is a collection of key/value pairs, you iterate over it differently than
you do
for an array or a normal list of items.
The first thing to notice is that if you pipe your hashtable, the pipe treats it like one
object.
PowerShell
count : 1
Even though the .count property tells you how many values it contains.
PowerShell
PS> $ageList.count
You get around this issue by using the .values property if all you need is just the values.
PowerShell
Count : 2
Average : 22.5
It's often more useful to enumerate the keys and use them to access the values.
PowerShell
Write-Output $message
PowerShell
foreach($key in $ageList.keys)
Write-Output $message
We are walking each key in the hashtable and then using it to access the value. This is a
common
pattern when working with hashtables as a collection.
GetEnumerator()
That brings us to GetEnumerator() for iterating over our hashtable.
PowerShell
$ageList.GetEnumerator() | ForEach-Object{
Write-Output $message
The enumerator gives you each key/value pair one after another. It was designed
specifically for
this use case. Thank you to Mark Kraus for reminding me
of this one.
BadEnumeration
One important detail is that you can't modify a hashtable while it's being enumerated. If
we start
with our basic $environments example:
PowerShell
$environments = @{
Prod = 'SrvProd05'
QA = 'SrvQA02'
Dev = 'SrvDev12'
And trying to set every key to the same server value fails.
PowerShell
$environments.Keys | ForEach-Object {
$environments[$_] = 'SrvDev03'
+ CategoryInfo : InvalidOperation:
tableEnumerator:HashtableEnumerator) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
This will also fail even though it looks like it should also be fine:
PowerShell
foreach($key in $environments.keys) {
$environments[$key] = 'SrvDev03'
+ FullyQualifiedErrorId : System.InvalidOperationException
The trick to this situation is to clone the keys before doing the enumeration.
PowerShell
$environments.Keys.Clone() | ForEach-Object {
$environments[$_] = 'SrvDev03'
Property-based access
The use of property-based access changes the dynamics of hashtables and how you can
use them in
PowerShell. Here is our usual example from above treating the keys as
properties.
PowerShell
$ageList = @{}
$ageList.Kevin = 35
$ageList.Alex = 9
Just like the examples above, this example adds those keys if they don't exist in the
hashtable
already. Depending on how you defined your keys and what your values are,
this is either a
little strange or a perfect fit. The age list example has worked great up
until this point. We need
a new example for this to feel right going forward.
PowerShell
$person = @{
name = 'Kevin'
age = 36
And we can add and access attributes on the $person like this.
PowerShell
$person.city = 'Austin'
$person.state = 'TX'
All of a sudden this hashtable starts to feel and act like an object. It's still a collection of
things, so all the examples above still apply. We just approach it from a different point
of view.
PowerShell
It's simple but has been the source of many bugs for me because I was overlooking one
important
detail in my logic. I started to use it to test if a key was present. When the
value was $false or
zero, that statement would return $false unexpectedly.
PowerShell
This works around that issue for zero values but not $null vs non-existent keys. Most of
the time
you don't need to make that distinction but there are functions for when you
do.
PowerShell
We also have a ContainsValue() for the situation where you need to test for a value
without
knowing the key or iterating the whole collection.
PowerShell
$person.remove('age')
Assigning them a $null value just leaves you with a key that has a $null value.
PowerShell
$person = @{}
While that does work, try to use the clear() function instead.
PowerShell
$person.clear()
This is one of those instances where using the function creates self-documenting code
and it makes
the intentions of the code very clean.
Ordered hashtables
By default, hashtables aren't ordered (or sorted). In the traditional context, the order
doesn't
matter when you always use a key to access values. You may find that you want
the properties to stay
in the order that you define them. Thankfully, there's a way to do
that with the ordered keyword.
PowerShell
$person = [ordered]@{
name = 'Kevin'
age = 36
Now when you enumerate the keys and values, they stay in that order.
Inline hashtables
When you're defining a hashtable on one line, you can separate the key/value pairs with
a
semicolon.
PowerShell
PowerShell
$property = @{
name = 'totalSpaceGB'
The name is what the cmdlet would label that column. The expression is a script block
that is
executed where $_ is the value of the object on the pipe. Here is that script in
action:
PowerShell
Name totalSpaceGB
---- ------------
C 238.472652435303
I placed that in a variable but it could easily be defined inline and you can shorten name
to n
and expression to e while you're at it.
PowerShell
I personally don't like how long that makes commands and it often promotes some bad
behaviors that I
won't get into. I'm more likely to create a new hashtable or
pscustomobject with all the fields
and properties that I want instead of using this
approach in scripts. But there's a lot of code out
there that does this so I wanted you to
be aware of it. I talk about creating a pscustomobject
later on.
PowerShell
In this example I'm taking a list of users and using some custom cmdlet to get
additional
information just for the sort.
PowerShell
$data = @(
@{name='a'}
@{name='c'}
@{name='e'}
@{name='f'}
@{name='d'}
@{name='b'}
PowerShell
Add-DhcpServerv4Scope -Name 'TestNetwork' -StartRange'10.0.0.2' -EndRange
'10.0.0.254' -SubnetMask '255.255.255.0' -Description 'Network for testlab
A' -LeaseDuration (New-TimeSpan -Days 8) -Type "Both"
Without using splatting, all those things need to be defined on a single line. It either
scrolls
off the screen or will wrap where ever it feels like. Now compare that to a
command that uses
splatting.
PowerShell
$DHCPScope = @{
Name = 'TestNetwork'
StartRange = '10.0.0.2'
EndRange = '10.0.0.254'
SubnetMask = '255.255.255.0'
Description = 'Network for testlab A'
Type = "Both"
Add-DhcpServerv4Scope @DHCPScope
The use of the @ sign instead of the $ is what invokes the splat operation.
Just take a moment to appreciate how easy that example is to read. They are the exact
same command
with all the same values. The second one is easier to understand and
maintain going forward.
I use splatting anytime the command gets too long. I define too long as causing my
window to scroll
right. If I hit three properties for a function, odds are that I'll rewrite it
using a splatted
hashtable.
PowerShell
$CIMParams = @{
ClassName = 'Win32_Bios'
ComputerName = $ComputerName
if($Credential)
$CIMParams.Credential = $Credential
Get-CIMInstance @CIMParams
I start by creating my hashtable with common parameters. Then I add the $Credential if
it exists.
Because I'm using splatting here, I only need to have the call to Get-
CIMInstance in my code
once. This design pattern is very clean and can handle lots of
To be fair, you could write your commands to allow $null values for parameters. You
just don't
always have control over the other commands you're calling.
Multiple splats
You can splat multiple hashtables to the same cmdlet. If we revisit our original splatting
example:
PowerShell
$Common = @{
SubnetMask = '255.255.255.0'
LeaseDuration = (New-TimeSpan -Days 8)
Type = "Both"
$DHCPScope = @{
Name = 'TestNetwork'
StartRange = '10.0.0.2'
EndRange = '10.0.0.254'
I'll use this method when I have a common set of parameters that I'm passing to lots of
commands.
PowerShell
Splatting executables
Splatting also works on some executables that use a /param:value syntax. Robocopy.exe ,
for
example, has some parameters like this.
PowerShell
$robo = @{R=1;W=1;MT=8}
I don't know that this is all that useful, but I found it interesting.
Adding hashtables
Hashtables support the addition operator to combine two hashtables.
PowerShell
Nested hashtables
We can use hashtables as values inside a hashtable.
PowerShell
$person = @{
name = 'Kevin'
age = 36
$person.location = @{}
$person.location.city = 'Austin'
$person.location.state = 'TX'
I started with a basic hashtable containing two keys. I added a key called location with
an empty
hashtable. Then I added the last two items to that location hashtable. We can
do this all inline
too.
PowerShell
$person = @{
name = 'Kevin'
age = 36
location = @{
city = 'Austin'
state = 'TX'
This creates the same hashtable that we saw above and can access the properties the
same way.
PowerShell
$person.location.city
Austin
There are many ways to approach the structure of your objects. Here is a second way to
look at a
nested hashtable.
PowerShell
$people = @{
Kevin = @{
age = 36
city = 'Austin'
Alex = @{
age = 9
city = 'Austin'
This mixes the concept of using hashtables as a collection of objects and a collection of
properties. The values are still easy to access even when they're nested using whatever
approach
you prefer.
PowerShell
PS> $people.kevin.age
36
PS> $people.kevin['city']
Austin
PS> $people['Alex'].age
9
PS> $people['Alex']['City']
Austin
I tend to use the dot property when I'm treating it like a property. Those are generally
things I've
defined statically in my code and I know them off the top of my head. If I
need to walk the list or
programmatically access the keys, I use the brackets to provide
the key name.
PowerShell
foreach($name in $people.keys)
$person = $people[$name]
Having the ability to nest hashtables gives you a lot of flexibility and options.
PowerShell
PS> $people
Name Value
---- -----
My go to command for looking at these things is ConvertTo-JSON because it's very clean
and I
frequently use JSON on other things.
PowerShell
"Kevin": {
"age": 36,
"city": "Austin"
},
"Alex": {
"age": 9,
"city": "Austin"
Even if you don't know JSON, you should be able to see what you're looking for. There's
a
Format-Custom command for structured data like this but I still like the JSON view
better.
Creating objects
Sometimes you just need to have an object and using a hashtable to hold properties
just isn't
getting the job done. Most commonly you want to see the keys as column
names. A pscustomobject
makes that easy.
PowerShell
$person = [pscustomobject]@{
name = 'Kevin'
age = 36
$person
name age
---- ---
Kevin 36
Even if you don't create it as a pscustomobject initially, you can always cast it later when
needed.
PowerShell
$person = @{
name = 'Kevin'
age = 36
[pscustomobject]$person
name age
---- ---
Kevin 36
I already have detailed write-up for pscustomobject that you should go read after this
one. It
builds on a lot of the things learned here.
PowerShell
PowerShell
There are two important points about this method. First is that the JSON is written out
multiline so
I need to use the -Raw option to read it back into a single string. The
Second is that the
imported object is no longer a [hashtable] . It's now a
[pscustomobject] and that can cause
issues if you don't expect it.
Watch for deeply-nested hashtables. When you convert it to JSON you might not get
the results you
expect.
PowerShell
"a": {
"b": {
"c": "System.Collections.Hashtable"
Use Depth parameter to ensure that you have expanded all the nested hashtables.
PowerShell
"a": {
"b": {
"c": {
"d": "e"
If you need it to be a [hashtable] on import, then you need to use the Export-CliXml
and
Import-CliXml commands.
PowerShell
[Reflection.Assembly]::LoadWithPartialName("System.Web.Script.Serialization"
)
$JSSerializer =
[System.Web.Script.Serialization.JavaScriptSerializer]::new()
$JSSerializer.Deserialize($json,'Hashtable')
Beginning in PowerShell v6, JSON support uses the NewtonSoft JSON.NET and adds
hashtable support.
PowerShell
Name Value
---- -----
a b
PowerShell 6.2 added the Depth parameter to ConvertFrom-Json . The default Depth is
1024.
PowerShell
It imports the contents of the file into a scriptblock , then checks to make sure it
doesn't have
any other PowerShell commands in it before it executes it.
On that note, did you know that a module manifest (the psd1 file) is just a hashtable?
PowerShell
$person = @{
'#' = 3978
$person['full name']
You can do some odd things that you may not have realized you could do.
PowerShell
$person.'full name'
$person.$key
Just because you can do something, it doesn't mean that you should. That last one just
looks like a
bug waiting to happen and would be easily misunderstood by anyone
reading your code.
Technically your key doesn't have to be a string but they're easier to think about if you
only use
strings. However, indexing doesn't work well with the complex keys.
PowerShell
$ht
Name Value
---- -----
{1, 2, 3} a
Accessing a value in the hashtable by its key doesn't always work. For example:
PowerShell
$key = $ht.keys[0]
$ht.$($key)
$ht[$key]
When the key is an array, you must wrap the $key variable in a subexpression so that it
can be
used with member access ( . ) notation. Or, you can use array index ( [] )
notation.
$PSBoundParameters
$PSBoundParameters is an automatic variable that only exists inside the context of a
function.
It contains all the parameters that the function was called with. This isn't
exactly a hashtable but
close enough that you can treat it like one.
That includes removing keys and splatting it to other functions. If you find yourself
writing proxy
functions, take a closer look at this one.
PSBoundParameters gotcha
One important thing to remember is that this only includes the values that are passed in
as
parameters. If you also have parameters with default values but aren't passed in by
the caller,
$PSBoundParameters doesn't contain those values. This is commonly
overlooked.
$PSDefaultParameterValues
This automatic variable lets you assign default values to any cmdlet without changing
the cmdlet.
Take a look at this example.
PowerShell
$PSDefaultParameterValues["Out-File:Encoding"] = "UTF8"
This adds an entry to the $PSDefaultParameterValues hashtable that sets UTF8 as the
default
value for the Out-File -Encoding parameter. This is session-specific so you
should place it in
your $profile .
PowerShell
$PSDefaultParameterValues[ "Connect-VIServer:Server" ] =
'VCENTER01.contoso.local'
This also accepts wildcards so you can set values in bulk. Here are some ways you can
use that:
PowerShell
For a more in-depth breakdown, see this great article on Automatic Defaults by
Michael Sorens .
Regex $Matches
When you use the -match operator, an automatic variable called $matches is created
with the
results of the match. If you have any sub expressions in your regex, those sub
matches are also
listed.
PowerShell
$Matches[0]
$Matches[1]
Named matches
This is one of my favorite features that most people don't know about. If you use a
named regex
match, then you can access that match by name on the matches.
PowerShell
$Matches.Name
$Matches.SSN
In the example above, the (?<Name>.*) is a named sub expression. This value is then
placed in the
$Matches.Name property.
Group-Object -AsHashtable
One little known feature of Group-Object is that it can turn some datasets into a
hashtable for
you.
PowerShell
This will add each row into a hashtable and use the specified property as the key to
access it.
Copying Hashtables
One important thing to know is that hashtables are objects. And each variable is just a
reference to
an object. This means that it takes more work to make a valid copy of a
hashtable.
Copy: [copy]
Orig: [copy]
This highlights that they're the same because altering the values in one will also alter the
values
in the other. This also applies when passing hashtables into other functions. If
those functions
make changes to that hashtable, your original is also altered.
PowerShell
Copy: [copy]
Orig: [orig]
This will allow us to make some basic changes to one that don't impact the other.
PowerShell
PS> $orig = @{
person=@{
name='orig'
Copy: [copy]
Orig: [copy]
So you can see that even though I cloned the hashtable, the reference to person wasn't
cloned. We
need to make a deep copy to truly have a second hashtable that isn't linked
to the first.
Deep copies
There are a couple of ways to make a deep copy of a hashtable (and keep it as a
hashtable). Here's a
function using PowerShell to recursively create a deep copy:
PowerShell
function Get-DeepClone
[CmdletBinding()]
param(
$InputObject
process
$clone = @{}
foreach($key in $InputObject.keys)
{
return $clone
} else {
return $InputObject
It doesn't handle any other reference types or arrays, but it's a good starting point.
Another way is to use .Net to deserialize it using CliXml like in this function:
PowerShell
function Get-DeepClone
param(
$InputObject
$TempCliXmlString =
[System.Management.Automation.PSSerializer]::Serialize($obj,
[int32]::MaxValue)
return
[System.Management.Automation.PSSerializer]::Deserialize($TempCliXmlString)
For extremely large hashtables, the deserializing function is faster as it scales out.
However,
there are some things to consider when using this method. Since it uses
CliXml, it's memory
intensive and if you are cloning huge hashtables, that might be a
problem. Another limitation of the
CliXml is there is a depth limitation of 48. Meaning, if
you have a hashtable with 48 layers of
nested hashtables, the cloning will fail and no
hashtable will be output at all.
Anything else?
I covered a lot of ground quickly. My hope is that you walk away leaning something new
or
understanding it better every time you read this. Because I covered the full spectrum
of this
feature, there are aspects that just may not apply to you right now. That is
perfectly OK and is
kind of expected depending on how much you work with
PowerShell.
Everything you wanted to know about
PSCustomObject
Article • 06/07/2023
PSCustomObject is a great tool to add into your PowerShell tool belt. Let's start with the
basics
and work our way into the more advanced features. The idea behind using a
PSCustomObject is to
have a simple way to create structured data. Take a look at the first
7 Note
Creating a PSCustomObject
I love using [PSCustomObject] in PowerShell. Creating a usable object has never been
easier.
Because of that, I'm going to skip over all the other ways you can create an
object but I need
to mention that most of these examples are PowerShell v3.0 and
newer.
PowerShell
$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
This method works well for me because I use hashtables for just about everything. But
there are
times when I would like PowerShell to treat hashtables more like an object. The
first place you
notice the difference is when you want to use Format-Table or Export-
CSV and you realize that a
hashtable is just a collection of key/value pairs.
You can then access and use the values like you would a normal object.
PowerShell
$myObject.Name
Converting a hashtable
While I am on the topic, did you know you could do this:
PowerShell
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
$myObject = [pscustomobject]$myHashtable
I do prefer to create the object from the start but there are times you have to work with
a
hashtable first. This example works because the constructor takes a hashtable for the
object
properties. One important note is that while this method works, it isn't an exact
equivalent. The
biggest difference is that the order of the properties isn't preserved.
Legacy approach
You may have seen people use New-Object to create custom objects.
PowerShell
$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
This way is quite a bit slower but it may be your best option on early versions of
PowerShell.
Saving to a file
I find the best way to save a hashtable to a file is to save it as JSON. You can import it
back into
a [PSCustomObject]
PowerShell
$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path
Adding properties
You can still add new properties to your PSCustomObject with Add-Member .
PowerShell
$myObject.ID
Remove properties
You can also remove properties off of an object.
PowerShell
$myObject.psobject.properties.remove('ID')
The .psobject is an intrinsic member that gives you access to base object metadata. For
more
information about intrinsic members, see
about_Intrinsic_Members.
PowerShell
We can get this same list off of the psobject property too.
PowerShell
$myobject.psobject.properties.name
PowerShell
$myObject.Name
You can use a string for the property name and it will still work.
PowerShell
$myObject.'Name'
We can take this one more step and use a variable for the property name.
PowerShell
$property = 'Name'
$myObject.$property
PowerShell
$hashtable = @{}
$hashtable[$property] = $myObject.$property
PowerShell
But if the value could be $null you can check to see if it exists by checking the
psobject.properties for it.
PowerShell
if( $myobject.psobject.properties.match('ID').Count )
Here is a
scriptblock to turn an object into a hashtable. (same code form the last
example)
PowerShell
$ScriptBlock = {
$hashtable = @{}
$hashtable[$property] = $this.$property
return $hashtable
PowerShell
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
Add-Member @memberParam
PowerShell
$myObject.ToHashtable()
PowerShell
$first = 1
$second = $first
$second = 2
Object variables hold a reference to the actual object. When you assign one object to a
new
variable, they still reference the same object.
PowerShell
$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4
Because $third and $fourth reference the same instance of an object, both $third.key
and
$fourth.Key are 4.
psobject.copy()
If you need a true copy of an object, you can clone it.
PowerShell
$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4
Clone creates a shallow copy of the object. They have different instances now and
$third.key is 3
and $fourth.Key is 4 in this example.
I call this a shallow copy because if you have nested objects (objects with properties
contain other
objects), only the top-level values are copied. The child objects will
reference each other.
PowerShell
$myObject.PSObject.TypeNames.Insert(0,"My.Object")
PowerShell
$myObject = [PSCustomObject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
I love how nicely this just fits into the language. Now that we have an object with a
proper type
name, we can do some more things.
7 Note
You can also create custom PowerShell types using PowerShell classes. For more
information, see
PowerShell Class Overview.
$defaultDisplaySet = 'Name','Language'
$defaultDisplayPropertySet = New-Object
System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',
[string[]]$defaultDisplaySet)
$PSStandardMembers =
[System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
Now when my object just falls to the shell, it will only show those properties by default.
PowerShell
$TypeData = @{
TypeName = 'My.Object'
DefaultDisplayPropertySet = 'Name','Language'
Update-TypeData @TypeData
That is simple enough that I could almost remember it if I didn't have this post as a
quick
reference. Now I can easily create objects with lots of properties and still give it a
nice clean
view when looking at it from the shell. If I need to access or see those other
properties, they're
still there.
PowerShell
$myObject | Format-List *
PowerShell
$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.toUpper()}
Update-TypeData @TypeData
You can do this before your object is created or after and it will still work. This is what
makes
this different then using Add-Member with a script property. When you use Add-
Member the way I
referenced earlier, it only exists on that specific instance of the object.
Function parameters
You can now use these custom types for parameters in your functions and scripts. You
can have one
function create these custom objects and then pass them into other
functions.
PowerShell
param( [PSTypeName('My.Object')]$Data )
PowerShell requires that the object is the type you specified. It throws a validation error
if
the type doesn't match automatically to save you the step of testing for it in your
code. A great
example of letting PowerShell do what it does best.
Function OutputType
You can also define an OutputType for your advanced functions.
PowerShell
function Get-MyObject
[OutputType('My.Object')]
[CmdletBinding()]
param
...
The OutputType attribute value is only a documentation note. It isn't derived from the
function
code or compared to the actual function output.
The main reason you would use an output type is so that meta information about your
function
reflects your intentions. Things like Get-Command and Get-Help that your
development environment
can take advantage of. If you want more information, then
take a look at the help for it:
about_Functions_OutputTypeAttribute.
With that said, if you're using Pester to unit test your functions then it would be a good
idea
to validate the output objects match your OutputType. This could catch variables
that just fall
to the pipe when they shouldn't.
Closing thoughts
The context of this was all about [PSCustomObject] , but a lot of this information applies
to
objects in general.
I have seen most of these features in passing before but never saw them presented as a
collection of
information on PSCustomObject . Just this last week I stumbled upon
another one and was surprised
that I had not seen it before. I wanted to pull all these
ideas together so you can hopefully see
the bigger picture and be aware of them when
you have an opportunity to use them. I hope you learned
something and can find a way
to work this into your scripts.
Everything you wanted to know about
variable substitution in strings
Article • 11/16/2022
There are many ways to use variables in strings. I'm calling this variable substitution but
I'm
referring to any time you want to format a string to include values from variables.
This is
something that I often find myself explaining to new scripters.
7 Note
Concatenation
The first class of methods can be referred to as concatenation. It's basically taking
several
strings and joining them together. There's a long history of using concatenation
to build formatted
strings.
PowerShell
Concatenation works out OK when there are only a few values to add. But this can get
complicated
quickly.
PowerShell
$first = 'Kevin'
$last = 'Marquette'
PowerShell
PowerShell
The type of quotes you use around the string makes a difference. A double quoted
string allows the
substitution but a single quoted string doesn't. There are times you
want one or the other so you
have an option.
Command substitution
Things get a little tricky when you start trying to get the values of properties into a
string. This
is where many new people get tripped up. First let me show you what they
think should work (and at
face value almost looks like it should).
PowerShell
You would be expecting to get the CreationTime off of the $directory , but instead you
get this
Time: c:\windows.CreationTime as your value. The reason is that this type of
substitution only
sees the base variable. It considers the period as part of the string so it
stops resolving the
value any deeper.
It just so happens that this object gives a string as a default value when placed into a
string.
Some objects give you the type name instead like System.Collections.Hashtable .
Just something
to watch for.
PowerShell allows you to do command execution inside the string with a special syntax.
This allows
us to get the properties of these objects and run any other command to get
a value.
PowerShell
This works great for some situations but it can get just as crazy as concatenation if you
have just
a few variables.
Command execution
You can run commands inside a string. Even though I have this option, I don't like it. It
gets
cluttered quickly and hard to debug. I either run the command and save to a
variable or use a format
string.
PowerShell
Format string
.NET has a way to format strings that I find fairly easy to work with. First let me show you
the
static method for it before I show you the PowerShell shortcut to do the same thing.
PowerShell
What is happening here is that the string is parsed for the tokens {0} and {1} , then it
uses
that number to pick from the values provided. If you want to repeat one value
some place in the
string, you can reuse that values number.
The more complicated the string gets, the more value you get out of this approach.
PowerShell
$values = @(
"Kevin"
"Marquette"
This is not splatting because I'm passing the whole array in, but the idea is similar.
Advanced formatting
I intentionally called these out as coming from .NET because there are lots of formatting
options
already well documented on it. There are built in ways to format various data
types.
PowerShell
"{0:yyyyMMdd}" -f (Get-Date)
Output
20211110
Population 8,175,133
I'm not going to go into them but I just wanted to let you know that this is a very
powerful
formatting engine if you need it.
Joining strings
Sometimes you actually do want to concatenate a list of values together. There's a -
join operator
that can do that for you. It even lets you specify a character to join
PowerShell
$servers = @(
'server1'
'server2'
'server3'
If you want to -join some strings without a separator, you need to specify an empty
string '' .
But if that is all you need, there's a faster option.
PowerShell
[string]::Concat('server1','server2','server3')
[string]::Concat($servers)
It's also worth pointing out that you can also -split strings too.
Join-Path
This is often overlooked but a great cmdlet for building a file path.
PowerShell
$folder = 'Temp'
The great thing about this is it works out the backslashes correctly when it puts the
values
together. This is especially important if you are taking values from users or config
files.
This also goes well with Split-Path and Test-Path . I also cover these in my post about
reading and saving to files .
PowerShell
foreach($number in 1..10000)
It looks very basic but what you don't see is that each time a string is added to $message
that a
whole new string is created. Memory gets allocated, data gets copied and the old
one is discarded.
Not a big deal when it's only done a few times, but a loop like this
would really expose the issue.
StringBuilder
StringBuilder is also very popular for building large strings from lots of smaller strings.
The
reason why is because it just collects all the strings you add to it and only
concatenates all of
them at the end when you retrieve the value.
PowerShell
[void]$stringBuilder.Append("Numbers: ")
foreach($number in 1..10000)
[void]$stringBuilder.Append(" $number")
$message = $stringBuilder.ToString()
Again, this is something that I'm reaching out to .NET for. I don't use it often anymore
but it's
good to know it's there.
PowerShell
$test = "Bet"
$tester = "Better"
PowerShell
I personally use format string for this, but this is good to know incase you see it in the
wild.
Let us assume you pulled in a template from a file that has a lot of text.
PowerShell
You may have lots of tokens to replace. The trick is to use a very distinct token that is
easy to
find and replace. I tend to use a special character at both ends to help
distinguish it.
I recently found a new way to approach this. I decided to leave this section in here
because this is
a pattern that is commonly used.
PowerShell
$tokenList = @{
State = 'CA'
ExecutionContext ExpandString
There's a clever way to define a substitution string with single quotes and expand the
variables
later. Look at this example:
PowerShell
$message = 'Hello, $Name!'
$string = $ExecutionContext.InvokeCommand.ExpandString($message)
If we expand on that just a little bit, we can perform this substitution over and over wih
different
values.
PowerShell
foreach($name in $nameList){
$ExecutionContext.InvokeCommand.ExpandString($message)
To keep going on this idea; you could be importing a large email template from a text
file to do
this. I have to thank Mark Kraus for this suggestion .
Anything else?
I covered a lot of ground on this one. My hope is that you walk away learning
something new.
Links
If you'd like to learn more about the methods and features that make string
interpolation possible,
see the following list for the reference documentation.
Like many other languages, PowerShell has statements for conditionally executing code
in your
scripts. One of those statements is the If statement. Today we will take a deep
dive into one of
the most fundamental commands in PowerShell.
7 Note
Conditional execution
Your scripts often need to make decisions and perform different logic based on those
decisions.
This is what I mean by conditional execution. You have one statement or value
to evaluate, then
execute a different section of code based on that evaluation. This is
exactly what the if
statement does.
The if statement
Here is a basic example of the if statement:
PowerShell
$condition = $true
if ( $condition )
The first thing the if statement does is evaluate the expression in parentheses. If it
evaluates
to $true , then it executes the scriptblock in the braces. If the value was
$false , then it
would skip over that scriptblock.
In the previous example, the if statement was just evaluating the $condition variable.
It was
$true and would have executed the Write-Output command inside the
scriptblock.
In some languages, you can place a single line of code after the if statement and it
gets
executed. That isn't the case in PowerShell. You must provide a full scriptblock
with braces for
it to work correctly.
Comparison operators
The most common use of the if statement for is comparing two items with each other.
PowerShell has
special operators for different comparison scenarios. When you use a
comparison operator, the value
on the left-hand side is compared to the value on the
right-hand side.
PowerShell
$value = Get-MysteryValue
if ( 5 -eq $value )
# do something
In this example, I'm taking a known value of 5 and comparing it to my $value to see if
they
match.
One possible use case is to check the status of a value before you take an action on it.
You could
get a service and check that the status was running before you called
Restart-Service on it.
It's common in other languages like C# to use == for equality (ex: 5 == $value ) but that
doesn't
work with PowerShell. Another common mistake that people make is to use the
equals sign (ex:
5 = $value ) that is reserved for assigning values to variables. By placing
your known value on the
left, it makes that mistake more awkward to make.
PowerShell
if ( 5 -ne $value )
# do something
Use this to make sure that the action only executes if the value isn't 5 . A good use-cases
where
would be to check if a service was in the running state before you try to start it.
Variations:
These are inverse variations of -eq . I'll group these types together when I list variations
for other operators.
PowerShell
if ( $value -gt 5 )
# do something
Variations:
I don't know why you would use case-sensitive and insensitive options for these
operators.
PowerShell
$value = 'S-ATX-SQL01'
# do something
It's important to point out that the pattern matches the whole string. If you need to
match
something in the middle of the string, you need to place the * on both ends of
the
string.
PowerShell
$value = 'S-ATX-SQL02'
# do something
Variations:
PowerShell
$value = 'S-ATX-SQL01'
# do something
A regex pattern matches anywhere in the string by default. So you can specify a
substring that
you want matched like this:
PowerShell
$value = 'S-ATX-SQL01'
# do something
Regex is a complex language of its own and worth looking into. I talk more about -
match and
the many ways to use regex in another article.
Variations:
-is of type
You can check a value's type with the -is operator.
PowerShell
# do something
You may use this if you're working with classes or accepting various objects over the
pipeline. You
could have either a service or a service name as your input. Then check to
see if you have a service
and fetch the service if you only have the name.
PowerShell
Variations:
-is of type
-isnot not of type
Collection operators
When you use the previous operators with a single value, the result is $true or $false .
This is
handled slightly differently when working with a collection. Each item in the
collection gets
evaluated and the operator returns every value that evaluates to $true .
PowerShell
This still works correctly in a if statement. So a value is returned by your operator, then
the
whole statement is $true .
PowerShell
$array = 1..6
if ( $array -gt 3 )
# do something
There's one small trap hiding in the details here that I need to point out. When using the
-ne
operator this way, it's easy to mistakenly look at the logic backwards. Using -ne
with a
collection returns $true if any item in the collection doesn't match your value.
PowerShell
This may look like a clever trick, but we have operators -contains and -in that handle
this more
efficiently. And -notcontains does what you expect.
-contains
The -contains operator checks the collection for your value. As soon as it finds a match,
it
returns $true .
PowerShell
$array = 1..6
if ( $array -contains 3 )
# do something
This is the preferred way to see if a collection contains your value. Using Where-Object
(or
-eq ) walks the entire list every time and is significantly slower.
Variations:
PowerShell
$array = 1..6
if ( 3 -in $array )
# do something
Variations:
Logical operators
Logical operators are used to invert or combine other expressions.
-not
The -not operator flips an expression from $false to $true or from $true to $false .
Here
is an example where we want to perform an action when Test-Path is $false .
PowerShell
Most of the operators we talked about do have a variation where you do not need to
use the -not
operator. But there are still times it is useful.
! operator
You can use ! as an alias for -not .
PowerShell
if ( !$value ){}
You may see ! used more by people that come from another languages like C#. I prefer
to type it
out because I find it hard to see when quickly looking at my scripts.
-and
You can combine expressions with the -and operator. When you do that, both sides
need to be
$true for the whole expression to be $true .
PowerShell
In that example, $age must be 13 or older for the left side and less than 55 for the right
side. I
added extra parentheses to make it clearer in that example but they're optional as
long as the
expression is simple. Here is the same example without them.
PowerShell
Evaluation happens from left to right. If the first item evaluates to $false , it exits early
and
doesn't perform the right comparison. This is handy when you need to make sure a
value exists before
you use it. For example, Test-Path throws an error if you give it a
$null path.
PowerShell
-or
The -or allows for you to specify two expressions and returns $true if either one of
them is
$true .
PowerShell
Just like with the -and operator, the evaluation happens from left to right. Except that if
the
first part is $true , then the whole statement is $true and it doesn't process the rest
of the
expression.
Also make note of how the syntax works for these operators. You need two separate
expressions. I
have seen users try to do something like this $value -eq 5 -or 6 without
realizing their mistake.
-xor exclusive or
This one is a little unusual. -xor allows only one expression to evaluate to $true . So if
both
items are $false or both items are $true , then the whole expression is $false .
Another way to
look at this is the expression is only $true when the results of the
expression are different.
It's rare that anyone would ever use this logical operator and I can't think up a good
example as to
why I would ever use it.
Bitwise operators
Bitwise operators perform calculations on the bits within the values and produce a new
value as the
result. Teaching bitwise operators is beyond the scope of this article, but
here is the list the
them.
-bor binary OR
-bxor binary exclusive OR
PowerShell expressions
We can use normal PowerShell inside the condition statement.
PowerShell
Test-Path returns $true or $false when it executes. This also applies to commands
that return
other values.
PowerShell
if ( Get-Process Notepad* )
PowerShell
These expressions can be combined with each other with the -and and -or operators,
but you may
have to use parenthesis to break them into subexpressions.
PowerShell
PowerShell
There are quite a few nuances when dealing with $null values in PowerShell. If you're
interested
in diving deeper, I have an article about everything you wanted to know
about $null.
PowerShell
if ($process=Get-Process notepad -ErrorAction ignore) {$process} else
{$false}
Normally when you assign a value to a variable, the value isn't passed onto the pipeline
or
console. When you do a variable assignment in a sub expression, it does get passed
on to the
pipeline.
PowerShell
PS> $first = 1
PS> ($second = 2)
See how the $first assignment has no output and the $second assignment does?
When an assignment
is done in an if statement, it executes just like the $second
assignment above. Here is a clean
example on how you could use it:
PowerShell
$process | Stop-Process
If $process gets assigned a value, then the statement is $true and $process gets
stopped.
Make sure you don't confuse this with -eq because this isn't an equality check. This is a
more
obscure feature that most people don't realize works this way.
PowerShell
Get-SeniorDiscount
Get-ChildDiscount
else
0.00
Each script block is writing the results of the commands, or the value, as output. We can
assign the
result of the if statement to the $discount variable. That example could
have just as easily
assigned those values to the $discount variable directly in each
scriptblock. I can't say that I
use this with the if statement often, but I do have an
example where I used this recently.
else
The else statement is always the last part of the if statement when used.
PowerShell
else
In this example, we check the $path to make sure it's a file. If we find the file, we move
it. If
not, we write a warning. This type of branching logic is very common.
Nested if
The if and else statements take a script block, so we can place any PowerShell
command inside
them, including another if statement. This allows you to make use of
much more complicated logic.
PowerShell
if ( Test-Path -Path $Path -PathType Leaf )
else
else
In this example, we test the happy path first and then take action on it. If that fails, we
do
another check and to provide more detailed information to the user.
elseif
We aren't limited to just a single conditional check. We can chain if and else
statements
together instead of nesting them by using the elseif statement.
PowerShell
Write-Warning "A file was required but a directory was found instead."
else
The execution happens from the top to the bottom. The top if statement is evaluated
first. If that
is $false , then it moves down to the next elseif or else in the list. That
last else is the
default action to take if none of the others return $true .
switch
At this point, I need to mention the switch statement. It provides an alternate syntax for
doing
multiple comparisons with a value. With the switch , you specify an expression
and that result gets
compared with several different values. If one of those values match,
the matching code block is
executed. Take a look at this example:
PowerShell
$itemType = 'Role'
switch ( $itemType )
'Component'
'is a component'
'Role'
'is a role'
'Location'
'is a location'
There three possible values that can match the $itemType . In this case, it matches with
Role . I
used a simple example just to give you some exposure to the switch operator. I
talk more
about everything you ever wanted to know about the switch statement in
another article.
Array inline
I have a function called Invoke-SnowSql that launches an executable with several
command-line
arguments. Here is a clip from that function where I build the array of
arguments.
PowerShell
$snowSqlParam = @(
'--accountname', $Endpoint
'--username', $Credential.UserName
'--option', 'exit_on_error=true'
'--option', 'output_format=csv'
'--option', 'friendly=false'
'--option', 'timing=false'
if ($Debug)
'--option', 'log_level=DEBUG'
if ($Path)
'--filename', $Path
else
'--query', $singleLineQuery
The $Debug and $Path variables are parameters on the function that are provided by the
end user.
I evaluate them inline inside the initialization of my array. If $Debug is true,
then those values
fall into the $snowSqlParam in the correct place. Same holds true for
the $Path variable.
PowerShell
# Do Something
They can be hard to read and that make you more prone to make mistakes. There are a
few things we
can do about that.
Line continuation
There some operators in PowerShell that let you wrap you command to the next line.
The logical
operators -and and -or are good operators to use if you want to break your
expression into
multiple lines.
PowerShell
# Do Something
There's still a lot going on there, but placing each piece on its own line makes a big
difference.
I generally use this when I get more than two comparisons or if I have to
scroll to the right to
read any of the logic.
Pre-calculating results
We can take that statement out of the if statement and only check the result.
PowerShell
if ( $needsSecureHomeDrive )
# Do Something
This just feels much cleaner than the previous example. You also are given an
opportunity to use a
variable name that explains what it's that you're really checking.
This is also and example of
self-documenting code that saves unnecessary comments.
Multiple if statements
We can break this up into multiple statements and check them one at a time. In this
case, we use a
flag or a tracking variable to combine the results.
PowerShell
$skipUser = $false
$skipUser = $true
$skipUser = $true
$skipUser = $true
$skipUser = $true
if ( -not $skipUser )
# do something
I did have to invert the logic to make the flag logic work correctly. Each evaluation is an
individual if statement. The advantage of this is that when you're debugging, you can
tell
exactly what the logic is doing. I was able to add much better verbosity at the same
time.
The obvious downside is that it's so much more code to write. The code is more
complex to look at
as it takes a single line of logic and explodes it into 25 or more lines.
Using functions
We can also move all that validation logic into a function. Look at how clean this looks
at a
glance.
PowerShell
# do something
You still have to create the function to do the validation, but it makes this code much
easier to
work with. It makes this code easier to test. In your tests, you can mock the call
to
Test-ADDriveConfiguration and you only need two tests for this function. One where
it returns
$true and one where it returns $false . Testing the other function is simpler
because it's
so small.
The body of that function could still be that one-liner we started with or the exploded
logic that
we used in the last section. This works well for both scenarios and allows you
to easily change that
implementation later.
Error handling
One important use of the if statement is to check for error conditions before you run
into
errors. A good example is to check if a folder already exists before you try to create
it.
PowerShell
I like to say that if you expect an exception to happen, then it's not really an exception.
So check
your values and validate your conditions where you can.
If you want to dive a little more into actual exception handling, I have an article on
everything you ever wanted to know about exceptions.
Final words
The if statement is such a simple statement but is a fundamental piece of PowerShell.
You will
find yourself using this multiple times in almost every script you write. I hope
you have a better
understanding than you had before.
Everything you ever wanted to know
about the switch statement
Article • 11/17/2022
Like many other languages, PowerShell has commands for controlling the flow of
execution within your
scripts. One of those statements is the switch statement and in
PowerShell, it offers
features that aren't found in other languages. Today, we take a deep
dive into working with the
PowerShell switch .
7 Note
The if statement
One of the first statements that you learn is the if statement. It lets you execute a script
block
if a statement is $true .
PowerShell
if ( Test-Path $Path )
Remove-Item $Path
You can have much more complicated logic using elseif and else statements. Here is
an example
where I have a numeric value for day of the week and I want to get the
name as a string.
PowerShell
$day = 3
$result
Output
Wednesday
It turns out that this is a common pattern and there are many ways to deal with this.
One
of them is with a switch .
Switch statement
The switch statement allows you to provide a variable and a list of possible values. If
the value
matches the variable, then its scriptblock is executed.
PowerShell
$day = 3
switch ( $day )
0 { $result = 'Sunday' }
1 { $result = 'Monday' }
2 { $result = 'Tuesday' }
3 { $result = 'Wednesday' }
4 { $result = 'Thursday' }
5 { $result = 'Friday' }
6 { $result = 'Saturday' }
$result
Output
'Wednesday'
For this example, the value of $day matches one of the numeric values, then the correct
name is
assigned to $result . We're only doing a variable assignment in this example,
but any PowerShell
can be executed in those script blocks.
Assign to a variable
We can write that last example in another way.
PowerShell
0 { 'Sunday' }
1 { 'Monday' }
2 { 'Tuesday' }
3 { 'Wednesday' }
4 { 'Thursday' }
5 { 'Friday' }
6 { 'Saturday' }
We're placing the value on the PowerShell pipeline and assigning it to the $result . You
can do
this same thing with the if and foreach statements.
Default
We can use the default keyword to identify the what should happen if there is no
match.
PowerShell
0 { 'Sunday' }
# ...
6 { 'Saturday' }
default { 'Unknown' }
Strings
I was matching numbers in those last examples, but you can also match strings.
PowerShell
$item = 'Role'
switch ( $item )
Component
'is a component'
Role
'is a role'
Location
'is a location'
Output
is a role
I decided not to wrap the Component , Role and Location matches in quotes here to
highlight that
they're optional. The switch treats those as a string in most cases.
Arrays
One of the cool features of the PowerShell switch is the way it handles arrays. If you
give a
switch an array, it processes each element in that collection.
PowerShell
$roles = @('WEB','Database')
switch ( $roles ) {
Output
Configure IIS
Configure SQL
If you have repeated items in your array, then they're matched multiple times by the
appropriate
section.
PSItem
You can use the $PSItem or $_ to reference the current item that was processed. When
we do a
simple match, $PSItem is the value that we're matching. I'll be performing some
advanced matches
in the next section where this variable is used.
Parameters
A unique feature of the PowerShell switch is that it has a number of switch parameters
that
change how it performs.
-CaseSensitive
The matches aren't case-sensitive by default. If you need to be case-sensitive, you can
use
-CaseSensitive . This can be used in combination with the other switch parameters.
-Wildcard
We can enable wildcard support with the -wildcard switch. This uses the same wildcard
logic as the
-like operator to do each match.
PowerShell
'Error*'
'Warning*'
default
Write-Information $message
Output
Here we're processing a message and then outputting it on different streams based on
the contents.
-Regex
The switch statement supports regex matches just like it does wildcards.
PowerShell
'^Error'
'^Warning'
default
Write-Information $message
-File
A little known feature of the switch statement is that it can process a file with the -File
parameter. You use -file with a path to a file instead of giving it a variable expression.
PowerShell
'Error*'
'Warning*'
default
Write-Output $PSItem
It works just like processing an array. In this example, I combine it with wildcard
matching and
make use of the $PSItem . This would process a log file and convert it to
warning and error
messages depending on the regex matches.
Advanced details
Now that you're aware of all these documented features, we can use them in the context
of more
advanced processing.
Expressions
The switch can be on an expression instead of a variable.
PowerShell
Whatever the expression evaluates to is the value used for the match.
Multiple matches
You may have already picked up on this, but a switch can match to multiple conditions.
This is
especially true when using -wildcard or -regex matches. You can add the same
condition multiple
times and all are triggered.
PowerShell
switch ( 'Word' )
Output
All three of these statements are fired. This shows that every condition is checked (in
order). This
holds true for processing arrays where each item checks each condition.
Continue
Normally, this is where I would introduce the break statement, but it's better that we
learn how
to use continue first. Just like with a foreach loop, continue continues onto
the next item in
the collection or exits the switch if there are no more items. We can
rewrite that last example
with continue statements so that only one statement executes.
PowerShell
switch ( 'Word' )
'word'
continue
'Word'
continue
'WORD'
continue
Output
Instead of matching all three items, the first one is matched and the switch continues to
the next
value. Because there are no values left to process, the switch exits. This next
example is showing
how a wildcard could match multiple items.
PowerShell
'*Error*'
continue
'*Warning*'
continue
default
Write-Output $PSItem
Because a line in the input file could contain both the word Error and Warning , we only
want the
first one to execute and then continue processing the file.
Break
A break statement exits the switch. This is the same behavior that continue presents for
single
values. The difference is shown when processing an array. break stops all
processing in the switch
and continue moves onto the next item.
PowerShell
$Messages = @(
'Downloading update'
'Sending email'
'...'
'Error*'
break
'*Error*'
continue
'*Warning*'
continue
default
Write-Output $PSItem
Output
Downloading update
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
In this case, if we hit any lines that start with Error then we get an error and the switch
stops.
This is what that break statement is doing for us. If we find Error inside the
string and not
just at the beginning, we write it as a warning. We do the same thing for
Warning . It's possible
that a line could have both the word Error and Warning , but we
only need one to process. This is
what the continue statement is doing for us.
Break labels
The switch statement supports break/continue labels just like foreach .
PowerShell
'Error*'
break filelist
'Warning*'
break logFile
default
Write-Output $PSItem
I personally don't like the use of break labels but I wanted to point them out because
they're
confusing if you've never seen them before. When you have multiple switch or
foreach statements
that are nested, you may want to break out of more than the inner
PowerShell
enum Context {
Component
Role
Location
$item = [Context]::Role
switch ( $item )
Component
'is a component'
Role
'is a role'
Location
'is a location'
Output
is a role
If you want to keep everything as strongly typed enums, then you can place them in
parentheses.
PowerShell
switch ($item )
([Context]::Component)
'is a component'
([Context]::Role)
'is a role'
([Context]::Location)
'is a location'
The parentheses are needed here so that the switch doesn't treat the value
[Context]::Location as
a literal string.
ScriptBlock
We can use a scriptblock to perform the evaluation for a match if needed.
PowerShell
$age = 37
switch ( $age )
'child'
'adult'
Output
'adult'
This adds complexity and can make your switch hard to read. In most cases where you
would use
something like this it would be better to use if and elseif statements. I
would consider using
this if I already had a large switch in place and I needed two items
to hit the same evaluation
block.
One thing that I think helps with legibility is to place the scriptblock in parentheses.
PowerShell
switch ( $age )
'child'
'adult'
It still executes the same way and gives a better visual break when quickly looking at it.
Regex $matches
We need to revisit regex to touch on something that isn't immediately obvious. The use
of regex
populates the $matches variable. I do go into the use of $matches more when I
talk about
The many ways to use regex . Here is a quick sample to show it in
action
with named matches.
PowerShell
'(?<SSN>\d\d\d-\d\d-\d\d\d\d)'
'(?<CC>\d\d\d\d-\d\d\d\d-\d\d\d\d-\d\d\d\d)'
'(?<Phone>\d\d\d-\d\d\d-\d\d\d\d)'
Output
$null
You can match a $null value that doesn't have to be the default.
PowerShell
$values = '', 5, $null
switch ( $values )
Output
When testing for an empty string in a switch statement, it's important to use the
comparison
statement as shown in this example instead of the raw value '' . In a switch
statement, the raw
value '' also matches $null . For example:
PowerShell
switch ( $values )
Output
Also, be careful with empty returns from cmdlets. Cmdlets or pipelines that have no
output are
treated as an empty array that doesn't match anything, including the
default case.
PowerShell
switch ( $file )
# No matches
Constant expression
Lee Dailey pointed out that we can use a constant $true expression to evaluate [bool]
items.
Imagine if we have several boolean checks that need to happen.
PowerShell
$isVisible = $false
$isEnabled = $true
$isSecure = $true
switch ( $true )
$isEnabled
'Do-Action'
$isVisible
'Show-Animation'
$isSecure
'Enable-AdminMenu'
Output
Do-Action
Enabled-AdminMenu
This is a clean way to evaluate and take action on the status of several boolean fields.
The cool
thing about this is that you can have one match flip the status of a value that
hasn't been
evaluated yet.
PowerShell
$isVisible = $false
$isEnabled = $true
$isAdmin = $false
switch ( $true )
$isEnabled
'Do-Action'
$isVisible = $true
$isVisible
'Show-Animation'
$isAdmin
'Enable-AdminMenu'
Output
Do-Action
Show-Animation
Setting $isEnabled to $true in this example makes sure that $isVisible is also set to
$true .
Then when $isVisible gets evaluated, its scriptblock is invoked. This is a bit
counter-intuitive
but is a clever use of the mechanics.
PowerShell
$a = 1, 2, 3, 4
switch($a) {
1 { [void]$switch.MoveNext(); $switch.Current }
3 { [void]$switch.MoveNext(); $switch.Current }
Output
By moving the enumerator forward, the next item doesn't get processed by the switch
but you can
access that value directly. I would call it madness.
Other patterns
Hashtables
One of my most popular posts is the one I did on hashtables. One of the use cases for
a
hashtable is to be a lookup table. That's an alternate approach to a common pattern
that a
switch statement is often addressing.
PowerShell
$day = 3
$lookup = @{
0 = 'Sunday'
1 = 'Monday'
2 = 'Tuesday'
3 = 'Wednesday'
4 = 'Thursday'
5 = 'Friday'
6 = 'Saturday'
$lookup[$day]
Output
Wednesday
Enum
PowerShell 5.0 introduced the Enum and it's also an option in this case.
PowerShell
$day = 3
enum DayOfTheWeek {
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
[DayOfTheWeek]$day
Output
Wednesday
We could go all day looking at different ways to solve this problem. I just wanted to
make sure you
knew you had options.
Final words
The switch statement is simple on the surface but it offers some advanced features that
most people
don't realize are available. Stringing those features together makes this a
powerful feature. I hope
you learned something that you had not realized before.
Everything you wanted to know about
exceptions
Article • 11/17/2022
Error handling is just part of life when it comes to writing code. We can often check and
validate
conditions for expected behavior. When the unexpected happens, we turn to
exception handling. You
can easily handle exceptions generated by other people's code
or you can generate your own
exceptions for others to handle.
7 Note
Basic terminology
We need to cover some basic terms before we jump into this one.
Exception
An Exception is like an event that is created when normal error handling can't deal with
the issue.
Trying to divide a number by zero or running out of memory are examples of
something that creates an
exception. Sometimes the author of the code you're using
creates exceptions for certain issues
when they happen.
I point this out because Write-Error and other non-terminating errors do not trigger
the
catch .
Swallowing an exception
This is when you catch an error just to suppress it. Do this with caution because it can
make
troubleshooting issues very difficult.
Throw
To create our own exception event, we throw an exception with the throw keyword.
PowerShell
function Start-Something
This creates a runtime exception that is a terminating error. It's handled by a catch in a
calling function or exits the script with a message like this.
PowerShell
PS> Start-Something
At line:1 char:1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
PowerShell
Thank you to Lee Dailey for reminding about using -ErrorAction Stop this way.
PowerShell
Try/Catch
The way exception handling works in PowerShell (and many other languages) is that you
first try a
section of code and if it throws an error, you can catch it. Here is a quick
sample.
PowerShell
try
Start-Something
catch
Write-Output $_
try
catch
Write-Output $_
The catch script only runs if there's a terminating error. If the try executes correctly,
then
it skips over the catch . You can access the exception information in the catch
block using the
$_ variable.
Try/Finally
Sometimes you don't need to handle an error but still need some code to execute if an
exception
happens or not. A finally script does exactly that.
PowerShell
$command.Connection.Open()
$command.ExecuteNonQuery()
$command.Connection.Close()
Anytime you open or connect to a resource, you should close it. If the
ExecuteNonQuery() throws
an exception, the connection isn't closed. Here is the same
code inside a try/finally block.
PowerShell
try
$command.Connection.Open()
$command.ExecuteNonQuery()
finally
$command.Connection.Close()
In this example, the connection is closed if there's an error. It also is closed if there's no
error. The finally script runs every time.
Because you're not catching the exception, it still gets propagated up the call stack.
Try/Catch/Finally
It's perfectly valid to use catch and finally together. Most of the time you'll use one or
the other, but you may find scenarios where you use both.
$PSItem
Now that we got the basics out of the way, we can dig a little deeper.
For these examples, I used an invalid path in ReadAllText to generate this exception.
PowerShell
[System.IO.File]::ReadAllText( '\\test\no\filefound.log')
PSItem.ToString()
This gives you the cleanest message to use in logging and general output. ToString() is
automatically called if $PSItem is placed inside a string.
PowerShell
catch
catch
$PSItem.InvocationInfo
This property contains additional information collected by PowerShell about the
function or script
where the exception was thrown. Here is the InvocationInfo from the
sample exception that I
created.
PowerShell
MyCommand : Get-Resource
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 5
OffsetInLine : 5
ScriptName : C:\blog\throwerror.ps1
Line : Get-Resource
+ Get-Resource
+ ~~~~~~~~~~~~
PSScriptRoot : C:\blog
PSCommandPath : C:\blog\throwerror.ps1
InvocationName : Get-Resource
The important details here show the ScriptName , the Line of code and the
ScriptLineNumber
where the invocation started.
$PSItem.ScriptStackTrace
This property shows the order of function calls that got you to the code where the
exception was
generated.
PowerShell
PS> $PSItem.ScriptStackTrace
I'm only making calls to functions in the same script but this would track the calls if
multiple
scripts were involved.
$PSItem.Exception
This is the actual exception that was thrown.
$PSItem.Exception.Message
This is the general message that describes the exception and is a good starting point
when
troubleshooting. Most exceptions have a default message but can also be set to
something custom when
the exception is thrown.
PowerShell
PS> $PSItem.Exception.Message
Exception calling "ReadAllText" with "1" argument(s): "The network path was
not found."
This is also the message returned when calling $PSItem.ToString() if there was not one
set on the
ErrorRecord .
$PSItem.Exception.InnerException
Exceptions can contain inner exceptions. This is often the case when the code you're
calling
catches an exception and throws a different exception. The original exception is
placed inside
the new exception.
PowerShell
PS> $PSItem.Exception.InnerExceptionMessage
$PSItem.Exception.StackTrace
This is the StackTrace for the exception. I showed a ScriptStackTrace above, but this
one is for
the calls to managed code.
Output
checkHost)
You only get this stack trace when the event is thrown from managed code. I'm calling a
.NET
framework function directly so that is all we can see in this example. Generally
when you're
looking at a stack trace, you're looking for where your code stops and the
system calls begin.
PowerShell
try
catch [System.IO.FileNotFoundException]
catch [System.IO.IOException]
The exception type is checked for each catch block until one is found that matches your
exception.
It's important to realize that exceptions can inherit from other exceptions. In
the example above,
FileNotFoundException inherits from IOException . So if the
IOException was first, then it
would get called instead. Only one catch block is invoked
PowerShell
try
catch [System.IO.DirectoryNotFoundException],
[System.IO.FileNotFoundException]
{
catch [System.IO.IOException]
PowerShell
PowerShell
You can also create a new instance of an exception to be thrown. The message is
optional when you do
this because the system has default messages for all built-in
exceptions.
PowerShell
throw [System.IO.FileNotFoundException]::new()
If you're not using PowerShell 5.0 or higher, you must use the older New-Object
approach.
PowerShell
By using a typed exception, you (or others) can catch the exception by the type as
mentioned in the
previous section.
Write-Error -Exception
We can add these typed exceptions to Write-Error and we can still catch the errors by
exception
type. Use Write-Error like in these examples:
PowerShell
# Pre PS 5.0
PowerShell
catch [System.IO.FileNotFoundException]
Write-Log $PSItem.ToString()
I start by searching that list for exceptions that feel like they would be a good fit for my
situation. You should try to use exceptions in the base System namespace.
PowerShell
PowerShell
catch [System.IO.FileNotFoundException]
Write-Output $PSItem.Exception.FileName
You should consult the .NET documentation for other constructors and object
properties.
Re-throwing an exception
If all you're going to do in your catch block is throw the same exception, then don't
catch
it. You should only catch an exception that you plan to handle or perform some
action when it
happens.
There are times where you want to perform an action on an exception but re-throw the
exception so
something downstream can deal with it. We could write a message or log
the problem close to where we
discover it but handle the issue further up the stack.
PowerShell
catch
Write-Log $PSItem.ToString()
throw $PSItem
Interestingly enough, we can call throw from within the catch and it re-throws the
current
exception.
PowerShell
catch
Write-Log $PSItem.ToString()
throw
We want to re-throw the exception to preserve the original execution information like
source script
and line number. If we throw a new exception at this point, it hides where
the exception started.
PowerShell
catch
$PSCmdlet.ThrowTerminatingError()
The one thing that I don't like about using throw for raw exceptions is that the error
message
points at the throw statement and indicates that line is where the problem is.
Output
At line:31 char:9
+ throw [System.IO.FileNotFoundException]::new()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Having the error message tell me that my script is broken because I called throw on line
31 is a
bad message for users of your script to see. It doesn't tell them anything useful.
Dexter Dhami pointed out that I can use ThrowTerminatingError() to correct that.
PowerShell
$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
[System.Management.Automation.ErrorCategory]::OpenError,
$MyObject
Output
Assemblies\Microsoft\Framework\.NETPortable\v4.6\System.IO.xml
At line:6 char:5
+ ~~~~~~~~~~~~
+ FullyQualifiedErrorId : My.ID,Get-Resource
Do you see how it points to the Get-Resource function as the source of the problem?
That tells the
user something useful.
PowerShell
catch
$PSCmdlet.ThrowTerminatingError($PSItem)
This changes the source of the error to the Cmdlet and hide the internals of your
function from
the users of your Cmdlet.
PowerShell
Then invoke it like this to see it generate the error and still output the message.
PowerShell
But by placing that same code inside a try/catch , we see something else happen.
PowerShell
try
catch
We see the error become a terminating error and not output the first message. What I
don't like
about this one is that you can have this code in a function and it acts
differently if someone
is using a try/catch .
I have not ran into issues with this myself but it is corner case to be aware of.
functions.
PowerShell
function Start-Something
[CmdletBinding()]
param()
process
try
...
catch
$PSCmdlet.ThrowTerminatingError($PSItem)
Trap
I focused on the try/catch aspect of exceptions. But there's one legacy feature I need
to mention
before we wrap this up.
A trap is placed in a script or function to catch all exceptions that happen in that scope.
When
an exception happens, the code in the trap is executed and then the normal
code continues. If
multiple exceptions happen, then the trap is called over and over.
PowerShell
trap
Write-Log $PSItem.ToString()
throw [System.Exception]::new('first')
throw [System.Exception]::new('second')
throw [System.Exception]::new('third')
I personally never adopted this approach but I can see the value in admin or controller
scripts that
log any and all exceptions, then still continue to execute.
Closing remarks
Adding proper exception handling to your scripts not only make them more stable, but
also makes it
easier for you to troubleshoot those exceptions.
I spent a lot of time talking throw because it is a core concept when talking about
exception
handling. PowerShell also gave us Write-Error that handles all the situations
where you would use
throw . So don't think that you need to be using throw after
reading this.
Now that I have taken the time to write about exception handling in this detail, I'm
going to
switch over to using Write-Error -Stop to generate errors in my code. I'm also
going to take
Kirk's advice and make ThrowTerminatingError my goto exception handler
for every function.
Everything you wanted to know about
$null
Article • 11/17/2022
The PowerShell $null often appears to be simple but it has a lot of nuances. Let's take a
close
look at $null so you know what happens when you unexpectedly run into a $null
value.
7 Note
What is NULL?
You can think of NULL as an unknown or empty value. A variable is NULL until you
assign a value or
an object to it. This can be important because there are some
commands that require a value and
generate errors if the value is NULL.
PowerShell $null
$null is an automatic variable in PowerShell used to represent NULL. You can assign it
to
variables, use it in comparisons and use it as a place holder for NULL in a collection.
PowerShell treats $null as an object with a value of NULL. This is different than what
you may
expect if you come from another language.
Examples of $null
Anytime you try to use a variable that you have not initialized, the value is $null . This is
one
of the most common ways that $null values sneak into your code.
PowerShell
True
If you happen to mistype a variable name then PowerShell sees it as a different variable
and the
value is $null .
The other way you find $null values is when they come from other commands that
don't give you
any results.
PowerShell
True
Impact of $null
$null values impact your code differently depending on where they show up.
In strings
If you use $null in a string, then it's a blank value (or empty string).
PowerShell
The value is
This is one of the reasons that I like to place brackets around variables when using them
in log
messages. It's even more important to identify the edges of your variable values
when the value is
at the end of the string.
PowerShell
The value is []
In numeric equation
When a $null value is used in a numeric equation then your results are invalid if they
don't give
an error. Sometimes the $null evaluates to 0 and other times it makes the
whole result $null .
Here is an example with multiplication that gives 0 or $null
depending on the order of the values.
PowerShell
PS> $null * 5
True
PS> 5 * $null
False
In place of a collection
A collection allows you use an index to access values. If you try to index into a collection
that is
actually null , you get this error: Cannot index into a null array .
PowerShell
PS> $value[10]
At line:1 char:1
+ $value[10]
+ ~~~~~~~~~~
+ FullyQualifiedErrorId : NullArray
If you have a collection but try to access an element that is not in the collection, you get
a
$null result.
PowerShell
$array = @( 'one','two','three' )
True
In place of an object
If you try to access a property or sub property of an object that doesn't have the
specified
property, you get a $null value like you would for an undefined variable. It
doesn't matter if the
variable is $null or an actual object in this case.
PowerShell
True
True
PowerShell
PS> $value.toString()
At line:1 char:1
+ $value.tostring()
+ ~~~~~~~~~~~~~~~~~
+ FullyQualifiedErrorId : InvokeMethodOnNull
Whenever I see the phrase You cannot call a method on a null-valued expression then
the first
thing I look for are places where I am calling a method on a variable without
first checking it
for $null .
PowerShell
If I do not define $value , the first one evaluates to $true and our message is
The array
is $null . The trap here is that it's possible to create a $value that allows both of
them
to be $false
PowerShell
$value = @( $null )
In this case, the $value is an array that contains a $null . The -eq checks every value in
the
array and returns the $null that is matched. This evaluates to $false . The -ne
returns
everything that doesn't match $null and in this case there are no results (This
also evaluates to
$false ). Neither one is $true even though it looks like one of them
should be.
Not only can we create a value that makes both of them evaluate to $false , it's possible
to
create a value where they both evaluate to $true . Mathias Jessen (@IISResetMe) has
a
good post that dives into that scenario.
PowerShell
RuleName Message
-------- -------
Because VS Code uses the PSScriptAnalyser rules too, it also highlights or identifies this
as a
problem in your script.
Simple if check
A common way that people check for a non-$null value is to use a simple if()
statement without
the comparison.
PowerShell
if ( $value )
Do-Something
If the value is $null , this evaluates to $false . This is easy to read, but be careful that it's
looking for exactly what you're expecting it to look for. I read that line of code as:
But that's not the whole story. That line is actually saying:
PowerShell
Do-Something
It's perfectly OK to use a basic if check as long as you remember those other values
count as
$false and not just that a variable has a value.
I ran into this issue when refactoring some code a few days ago. It had a basic property
check like
this.
PowerShell
if ( $object.property )
{
$object.property = $value
I wanted to assign a value to the object property only if it existed. In most cases, the
original
object had a value that would evaluate to $true in the if statement. But I ran
into an issue
where the value was occasionally not getting set. I debugged the code and
found that the object had
the property but it was a blank string value. This prevented it
from ever getting updated with the
previous logic. So I added a proper $null check and
everything worked.
PowerShell
$object.property = $value
It's little bugs like these that are hard to spot and make me aggressively check values for
$null .
$null.Count
If you try to access a property on a $null value, that the property is also $null . The
count
property is the exception to this rule.
PowerShell
PS> $value.count
When you have a $null value, then the count is 0 . This special property is added by
PowerShell.
[PSCustomObject] Count
Almost all objects in PowerShell have that count property. One important exception is
the
[PSCustomObject] in Windows PowerShell 5.1 (This is fixed in PowerShell 6.0). It
doesn't have a
count property so you get a $null value if you try to use it. I call this out
here so that you
don't try to use .Count instead of a $null check.
Running this example on Windows PowerShell 5.1 and PowerShell 6.0 gives you different
results.
PowerShell
$value = [PSCustomObject]@{Name='MyObject'}
if ( $value.count -eq 1 )
Empty null
There is one special type of $null that acts differently than the others. I am going to call
it
the empty $null but it's really a
System.Management.Automation.Internal.AutomationNull. This
empty $null is the one
you get as the result of a function or script block that returns nothing (a
void result).
PowerShell
True
If you compare it with $null , you get a $null value. When used in an evaluation where
a value is
required, the value is always $null . But if you place it inside an array, it's
treated the same as
an empty array.
PowerShell
PS> $containempty.count
PS> $containnothing.count
PS> $containnull.count
You can have an array that contains one $null value and its count is 1 . But if you place
an empty result inside an array then it's not counted as an item. The count is 0 .
If you treat the empty $null like a collection, then it's empty.
If you pass in an empty value to a function parameter that isn't strongly typed,
PowerShell coerces
the nothing value into a $null value by default. This means inside
the function, the value will be
treated as $null instead of the
System.Management.Automation.Internal.AutomationNull type.
Pipeline
The primary place you see the difference is when using the pipeline. You can pipe a
$null
value but not an empty $null value.
PowerShell
'NULL Value'
Depending on your code, you should account for the $null in your logic.
Filter out null on the pipeline ( ... | Where {$null -ne $_} | ... )
Handle it in the pipeline function
foreach
One of my favorite features of foreach is that it doesn't enumerate over a $null
collection.
PowerShell
#skipped
This saves me from having to $null check the collection before I enumerate it. If you
have a
collection of $null values, the $node can still be $null .
The foreach started working this way with PowerShell 3.0. If you happen to be on an
older version,
then this is not the case. This is one of the important changes to be aware
of when back-porting
code for 2.0 compatibility.
Value types
Technically, only reference types can be $null . But PowerShell is very generous and
allows for
variables to be any type. If you decide to strongly type a value type, it cannot
be $null .
PowerShell converts $null to a default value for many types.
PowerShell
PS> $number
PS> $boolean
False
True
There are some types that do not have a valid conversion from $null . These types
generate a
Cannot convert null to type error.
PowerShell
At line:1 char:1
+ [datetime]$date = $null
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ FullyQualifiedErrorId : RuntimeException
Function parameters
Using a strongly typed values in function parameters is very common. We generally
learn to define
the types of our parameters even if we tend not to define the types of
other variables in our
scripts. You may already have some strongly typed variables in
your functions and not even realize
it.
PowerShell
function Do-Something
param(
[String] $Value
As soon as you set the type of the parameter as a string , the value can never be $null .
It's
common to check if a value is $null to see if the user provided a value or not.
PowerShell
$Value is an empty string '' when no value is provided. Use the automatic variable
$PSBoundParameters.Value instead.
PowerShell
$PSBoundParameters only contains the parameters that were specified when the function
was called.
You can also use the ContainsKey method to check for the property.
PowerShell
if ( $PSBoundParameters.ContainsKey('Value') ){...}
IsNotNullOrEmpty
If the value is a string, you can use a static string function to check if the value is $null
or
an empty string at the same time.
PowerShell
I find myself using this often when I know the value type should be a string.
PowerShell
I much prefer using if or foreach over using try/catch . Don't get me wrong, I still use
try/catch a lot. But if I can test for an error condition or an empty set of results, I can
allow
my exception handling be for true exceptions.
I also tend to check for $null before I index into a value or call methods on an object.
These two
actions fail for a $null object so I find it important to validate them first. I
already covered
those scenarios earlier in this post.
No results scenario
It's important to know that different functions and commands handle the no results
scenario
differently. Many PowerShell commands return the empty $null and an error
in the error stream. But
others throw exceptions or give you a status object. It's still up
to you to know how the commands
you use deal with the no results and error scenarios.
Initializing to $null
One habit that I have picked up is initializing all my variables before I use them. You are
required
to do this in other languages. At the top of my function or as I enter a foreach
loop, I define all
the values that I'm using.
Here is a scenario that I want you to take a close look at. It's an example of a bug I had
to chase
down before.
PowerShell
function Do-Something
try
catch
Update-Something $result
The expectation here is that Get-Something returns either a result or an empty $null . If
there
is an error, we log it. Then we check to make sure we got a valid result before
processing it.
The bug hiding in this code is when Get-Something throws an exception and doesn't
assign a value
to $result . It fails before the assignment so we don't even assign $null
to the $result
variable. $result still contains the previous valid $result from other
iterations.
Update-Something to execute multiple times on the same object in this
example.
I set $result to $null right inside the foreach loop before I use it to mitigate this issue.
PowerShell
$result = $null
try
...
Scope issues
This also helps mitigate scoping issues. In that example, we assign values to $result
over and
over in a loop. But because PowerShell allows variable values from outside the
function to bleed
into the scope of the current function, initializing them inside your
function mitigates bugs
that can be introduced that way.
An uninitialized variable in your function is not $null if it's set to a value in a parent
scope.
The parent scope could be another function that calls your function and uses the
same variable
names.
If I take that same Do-something example and remove the loop, I would end up with
something that
looks like this example:
PowerShell
function Invoke-Something
$result = 'ParentScope'
Do-Something
function Do-Something
try
catch
Update-Something $result
If the call to Get-Something throws an exception, then my $null check finds the $result
from
Invoke-Something . Initializing the value inside your function mitigates this issue.
Naming variables is hard and it's common for an author to use the same variable names
in multiple
functions. I know I use $node , $result , $data all the time. So it would be very
easy for values
from different scopes to show up in places where they should not be.
Out-Null
The Out-Null command is the built-in way to redirect pipeline data to $null .
PowerShell
Assign to $null
You can assign the results of a command to $null for the same effect as using Out-
Null .
PowerShell
Because $null is a constant value, you can never overwrite it. I don't like the way it
looks in my
code but it often performs faster than Out-Null .
Redirect to $null
You can also use the redirection operator to send output to $null .
PowerShell
If you're dealing with command-line executables that output on the different streams.
You can
redirect all output streams to $null like this:
PowerShell
Summary
I covered a lot of ground on this one and I know this article is more fragmented than
most of my
deep dives. That is because $null values can pop up in many different
places in PowerShell and all
the nuances are specific to where you find it. I hope you
walk away from this with a better
understanding of $null and an awareness of the more
obscure scenarios you may run into.
Everything you wanted to know about
ShouldProcess
Article • 11/17/2022
PowerShell functions have several features that greatly improve the way users interact
with them.
One important feature that is often overlooked is -WhatIf and -Confirm
support and it's easy to
add to your functions. In this article, we dive deep into how to
implement this feature.
7 Note
This is a simple feature you can enable in your functions to provide a safety net for the
users that
need it. There's nothing scarier than running a command that you know can
be dangerous for the
first time. The option to run it with -WhatIf can make a big
difference.
CommonParameters
Before we look at implementing these common parameters, I want to take a quick look
at how
they're used.
Using -WhatIf
When a command supports the -WhatIf parameter, it allows you to see what the
command would have
done instead of making changes. it's a good way to test out the
impact of a command, especially
before you do something destructive.
PowerShell
PS C:\temp> Get-ChildItem
Directory: C:\temp
If the command correctly implements ShouldProcess , it should show you all the changes
that it
would have made. Here is an example using a wildcard to delete multiple files.
PowerShell
Using -Confirm
Commands that support -WhatIf also support -Confirm . This gives you a chance
confirm an action
before performing it.
PowerShell
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
In this case, you have multiple options that allow you to continue, skip a change, or stop
the
script. The help prompt describes each of those options like this.
Output
S - Pause the current pipeline and return to the command prompt. Type "exit"
to resume the pipeline.
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
Localization
This prompt is localized in PowerShell so the language changes based on the language
of your
operating system. This is one more thing that PowerShell manages for you.
Switch parameters
Let's take quick moment to look at ways to pass a value to a switch parameter. The main
reason I
call this out is that you often want to pass parameter values to functions you
call.
The first approach is a specific parameter syntax that can be used for all parameters but
you mostly
see it used for switch parameters. You specify a colon to attach a value to
the parameter.
PowerShell
PowerShell
$DoWhatIf = $true
PowerShell
$RemoveSplat = @{
Path = '*'
WhatIf = $true
Remove-Item @RemoveSplat
SupportsShouldProcess
The first step to enable -WhatIf and -Confirm support is to specify
SupportsShouldProcess in
the CmdletBinding of your function.
PowerShell
function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
Remove-Item .\myfile1.txt
By specifying SupportsShouldProcess in this way, we can now call our function with -
WhatIf (or
-Confirm ).
PowerShell
PowerShell
function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
I will revisit the nuances much later once you have a better understanding of all the
pieces in
play.
$PSCmdlet.ShouldProcess
The method that allows you to implement SupportsShouldProcess is
$PSCmdlet.ShouldProcess . You
call $PSCmdlet.ShouldProcess(...) to see if you should
process some logic and PowerShell takes
care of the rest. Let's start with an example:
PowerShell
function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
if($PSCmdlet.ShouldProcess($file.Name)){
$file.Delete()
PowerShell
A call using -Confirm pauses the script and prompts the user with the option to
continue. It
returns $true if the user selected Y .
PowerShell
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
PowerShell
Overloads
There are a few different overloads for $PSCmdlet.ShouldProcess with different
parameters for
customizing the messaging. We already saw the first one in the example
above. Let's take a closer
look at it.
PowerShell
function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
if($PSCmdlet.ShouldProcess('TARGET')){
# ...
This produces output that includes both the function name and the target (value of the
parameter).
PowerShell
Specifying a second parameter as the operation uses the operation value instead of the
function
name in the message.
PowerShell
## $PSCmdlet.ShouldProcess('TARGET','OPERATION')
The next option is to specify three parameters to fully customize the message. When
three parameters
are used, the first one is the entire message. The second two
parameters are still used in the
-Confirm message output.
PowerShell
## $PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION')
PowerShell
## $PSCmdlet.ShouldProcess('TARGET')
## $PSCmdlet.ShouldProcess('TARGET','OPERATION')
## $PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION')
ShouldProcessReason
We have a fourth overload that's more advanced than the others. It allows you to get
the reason
ShouldProcess was executed. I'm only adding this here for completeness
because we can just check
if $WhatIfPreference is $true instead.
PowerShell
$reason = ''
if($PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION',[ref]$reason)){
$reason
We have to pass the $reason variable into the fourth parameter as a reference variable
with
[ref] . ShouldProcess populates $reason with the value None or WhatIf . I didn't
say this
was useful and I have had no reason to ever use it.
Where to place it
You use ShouldProcess to make your scripts safer. So you use it when your scripts are
making
changes. I like to place the $PSCmdlet.ShouldProcess call as close to the change
as possible.
PowerShell
## general logic and variable work
if ($PSCmdlet.ShouldProcess('TARGET','OPERATION')){
If I'm processing a collection of items, I call it for each item. So the call gets placed
inside
the foreach loop.
PowerShell
if ($PSCmdlet.ShouldProcess($node,'OPERATION')){
The reason why I place ShouldProcess tightly around the change, is that I want as much
code to
execute as possible when -WhatIf is specified. I want the setup and validation
to run if possible
so the user gets to see those errors.
I also like to use this in my Pester tests that validate my projects. If I have a piece of logic
that is hard to mock in pester, I can often wrap it in ShouldProcess and call it with -
WhatIf in
my tests. It's better to test some of your code than none of it.
$WhatIfPreference
The first preference variable we have is $WhatIfPreference . This is $false by default. If
you
set it to $true then your function executes as if you specified -WhatIf . If you set
this in
your session, all commands perform -WhatIf execution.
When you call a function with -WhatIf , the value of $WhatIfPreference gets set to
$true inside
the scope of your function.
ConfirmImpact
Most of my examples are for -WhatIf but everything so far also works with -Confirm to
prompt the
user. You can set the ConfirmImpact of the function to high and it prompts
the user as if it was
called with -Confirm .
PowerShell
function Test-ShouldProcess {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param()
if ($PSCmdlet.ShouldProcess('TARGET')){
This call to Test-ShouldProcess is performing the -Confirm action because of the High
impact.
PowerShell
PS> Test-ShouldProcess
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): y
Some Action
The obvious issue is that now it's harder to use in other scripts without prompting the
user. In
this case, we can pass a $false to -Confirm to suppress the prompt.
PowerShell
Some Action
$ConfirmPreference
$ConfirmPreference is an automatic variable that controls when ConfirmImpact asks you
to
confirm execution. Here are the possible values for both $ConfirmPreference and
ConfirmImpact .
High
Medium
Low
None
With these values, you can specify different levels of impact for each function. If you
have
$ConfirmPreference set to a value higher than ConfirmImpact , then you aren't
prompted to
confirm execution.
When calling a function with -Confirm , the value of $ConfirmPreference gets set to Low
inside
the scope of your function.
What I tend to do is specify -Confirm:$false on the commands that I call when I have
already
handled the prompting.
PowerShell
function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
if($PSCmdlet.ShouldProcess($file.Name)){
This brings us back to an earlier warning: There are nuances as to when -WhatIf is not
passed to a
function and when -Confirm passes to a function. I promise I'll get back to
this later.
$PSCmdlet.ShouldContinue
If you need more control than ShouldProcess provides, you can trigger the prompt
directly with
ShouldContinue . ShouldContinue ignores $ConfirmPreference ,
ConfirmImpact , -Confirm ,
$WhatIfPreference , and -WhatIf because it prompts every
PowerShell
function Test-ShouldContinue {
[CmdletBinding()]
param()
if($PSCmdlet.ShouldContinue('TARGET','OPERATION')){
PowerShell
Test-ShouldContinue
Second
TARGET
The biggest issue with ShouldContinue is that it requires the user to run it interactively
because
it always prompts the user. You should always be building tools that can be
used by other
scripts. The way you do this is by implementing -Force . I'll revisit this idea
later.
Yes to all
This is automatically handled with ShouldProcess but we have to do a little more work
for
ShouldContinue . There's a second method overload where we have to pass in a few
values by
reference to control the logic.
PowerShell
function Test-ShouldContinue {
[CmdletBinding()]
param()
$collection = 1..5
$yesToAll = $false
$noToAll = $false
foreach($target in $collection) {
$continue = $PSCmdlet.ShouldContinue(
"TARGET_$target",
'OPERATION',
[ref]$yesToAll,
[ref]$noToAll
if ($continue){
I added a foreach loop and a collection to show it in action. I pulled the ShouldContinue
call
out of the if statement to make it easier to read. Calling a method with four
parameters starts to
get a little ugly, but I tried to make it look as clean as I could.
Implementing -Force
ShouldProcess and ShouldContinue need to implement -Force in different ways. The
trick to
these implementations is that ShouldProcess should always get executed, but
ShouldContinue
should not get executed if -Force is specified.
ShouldProcess -Force
If you set your ConfirmImpact to high , the first thing your users are going to try is to
suppress it with -Force . That's the first thing I do anyway.
PowerShell
Test-ShouldProcess -Force
If you recall from the ConfirmImpact section, they actually need to call it like this:
PowerShell
Test-ShouldProcess -Confirm:$false
Not everyone realizes they need to do that and -Force doesn't suppress
ShouldContinue .
So we should implement -Force for the sanity of our users. Take a look
PowerShell
function Test-ShouldProcess {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param(
[Switch]$Force
$ConfirmPreference = 'None'
if ($PSCmdlet.ShouldProcess('TARGET')){
We add our own -Force switch as a parameter. The -Confirm parameter is automatically
added
when using SupportsShouldProcess in the CmdletBinding .
PowerShell
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param(
[Switch]$Force
PowerShell
if ($Force -and -not $Confirm){
$ConfirmPreference = 'None'
If the user specifies -Force , we want to suppress the confirm prompt unless they also
specify
-Confirm . This allows a user to force a change but still confirm the change. Then
we set
$ConfirmPreference in the local scope. Now, using the -Force parameter
temporarily sets the
$ConfirmPreference to none, disabling prompt for confirmation.
PowerShell
if ($PSCmdlet.ShouldProcess('TARGET')){
If someone specifies both -Force and -WhatIf , then -WhatIf needs to take priority. This
approach preserves -WhatIf processing because ShouldProcess always gets executed.
Do not add a check for the $Force value inside the if statement with the
ShouldProcess . That is
an anti-pattern for this specific scenario even though that's what I
ShouldContinue -Force
This is the correct way to implement -Force with ShouldContinue .
PowerShell
function Test-ShouldContinue {
[CmdletBinding()]
param(
[Switch]$Force
By placing the $Force to the left of the -or operator, it gets evaluated first. Writing it
this way short circuits the execution of the if statement. If $force is $true , then the
ShouldContinue is not executed.
PowerShell
Some Action
We don't have to worry about -Confirm or -WhatIf in this scenario because they're not
supported
by ShouldContinue . This is why it needs to be handled differently than
ShouldProcess .
Scope issues
Using -WhatIf and -Confirm are supposed to apply to everything inside your functions
and
everything they call. They do this by setting $WhatIfPreference to $true or setting
$ConfirmPreference to Low in the local scope of the function. When you call another
function,
calls to ShouldProcess use those values.
This actually works correctly most of the time. Anytime you call built-in cmdlet or a
function in
your same scope, it works. It also works when you call a script or a function
in a script module
from the console.
The one specific place where it doesn't work is when a script or a script module calls a
function in
another script module. This may not sound like a big problem, but most of
the modules you create or
pull from the PSGallery are script modules.
The core issue is that script modules do not inherit the values for $WhatIfPreference or
$ConfirmPreference (and several others) when called from functions in other script
modules.
The best way to summarize this as a general rule is that this works correctly for binary
modules and
never trust it to work for script modules. If you aren't sure, either test it or
just assume it
doesn't work correctly.
I personally feel this is very dangerous because it creates scenarios where you add -
WhatIf
support to multiple modules that work correctly in isolation, but fail to work
In closing
I have to look up how to use ShouldProcess every time I need to use it. It took me a
long time to
distinguish ShouldProcess from ShouldContinue . I almost always need to
look up what parameters
to use. So don't worry if you still get confused from time to
time. This article will be here when
you need it. I'm sure I will reference it often myself.
If you liked this post, please share your thoughts with me on Twitter using the link
below. I always
like hearing from people that get value from my content.
Writing Progress across multiple threads
with Foreach Parallel
Article • 11/17/2022
Set up
One of the downsides to this approach is it takes a, somewhat, complex set up to ensure
everything
runs without error.
PowerShell
$dataset = @(
@{
Id = 1
@{
Id = 2
@{
Id = 3
@{
Id = 4
@{
Id = 5
$origin = @{}
$sync = [System.Collections.Hashtable]::Synchronized($origin)
This section creates three different data structures, for three different purposes.
The $dataSet variable stores an array of hashtables that is used to coordinate the next
steps
without the risk of being modified. If an object collection is modified while
iterating through the
collection, PowerShell throws an error. You must keep the object
collection in the loop separate
from the objects being modified. The Id key in each
hashtable is the identifier for a mock
process. The Wait key simulates the workload of
each mock process being tracked.
The $origin variable stores a nested hashtable with each key being one of the mock
process id's.
Then, it is used to hydrate the synchronized hashtable stored in the $sync
variable. The $sync
variable is responsible for reporting the progress back to the parent
runspace, which displays the
progress.
PowerShell
$syncCopy = $using:sync
$process = $syncCopy.$($PSItem.Id)
$process.Id = $PSItem.Id
$process.Status = "Processing"
$process.Completed = $true
The mock processes are sent to Foreach-Object and started as jobs. The ThrottleLimit is
set to
3 to highlight running multiple processes in a queue. The jobs are stored in the
$job variable
and allows us to know when all the processes have finished later on.
When using the using: statement to reference a parent scope variable in PowerShell,
you can't use
expressions to make it dynamic. For example, if you tried to create the
$process variable like
this, $process = $using:sync.$($PSItem.id) , you would get an
error stating you can't use
expressions there. So, we create the $syncCopy variable to be
able to reference and modify the
$sync variable without the risk of it failing.
Next, we build out a hashtable to represent the progress of the process currently in the
loop using
the $process variable by referencing the synchronized hashtable keys. The
Activity and the
Status keys are used as parameter values for Write-Progress to display
the status of a given
mock process in the next section.
The foreach loop is just a way to simulate the process working and is randomized based
on the
$dataSet Wait attribute to set Start-Sleep using milliseconds. How you
calculate the
progress of your process may vary.
PowerShell
$sync.Keys | Foreach-Object {
if(![string]::IsNullOrEmpty($sync.$_.keys))
$param = $sync.$_
# Execute Write-Progress
Write-Progress @param
The $job variable contains the parent job and has a child job for each of the mock
processes. While any of the child jobs are still running, the parent job State will remain
"Running". This allows us to use the while loop to continually update the progress of
every process until all processes are finished.
Within the while loop, we loop through each of the keys in the $sync variable. Since this
is
a synchronized hashtable, it is constantly updated but can still be accessed without
throwing any
errors.
There is a check to ensure that the process being reported is actually running using the
IsNullOrEmpty() method. If the process hasn't been started, the loop won't report on it
and move
on to the next until it gets to a process that has been started. If the process is
started, the
hashtable from the current key is used to splat the parameters to Write-
Progress .
Full example
PowerShell
# Example workload
$dataset = @(
@{
Id = 1
@{
Id = 2
@{
Id = 3
@{
Id = 4
@{
Id = 5
$origin = @{}
$sync = [System.Collections.Hashtable]::Synchronized($origin)
$syncCopy = $using:sync
$process = $syncCopy.$($PSItem.Id)
$process.Id = $PSItem.Id
$process.Status = "Processing"
$process.Completed = $true
$sync.Keys | Foreach-Object {
if(![string]::IsNullOrEmpty($sync.$_.keys))
$param = $sync.$_
# Execute Write-Progress
Write-Progress @param
Related Links
about_Jobs
about_Scopes
about_Splatting
Add Credential support to PowerShell
functions
Article • 11/17/2022
7 Note
This article shows you how to add credential parameters to PowerShell functions and
why you'd want
to. A credential parameter is to allow you to run the function or cmdlet
as a different user. The
most common use is to run the function or cmdlet as an
elevated user account.
For example, the cmdlet New-ADUser has a Credential parameter, which you could
provide domain
admin credentials to create an account in a domain. Assuming your
normal account running the
PowerShell session doesn't have that access already.
To specify the domain name and username ahead of time you can use either the
Credential or
UserName parameters. When you use the UserName parameter, you're
also required to provide a
Message value. The code below demonstrates using the
cmdlet. You can also store the credential
object in a variable so that you can use the
credential multiple times. In the example below, the
credential object is stored in the
variable $Cred .
PowerShell
$Cred = Get-Credential
Sometimes, you can't use the interactive method of creating credential objects shown in
the previous
example. Most automation tools require a non-interactive method. To
create a credential without user
interaction, create a secure string containing the
password. Then pass the secure string and user
name to the
System.Management.Automation.PSCredential() method.
Use the following command to create a secure string containing the password:
PowerShell
Both the AsPlainText and Force parameters are required. Without those parameters, you
receive a message warning that you shouldn't pass plain text into a secure string.
PowerShell
returns this warning because the plain text password gets recorded in
various logs. Once you have a
secure string created, you need to pass it to the
PSCredential() method to create the credential
object. In the following example, the
variable $password contains the secure string $Cred
contains the credential object.
PowerShell
Now that you know how to create credential objects, you can add credential parameters
to your
PowerShell functions.
The following example shows the parameter block for a function called Get-Something . It
has two
parameters: $Name and $Credential .
PowerShell
function Get-Something {
param(
$Name,
[System.Management.Automation.PSCredential]$Credential
The code in this example is enough to have a working credential parameter, however
there are a few
things you can add to make it more robust.
Add the [ValidateNotNull()] validation attribute to check that the value being
passed to
Credential. If the parameter value is null, this attribute prevents the
function from
executing with invalid credentials.
passing this
$Credential object to existing PowerShell cmdlets. Providing a null
value to the cmdlet called
inside your function causes an error. Providing an empty
credential object avoids this error.
Tip
PowerShell
function Set-RemoteRegistryValue {
param(
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
} -Credential $Credential
about_Splatting article.
PowerShell
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
Using (Get-Credential) seems cumbersome. Normally, when you use the Credential
parameter with
only a username, the cmdlet automatically prompts for the password.
The
[System.Management.Automation.Credential()] attribute enables this behavior.
PowerShell
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
7 Note
To set the registry value shown, these examples assume you have the Web Server
features of
Windows installed. Run Install-WindowsFeature Web-Server and
Install-WindowsFeature web-mgmt-tools if required.
This example uses the .NET method to create the credential object and a secure string to
pass in the
password.
PowerShell
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
For this example, the secure string is created using a clear text password. All of the
previously mentioned CI/CD have a secure method of providing that password at run
time. When using
those tools, replace the plain text password with the variable defined
within the CI/CD tool you
use.
PowerShell
$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
Set-RemoteRegistryValue @remoteKeyParams
PowerShell
function Set-RemoteRegistryValue {
param(
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
} else {
Invoke-Command -ComputerName:$ComputerName {
PowerShell
function Set-RemoteRegistryValue {
param(
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
$Splat = @{
ComputerName = $ComputerName
if ($Credential -ne
[System.Management.Automation.PSCredential]::Empty) {
$Splat['Credential'] = $Credential
} @splat
The user name is available from the UserName property of the $Credential variable. To
obtain
the password, you have to use the GetNetworkCredential() method of the
$Credential object. The
values are extracted into variables that are added to a hash
PowerShell
function Get-AllSQLDatabases {
param(
$SQLServer,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
$UserName = $Credential.UserName
$Password = $Credential.GetNetworkCredential().Password
$splat = @{
UserName = $UserName
Password = $Password
ServerInstance = 'SQLServer'
Invoke-Sqlcmd @splat
$credSplat = @{
TypeName = 'System.Management.Automation.PSCredential'
BetterCredentials
Azure Key Vault
Vault Project
SecretManagement module
Avoid assigning variables in expressions
Article • 11/17/2022
PowerShell
# In an `if` conditional
# Property access
7 Note
While this syntax is allowed, its use is discouraged. There are cases where this does
not work and
the intent of the code author can be confusing to other code
reviewers.
Limitations
The assignment case doesn't always work. When it doesn't work, the assignment is
discarded. If you
create an instance of a mutable value type and attempt to both save
the instance in a variable and
modify one of its properties in the same expression, the
property assignment is discarded.
PowerShell
PS> $var.x
The difference is that you can't return a reference to the value. Essentially,
($var =
[Foo]::new()) is equivalent to $($var = [Foo]::new(); $var) . You're no longer
performing
a member access on the variable you're performing a member access on the
variable's output, which is
a copy.
The workaround is to create the instance and save it in a variable first, and then assign
to the
property via the variable:
PowerShell
PS> $var.x = 1
PS> $var.x
The Invoke-Expression cmdlet should only be used as a last resort. In most scenarios,
safer and
more robust alternatives are available. Forums like Stack Overflow are filled
with examples of
Invoke-Expression misuse. Also note that PSScriptAnalyzer has a rule
for this. For more
information, see
AvoidUsingInvokeExpression.
Carefully consider the security implications. When a string from an untrusted source
such as user
input is passed directly to Invoke-Expression , arbitrary commands can be
executed. Always consider
a different, more robust and secure solution first.
Common scenarios
Consider the following usage scenarios:
PowerShell
These cases are trivially avoidable. The script or code already exists in file or AST
form, so you
should write a script with parameters and invoke it directly instead of
using Invoke-Expression
on a string.
Running a script from a trusted source. For example, running the install script
from the
PowerShell repository:
PowerShell
You should only use this interactively. And, while this does make life simpler, this
practice
should be discouraged.
Testing for parsing errors. The PowerShell team tests for parse errors in the source
code
using Invoke-Expression because that's the only way to turn a parse-time
error into a runtime
one.
Conclusion
Most other scripting languages have a way to evaluate a string as code, and as an
interpreted
language, PowerShell must have a way to dynamically run itself. But there's
no good reason to use
Invoke-Expression in a production environment.
References
Stack Overflow discussion -
In what scenario was Invoke-Expression designed to be
used?
PowerShell Blog post -
Invoke-Expression Considered Harmful
Limitations of PowerShell transcripts
Article • 11/17/2022
Mixing Write-Host output with the output objects, strings, and PowerShell transcription
is
complicated. There is a subtle interaction between the script and how transcription
works with
PowerShell pipelines that can have unexpected results.
When you emit objects from your script the formatting of those objects is handled by
Out-Default .
But the formatting can occur after the script has completed and
PowerShell
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
Stop-Transcript
PS> ./scenario1.ps1
Path
----
/Users/user1/src/projects/transcript
The output to the console shows the output you expect, but not in the order you expect
it.
Write-Host 4 is visible before Get-Location because Write-Host is optimized to write
directly
to the host. There's code in transcription that copies the output to the transcript
file and the
console. Then we have the regular output of Get-Location and Write-Output
5 sent as output of
the script.
PowerShell
**********************
**********************
**********************
**********************
Since transcription is turned off before the script exits, it's not rendered in the transcript.
The
objects were sent to the next consumer in the pipeline. In this case, it's Out-Default ,
which
PowerShell inserted automatically. To complicate things further, the output of
strings is also
optimized in the formatting system. The first Write-Output 2 gets emitted
and captured by the
transcript. But the insertion of the Get-Location object causes its
output to be pushed into the
stack of things that need actual formatting, which sets a
bit of state for any remaining objects
that also may need formatting. This is why the
second Write-Output 5 doesn't get added to the
transcript.
PowerShell
Get-Location
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
Stop-Transcript
PS> ./scenario2.ps1
Path
----
/Users/user1/src/projects/transcript
We can see that the Write-Host commands happen before anything, and then the
objects start to come
out. The Write-Output of a string forces the object to be rendered
to the screen, but notice that
the transcript contains only the output of Write-Host .
That's because those string objects are
piped to Out-Default for formatting after the
script turned off transcription.
PowerShell
**********************
**********************
**********************
**********************
PowerShell
PS> Get-Content scenario3.ps1
Write-Host '1'
Write-Output '2'
Write-Host '4'
Write-Output '5'
Get-Location
Stop-Transcript
PS> ./scenario3.ps1
Path
----
/Users/user1/src/projects/transcript
The string output from both Write-Host and Write-Object makes it into the transcript.
However,
the output from Get-Location occurs after transcription has stopped.
**********************
**********************
**********************
**********************
. {
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
} | Out-Default
Stop-Transcript
PS> ./scenario4.ps1
Path
----
/Users/user1/src/projects/transcript
Notice that the last Write-Host call is still out of order, that's because of the
optimization in Write-Host that doesn't go into the output stream.
PowerShell
**********************
**********************
Path
----
/Users/user1/src/projects/transcript
**********************
**********************
c HOW-TO GUIDE
Sorting objects
Managing computers
c HOW-TO GUIDE
c HOW-TO GUIDE
Managing services
ki ih i
Working with printers
p CONCEPT
Redirecting output
c HOW-TO GUIDE
Creating UI elements
c HOW-TO GUIDE
Because objects play such a central role in PowerShell, there are several native
commands designed
to work with arbitrary object types. The most important one is the
Get-Member command.
The simplest technique for analyzing the objects that a command returns is to pipe the
output of
that command to the Get-Member cmdlet. The Get-Member cmdlet shows you
the formal name of the
object type and a complete listing of its members. The number
of elements that are returned can
sometimes be overwhelming. For example, a process
object can have over 100 members.
The following command allows you to see all the members of a Process object and page
through the
output.
PowerShell
Output
TypeName: System.Diagnostics.Process
PM AliasProperty PM = PagedMemorySize
VM AliasProperty VM = VirtualMemorySize
WS AliasProperty WS = WorkingSet
...
We can make this long list of information more usable by filtering for elements we want
to see. The
Get-Member command lets you list only members that are properties. There
are several forms of
properties. The cmdlet displays properties of a type using the
MemberType parameter with the
value Properties . The resulting list is still very long,
but a more manageable:
PowerShell
Get-Process | Get-Member -MemberType Properties
Output
TypeName: System.Diagnostics.Process
...
...
...
...
...
7 Note
There are more than 60 properties for a process. By default, PowerShell determines how
to display an
object type using information stored in XML files that have names ending
in .format.ps1xml . The
formatting definition for process objects is stored in
DotNetTypes.format.ps1xml .
If you need to look at properties other than those that PowerShell displays by default,
you can
format the output using the Format-* cmdlets.
Selecting parts of objects
Article • 12/09/2022
You can use the Select-Object cmdlet to create new, custom PowerShell objects that
contain
properties selected from the objects you use to create them. Type the following
command to create a
new object that includes only the Name and FreeSpace properties
of the Win32_LogicalDisk
WMI class:
PowerShell
Output
Name FreeSpace
---- ---------
C: 50664845312
PowerShell
label='FreeSpace'
expression={($_.FreeSpace/1GB).ToString('F2')}
Output
Name FreeSpace
---- ---------
C: 47.18
In PowerShell, you often generate and pass along more objects to a pipeline than you
want. You can
specify the properties of particular objects to display using the Format-*
cmdlets, but this
doesn't help with the problem of removing entire objects from the
display. You may want to filter
objects before the end of a pipeline, so you can perform
actions on only a subset of the initially
generated objects.
PowerShell includes a Where-Object cmdlet that allows you to test each object in the
pipeline and
only pass it along the pipeline if it meets a particular test condition. Objects
that don't pass the
test are removed from the pipeline. You supply the test condition as
the value of the
FilterScript parameter.
7 Note
Due to parsing considerations, symbols such as < , > , and = aren't used as comparison
operators. Instead, comparison operators are comprised of letters. The basic comparison
operators
are listed in the following table.
-notlike isn't like (wildcard comparison for text) "file.doc" -notlike "p*.doc"
Where-Object script blocks use the special variable $_ to refer to the current object in
the
pipeline. Here is an example of how it works. If you have a list of numbers, and only
want to return
the ones that are less than 3, you can use Where-Object to filter the
numbers by typing:
PowerShell
This still produces a long list. You may want to filter to only select the drivers set to start
automatically by testing the StartMode value as well:
PowerShell
Get-CimInstance -Class Win32_SystemDriver |
Output
Name : AsyncMac
State : Running
Status : OK
Started : True
Name : audstub
State : Running
Status : OK
Started : True
...
This gives us a lot of information we no longer need because we know that the drivers
are running.
In fact, the only information we probably need at this point are the name
and the display name. The
following command includes only those two properties,
resulting in much simpler output:
PowerShell
Output
Name DisplayName
---- -----------
bowser Browser
igfx igfx
...
There are two Where-Object elements in the above command, but they can be
expressed in a single
Where-Object element using the -and logical operator, like this:
PowerShell
-and Logical and; true if both sides are true (1 -eq 1) -and (2 -eq 2)
-or Logical or; true if either side is true (1 -eq 1) -or (1 -eq 2)
We can organize displayed data to make it easier to scan using the Sort-Object cmdlet.
Sort-Object takes the name of one or more properties to sort on, and returns data
sorted by the
values of those properties.
Basic sorting
Consider the problem of listing subdirectories and files in the current directory. If we
want to
sort by LastWriteTime and then by Name, we can do it by typing:
PowerShell
Get-ChildItem |
Output
LastWriteTime Name
------------- ----
...
You can also sort the objects in reverse order by specifying the Descending switch
parameter.
PowerShell
Get-ChildItem |
Output
LastWriteTime Name
------------- ----
...
The following example sorts objects in descending LastWriteTime order and ascending
Name
order.
PowerShell
Get-ChildItem |
Output
LastWriteTime Name
------------- ----
...
You can also set a scriptblock to the Expression key. When running the Sort-Object
cmdlet, the
scriptblock is executed and the result is used for sorting.
The following example sorts objects in descending order by the time span between
CreationTime
and LastWriteTime.
PowerShell
Get-ChildItem |
Output
LastWriteTime CreationTime
------------- ------------
...
Tips
You can omit the Property parameter name as following:
PowerShell
PowerShell
The keys in the hash tables for sorting can be abbreviated as following:
PowerShell
Sort-Object @{ e = 'LastWriteTime'; d = $true }, @{ e = 'Name'; a = $true }
In this example, the e stands for Expression, the d stands for Descending, and the
a
stands for Ascending.
To improve readability, you can place the hash tables into a separate variable:
PowerShell
$order = @(
Get-ChildItem |
Sort-Object $order |
There are software components with .NET Framework and COM interfaces that enable
you to perform many
system administration tasks. PowerShell lets you use these
components, so you aren't limited
to the tasks that can be performed by using cmdlets.
Many of the cmdlets in the initial release of
PowerShell don't work against remote
computers. We will demonstrate how to get around this
limitation when managing
event logs by using the .NET Framework System.Diagnostics.EventLog
class directly
from PowerShell.
PowerShell
Output
Although the command has created an instance of the EventLog class, the instance
doesn't include any
data. that's because we didn't specify a particular event log. How do
you get a real event log?
PowerShell
Output
7 Note
Since most of the .NET classes are contained in the System namespace, PowerShell
automatically
attempts to find classes you specify in the System namespace if it
can't find a match for the
typename you specify. This means that you can specify
Diagnostics.EventLog instead of
System.Diagnostics.EventLog .
The output from any valid PowerShell command can be stored in a variable. Variable
names always
begin with $ . If you want to store the Application log reference in a
variable named $AppLog ,
type the name of the variable, followed by an equal sign and
then type the command used to create
the Application log object:
PowerShell
If you then type $AppLog , you can see that it contains the Application log:
PowerShell
$AppLog
Output
PowerShell
$RemoteAppLog
Output
Now that we have a reference to an event log stored in the $RemoteAppLog variable, what
tasks can
we perform on it?
PowerShell
Output
TypeName: System.Diagnostics.EventLog
...
...
...
...
The Clear() method can be used to clear the event log. When calling a method, you
must always
follow the method name by parentheses, even if the method doesn't
require arguments. This lets
PowerShell distinguish between the method and a potential
property with the same name. Type
the following to call the Clear method:
PowerShell
$RemoteAppLog.Clear()
$RemoteAppLog
Output
Notice that the event log was cleared and now has 0 entries instead of 262.
You can create the WSH objects by specifying these progids: WScript.Shell,
WScript.Network,
Scripting.Dictionary, and Scripting.FileSystemObject. The following
commands create these
objects:
PowerShell
Although most of the functionality of these classes is made available in other ways in
Windows
PowerShell, a few tasks such as shortcut creation are still easier to do using the
WSH classes.
PowerShell
Get-Member works with COM objects, so you can explore the members of the object by
typing:
PowerShell
$WshShell | Get-Member
Output
TypeName: System.__ComObject#{41904400-be18-11d3-a28b-00104bd35090}
...
Get-Member has an optional InputObject parameter you can use instead of piping to
provide
input to Get-Member . You would get the same output as shown above if you
instead used the command
Get-Member -InputObject $WshShell. If you use
InputObject, it treats its argument as a
single item. This means that if you have several
objects in a variable, Get-Member treats them as
an array of objects. For example:
PowerShell
$a = 1,2,"three"
Get-Member -InputObject $a
Output
TypeName: System.Object[]
...
The WScript.Shell CreateShortcut method accepts a single argument, the path to the
shortcut file
to create. We could type in the full path to the desktop, but there is an
easier way. The desktop is
normally represented by a folder named Desktop inside the
home folder of the current user. Windows
PowerShell has a variable $HOME that contains
the path to this folder. We can specify the path to
the home folder by using this variable,
and then add the name of the Desktop folder and the name for
the shortcut to create
by typing:
PowerShell
$lnk = $WshShell.CreateShortcut("$HOME\Desktop\PSHome.lnk")
When you use something that looks like a variable name inside double-quotes,
PowerShell tries to
substitute a matching value. If you use single-quotes, PowerShell
doesn't try to substitute the
variable value. For example, try typing the following
commands:
PowerShell
"$HOME\Desktop\PSHome.lnk"
Output
PowerShell
'$HOME\Desktop\PSHome.lnk'
Output
$HOME\Desktop\PSHome.lnk
We now have a variable named $lnk that contains a new shortcut reference. If you want
to see its
members, you can pipe it to Get-Member . The output below shows the
members we need to use to
finish creating our shortcut:
PowerShell
$lnk | Get-Member
Output
TypeName: System.__ComObject#{f935dc23-1cf0-11d0-adb9-00c04fd58a0b}
...
...
We need to specify the TargetPath, which is the application folder for PowerShell, and
then save
the shortcut by calling the Save method. The PowerShell application folder
path is stored in the
variable $PSHome , so we can do this by typing:
PowerShell
$lnk.TargetPath = $PSHome
$lnk.Save()
You create an Internet Explorer instance by specifying the Internet Explorer ProgId,
InternetExplorer.Application:
PowerShell
This command starts Internet Explorer, but doesn't make it visible. If you type Get-
Process , you can
see that a process named iexplore is running. In fact, if you exit
PowerShell, the process will
continue to run. You must reboot the computer or use a
tool like Task Manager to end the iexplore
process.
7 Note
COM objects that start as separate processes, commonly called ActiveX executables,
may or may
not display a user interface window when they start up. If they create a
window but don't make it
visible, like Internet Explorer, the focus usually moves to
the Windows desktop. You must make the
window visible to interact with it.
By typing $ie | Get-Member , you can view properties and methods for Internet Explorer.
To see the
Internet Explorer window, set the Visible property to $true by typing:
PowerShell
$ie.Visible = $true
You can then navigate to a specific Web address using the Navigate method:
PowerShell
$ie.Navigate("https://devblogs.microsoft.com/scripting/")
Using other members of the Internet Explorer object model, it's possible to retrieve text
content
from the Web page. The following command displays the HTML text in the body
of the current Web
page:
PowerShell
$ie.Document.Body.InnerText
To close Internet Explorer from within PowerShell, call its Quit() method:
PowerShell
$ie.Quit()
The $ie variable no longer contains a valid reference even though it still appears to be a
COM
object. If you attempt to use it, PowerShell returns an automation error:
PowerShell
$ie | Get-Member
Output
cation" : "The object invoked has disconnected from its clients. (Exception
fro
At line:1 char:16
You can either remove the remaining reference with a command like $ie = $null , or
completely
remove the variable by typing:
PowerShell
Remove-Variable ie
7 Note
PowerShell
Output
this type exposes different members than the IDispatch members , scripts
written to work with this
object might not work if the primary interop assembly isn't installed. At
line:1 char:17 + $xl =
Although the object is still created, you are warned that it isn't a standard COM object.
Using static classes and methods
Article • 12/09/2022
Not all .NET Framework classes can be created using New-Object . For example, if you try
to
create a System.Environment or a System.Math object with New-Object , you will get
the
following error messages:
PowerShell
New-Object System.Environment
Output
type System.Environment.
At line:1 char:11
PowerShell
New-Object System.Math
Output
type System.Math.
At line:1 char:11
These errors occur because there is no way to create a new object from these classes.
These classes
are reference libraries of methods and properties that don't change state.
You don't need to create
them, you simply use them. Classes and methods such as these
are called static classes because
they're not created, destroyed, or changed. To make this
clear we will provide examples that use
static classes.
PowerShell
[System.Environment]
Output
7 Note
PowerShell
[System.Environment] | Get-Member
Output
TypeName: System.RuntimeType
PowerShell
Output
TypeName: System.Environment
...
TickCount ExitCode
PowerShell
[System.Environment]::Commandline
Output
To check the operating system version, display the OSVersion property by typing:
PowerShell
[System.Environment]::OSVersion
Output
We can check whether the computer is in the process of shutting down by displaying
the
HasShutdownStarted property:
PowerShell
[System.Environment]::HasShutdownStarted
Output
False
System.Math has several methods with the same name, but they're distinguished
by the type of
their parameters.
Type the following command to list the methods of the System.Math class.
PowerShell
Output
TypeName: System.Math
PowerShell
[System.Math]::Sqrt(9)
[System.Math]::Pow(2,3)
[System.Math]::Floor(3.3)
[System.Math]::Floor(-3.3)
-4
[System.Math]::Ceiling(3.3)
[System.Math]::Ceiling(-3.3)
-3
[System.Math]::Max(2,7)
[System.Math]::Min(2,7)
[System.Math]::Truncate(9.3)
[System.Math]::Truncate(-9.3)
-9
Get-CimClass addresses this problem by making WMI discoverable. You can get a list of
the WMI
classes available on the local computer by typing:
PowerShell
Select-Object CimClassName
Output
CimClassName
------------
Win32_DeviceChangeEvent
Win32_SystemConfigurationChangeEvent
Win32_VolumeChangeEvent
Win32_SystemTrace
Win32_ProcessTrace
Win32_ProcessStartTrace
Win32_ProcessStopTrace
Win32_ThreadTrace
Win32_ThreadStartTrace
Win32_ThreadStopTrace
...
You can retrieve the same information from a remote computer using the
ComputerName parameter,
specifying a computer name or IP address:
PowerShell
The class listing returned by remote computers may vary due to the specific operating
system the
computer is running and the particular WMI extensions added by installed
applications.
7 Note
When using CIM cmdlets to connect to a remote computer, the remote computer
must be running WMI
and the account you are using must be in the local
administrators group on the remote computer.
The remote system doesn't need to
have PowerShell installed. This allows you to administer
operating systems that
aren't running PowerShell, but do have WMI available.
PowerShell
Output
Although we're showing all of the parameters, the command can be expressed in a
more succinct way.
The ComputerName parameter isn't necessary when connecting to
the local system. We show it to
demonstrate the most general case and remind you
about the parameter. The Namespace defaults to
root/CIMV2 , and can be omitted as
well. Finally, most cmdlets allow you to omit the name of common
parameters. With
Get-CimInstance , if no name is specified for the first parameter, PowerShell
treats it as
the Class parameter. This means the last command could have been issued by typing:
PowerShell
Get-CimInstance Win32_OperatingSystem
The Win32_OperatingSystem class has many more properties than those displayed
here. You can use
Get-Member to see all the properties. The properties of a WMI class
are automatically available like
other object properties:
PowerShell
Output
TypeName:
Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_OperatingSy
stem
...
PowerShell
Output
7 Note
Wildcards work with property names in Format-Table , so the final pipeline element
can be
reduced to Format-Table -Property Total*Memory*, Free*
The memory data might be more readable if you format it as a list by typing:
PowerShell
Output
TotalVirtualMemorySize : 33449088
TotalVisibleMemorySize : 16671872
FreePhysicalMemory : 6524456
FreeSpaceInPagingFiles : 16285808
FreeVirtualMemory : 18393668
Name : Microsoft Windows 10
Pro|C:\WINDOWS|\Device\Harddisk0\Partition2
The elements that you see in PowerShell drives, such as the files and folders or registry
keys, are
called Items in PowerShell. The cmdlets for working with them item have the
noun Item in
their names.
The output of the Get-Command -Noun Item command shows that there are nine
PowerShell item
cmdlets.
PowerShell
Output
PowerShell
Output
Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp
To create a file, change the value of the ItemType parameter to file . For example, to
create a
file named file1.txt in the New.Directory directory, type:
PowerShell
Output
Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp\New.Directory
You can use the same technique to create a new registry key. In fact, a registry key is
easier to
create because the only item type in the Windows registry is a key. (Registry
entries are item
properties.) For example, to create a key named _Test in the
CurrentVersion subkey, type:
PowerShell
Output
Hive:
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wi
ndows\CurrentVersion
0 0 _Test {}
When typing a registry path, be sure to include the colon ( : ) in the PowerShell drive
names,
HKLM: and HKCU: . Without the colon, PowerShell doesn't recognize the drive
name in the path.
several registry entries that represent applications that run when the system
starts.
However, when you use Get-ChildItem to look for child items in the key, all you will see
is the
OptionalComponents subkey of the key:
PowerShell
Get-ChildItem HKLM:\Software\Microsoft\Windows\CurrentVersion\Run
Output
Hive:
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Wi
ndows\CurrentVersion\Run
3 0 OptionalComponents {}
Although it would be convenient to treat registry entries as items, you can't specify a
path to a
registry entry in a way that ensures that it's unique. The path notation doesn't
distinguish between
the registry subkey named Run and the (Default) registry entry in
the Run subkey.
Furthermore, because registry entry names can contain the backslash
character ( \ ), if registry
entries were items, then you couldn't use the path notation to
distinguish a registry entry named
Windows\CurrentVersion\Run from the subkey that's
located in that path.
Renaming existing items
To change the name of a file or folder, use the Rename-Item cmdlet. The following
command changes
the name of the file1.txt file to fileOne.txt .
PowerShell
The Rename-Item cmdlet can change the name of a file or a folder, but it can't move an
item. The
following command fails because it attempts to move the file from the
New.Directory directory to
the Temp directory.
PowerShell
Output
At line:1 char:12
Moving items
To move a file or folder, use the Move-Item cmdlet.
For example, the following command moves the New.Directory directory from the
C:\temp directory to
the root of the C: drive. To verify that the item was moved, include
PowerShell
Output
Directory: Microsoft.PowerShell.Core\FileSystem::C:\
Copying items
If you are familiar with the copy operations in other shells, you might find the behavior
of the
Copy-Item cmdlet in PowerShell to be unusual. When you copy an item from one
location to another,
Copy-Item doesn't copy its contents by default.
For example, if you copy the New.Directory directory from the C: drive to the C:\temp
directory,
the command succeeds, but the files in the New.Directory directory aren't
copied.
PowerShell
If you display the contents of C:\temp\New.Directory , you will find that it contains no
files:
PS>
Why doesn't the Copy-Item cmdlet copy the contents to the new location?
The Copy-Item cmdlet was designed to be generic; it isn't just for copying files and
folders.
Also, even when copying files and folders, you might want to copy only the
container and not the
items within it.
To copy all of the contents of a folder, include the Recurse parameter of the Copy-Item
cmdlet
in the command. If you have already copied the directory without its contents,
add the Force
parameter, which allows you to overwrite the empty folder.
PowerShell
Output
Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp
Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp\New.Directory
Deleting items
To delete files and folders, use the Remove-Item cmdlet. PowerShell cmdlets, such as
Remove-Item , that can make significant, irreversible changes will often prompt for
confirmation
when you enter its commands. For example, if you try to remove the
New.Directory folder, you will
be prompted to confirm the command, because the
PowerShell
Remove-Item C:\temp\New.Directory
Output
Confirm
specified. If you continue, all children will be removed with the item. Are
you
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
Because Yes is the default response, to delete the folder and its files, press the
Enter
key. To remove the folder without confirming, use the Recurse parameter.
PowerShell
Executing items
PowerShell uses the Invoke-Item cmdlet to perform a default action for a file or folder.
This
default action is determined by the default application handler in the registry; the
effect is the
same as if you double-click the item in File Explorer.
PowerShell
Invoke-Item C:\WINDOWS
An Explorer window that's located in C:\Windows appears, just as if you had double-
clicked the
C:\Windows folder.
PowerShell
Invoke-Item C:\boot.ini
If the .ini file type is associated with Notepad, the boot.ini file opens in Notepad.
Changing computer state
Article • 12/09/2022
Locking a computer
The only way to lock a computer directly with the standard available tools is to call the
LockWorkstation() function in user32.dll:
PowerShell
rundll32.exe user32.dll,LockWorkStation
This command immediately locks the workstation. It uses rundll32.exe to call the
LockWorkStation function in user32.dll .
When you lock a workstation while Fast User Switching is enabled, such as on Windows
XP, the
computer displays the user logon screen rather than starting the current user's
screensaver.
To shut down particular sessions on a Terminal Server, use the tsshutdn.exe command-
line tool.
You can also use the shutdown.exe tool with its logoff option:
PowerShell
shutdown.exe -l
For more information, see the Shutdown method of the Win32_OperatingSystem class.
PowerShell
You can also perform shutdown and restart operations directly from PowerShell.
PowerShell
Stop-Computer
PowerShell
Restart-Computer
PowerShell
Restart-Computer -Force
Cmdlets from CimCmdlets module are the most important cmdlets for general system
management
tasks. All critical subsystem settings are exposed through WMI.
Furthermore, WMI treats data as
objects that are in collections of one or more items.
Because PowerShell also works with objects and
has a pipeline that allows you to treat
single or multiple objects in the same way, generic WMI
access allows you to perform
some advanced tasks with very little work.
PowerShell
This returns information for all desktops, whether they're in use or not.
7 Note
Information returned by some WMI classes can be very detailed, and often include
metadata about
the WMI class.
Because most of these metadata properties have names that begin with Cim, you can
filter the
properties using Select-Object . Specify the -ExcludeProperty parameter with
"Cim*" as the
value. For example:
PowerShell
To filter out the metadata, use a pipeline operator (|) to send the results of the Get-
CimInstance
command to Select-Object -ExcludeProperty "CIM*" .
Listing BIOS Information
The WMI Win32_BIOS class returns fairly compact and complete information about the
system BIOS
on the local computer:
PowerShell
PowerShell
For a generic description string of the processor family, you can just return the
SystemType
property:
PowerShell
SystemType
----------
X86-based PC
PowerShell
Output
Name PrimaryOwnerName Domain TotalPhysicalMemory Model
Manufacturer
Your output from commands such as this, which return information directly from some
hardware, is
only as good as the data you have. Some information isn't correctly
configured by hardware
manufacturers and may therefore be unavailable.
PowerShell
Output
For more succinct output, you may want to exclude some properties. Although you can
use the
Get-CimInstance 's Property parameter to choose only the HotFixID, doing so
will actually
return more information, because all the metadata is displayed by default:
PowerShell
Output
InstalledOn :
Caption :
Description :
InstallDate :
Name :
Status :
CSName :
FixComments :
HotFixID : KB4533002
InstalledBy :
ServicePackInEffect :
PSComputerName :
CimClass : root/cimv2:Win32_QuickFixEngineering
CimSystemProperties :
Microsoft.Management.Infrastructure.CimSystemProperties
...
PowerShell
Output
HotFixId
--------
KB4048951
PowerShell
Select-Object -Property
BuildNumber,BuildType,OSType,ServicePackMajorVersion,ServicePackMinorVersion
You can also use wildcards with the Property parameter. Because all the properties
beginning
with either Build or ServicePack are important to use here, we can shorten
this to the
following form:
PowerShell
Get-CimInstance -ClassName Win32_OperatingSystem |
Output
BuildNumber : 18362
OSType : 18
ServicePackMajorVersion : 0
ServicePackMinorVersion : 0
PowerShell
PowerShell
PowerShell
Output
DeviceID DriveType ProviderName VolumeName Size FreeSpace
PSComputerName
PowerShell
Output
Property Sum
-------- ---
FreeSpace 109839607808
Size 326846914560
PowerShell
PowerShell
PowerShell
Output
Day : 23
DayOfWeek : 1
Hour : 8
Milliseconds :
Minute : 52
Month : 12
Quarter : 4
Second : 55
WeekInMonth : 4
Year : 2019
PSComputerName :
also use
Select-Object to filter the results to Status, Name, and DisplayName, the
output
format is almost identical to that from Get-Service :
PowerShell
To allow the complete display of names for services with long names, use the AutoSize
and
Wrap parameters of Format-Table . These parameters optimize column width and
allow long names
to wrap instead of being truncated:
PowerShell
To read the original June 3, 2014 Scripting Guy blog post, see
Use FilterHashTable to
Filter Event Log with PowerShell .
This article is an excerpt of the original blog post and explains how to use the Get-
WinEvent
cmdlet's FilterHashtable parameter to filter event logs. PowerShell's Get-
WinEvent cmdlet is a
powerful method to filter Windows event and diagnostic logs.
When you work with large event logs, it's not efficient to send objects down the pipeline
to a
Where-Object command. Prior to PowerShell 6, the Get-EventLog cmdlet was
another option to get
log data. For example, the following commands are inefficient to
filter the
Microsoft-Windows-Defrag logs:
PowerShell
The following command uses a hash table that improves the performance:
PowerShell
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='*defrag'
If the key-value pairs are on the same line, they must be separated by a semicolon. If
each
key-value pair is on a separate line, the semicolon isn't needed. For example, this
article
places key-value pairs on separate lines and doesn't use semicolons.
This sample uses several of the FilterHashtable parameter's key-value pairs. The
completed
query includes LogName, ProviderName, Keywords, ID, and Level.
The accepted key-value pairs are shown in the following table and are included in the
documentation for the Get-WinEvent FilterHashtable parameter.
The following table displays the key names, data types, and whether wildcard characters
are accepted
for a data value.
Path <String[]> No
Keywords <Long[]> No
ID <Int32[]> No
Level <Int32[]> No
StartTime <DateTime> No
EndTime <DateTime> No
UserID <SID> No
Data <String[]> No
<named-data> <String[]> No
The <named-data> key represents a named event data field. For example, the Perflib
event 1008
can contain the following event data:
XML
<EventData>
<Data Name="Service">BITS</Data>
<Data Name="Library">C:\Windows\System32\bitsperf.dll</Data>
<Data Name="Win32Error">2</Data>
</EventData>
You can query for these events using the following command:
PowerShell
7 Note
To begin, create the Get-WinEvent query. Use the FilterHashtable parameter's key-value
pair with the key, LogName, and the value, Application.
PowerShell
Get-WinEvent -FilterHashtable @{
LogName='Application'
Continue to build the hash table with the ProviderName key. Usually, the ProviderName
is the
name that appears in the Source field in the Windows Event Viewer. For example,
.NET Runtime in the following screenshot:
PowerShell
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
7 Note
For some event providers, the correct ProviderName can be obtained by looking
on the
Details tab in Event Properties. For example, events where the Source field
shows
Defrag , the correct ProviderName is Microsoft-Windows-Defrag .
If your query needs to get data from archived event logs, use the Path key. The Path
value
specifies the full path to the log file. For more information, see the Scripting Guy
blog post,
Use PowerShell to Parse Saved Event Logs for Errors .
maximum value
of [long] :
PowerShell
[long]::MaxValue
Output
9223372036854775807
For the Keywords key, PowerShell uses a number, not a string such as Security.
Windows
Event Viewer displays the Keywords as strings, but they're enumerated values.
In the hash
table, if you use the Keywords key with a string value, an error message is
displayed.
Open the Windows Event Viewer and from the Actions pane, click on Filter current log.
The Keywords drop-down menu displays the available keywords, as shown in the
following
screenshot:
PowerShell
[System.Diagnostics.Eventing.Reader.StandardEventKeywords] |
Output
TypeName: System.Diagnostics.Eventing.Reader.StandardEventKeywords
—- ———- ———-
The enumerated values are documented in the .NET Framework. For more information,
see
StandardEventKeywords Enumeration.
Name Value
AuditFailure 4503599627370496
AuditSuccess 9007199254740992
CorrelationHint2 18014398509481984
Name Value
EventLogClassic 36028797018963968
Sqm 2251799813685248
WdiDiagnostic 1125899906842624
WdiContext 562949953421312
ResponseTime 281474976710656
None 0
Update the hash table and include the key-value pair with the key, Keywords, and the
EventLogClassic enumeration value, 36028797018963968.
PowerShell
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
PowerShell
$C =
[System.Diagnostics.Eventing.Reader.StandardEventKeywords]::EventLogClassic
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=$C.Value__
Filtering by Event Id
To get more specific data, the query's results are filtered by Event Id. The Event Id is
referenced in the hash table as the key ID and the value is a specific Event Id. The
Windows Event Viewer displays the Event Id. This example uses Event Id 1023.
Update the hash table and include the key-value pair with the key, ID and the value,
1023.
PowerShell
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
ID=1023
Filtering by Level
To further refine the results and include only events that are errors, use the Level key.
Windows Event Viewer displays the Level as string values, but they're enumerated
values. In
the hash table, if you use the Level key with a string value, an error message is
displayed.
Level has values such as Error, Warning, or Informational. Use the following command
to display the StandardEventLevel property names.
PowerShell
[System.Diagnostics.Eventing.Reader.StandardEventLevel] |
Output
TypeName: System.Diagnostics.Eventing.Reader.StandardEventLevel
The enumerated values are documented in the .NET Framework. For more information,
see
StandardEventLevel Enumeration.
Name Value
Verbose 5
Informational 4
Warning 3
Error 2
Critical 1
LogAlways 0
The hash table for the completed query includes the key, Level, and the value, 2.
PowerShell
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
ID=1023
Level=2
PowerShell
$C = [System.Diagnostics.Eventing.Reader.StandardEventLevel]::Informational
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
ID=1023
Level=$C.Value__
You can use the Process cmdlets in PowerShell to manage local and remote processes in
PowerShell.
Getting processes
To get the processes running on the local computer, run a Get-Process with no
parameters.
You can get particular processes by specifying their process names or process IDs. The
following
command gets the Idle process:
PowerShell
Get-Process -id 0
Output
0 0 0 16 0 0 Idle
Although it's normal for cmdlets to return no data in some situations, when you specify
a process by
its ProcessId, Get-Process generates an error if it finds no matches,
because the usual intent
is to retrieve a known running process. If there is no process
with that ID, it's likely that the ID
is incorrect or that the process of interest has already
exited:
PowerShell
Get-Process -Id 99
Output
Get-Process : No process with process ID 99 was found.
At line:1 char:12
You can use the Name parameter of the Get-Process cmdlet to specify a subset of
processes based on
the process name. The Name parameter can take multiple names in
a comma-separated list and it
supports the use of wildcards, so you can type name
patterns.
For example, the following command gets process whose names begin with "ex."
PowerShell
Output
PowerShell
Output
You can use the ComputerName parameter of Get-Process to get processes on remote
computers. For
example, the following command gets the PowerShell processes on the
local computer (represented by
"localhost") and on two remote computers.
PowerShell
Output
The computer names aren't evident in this display, but they're stored in the
MachineName property of
the process objects that Get-Process returns. The following
command uses the Format-Table cmdlet
to display the process ID, ProcessName and
MachineName (ComputerName) properties of the
process objects.
PowerShell
Output
Id ProcessName MachineName
-- ----------- -----------
This more complex command adds the MachineName property to the standard Get-
Process display.
PowerShell
@{Label="NPM(K)";Expression={[int]($_.NPM/1024)}},
@{Label="PM(K)";Expression={[int]($_.PM/1024)}},
@{Label="WS(K)";Expression={[int]($_.WS/1024)}},
@{Label="VM(M)";Expression={[int]($_.VM/1MB)}},
Output
Stopping processes
PowerShell gives you flexibility for listing processes, but what about stopping a process?
The Stop-Process cmdlet takes a Name or Id to specify a process you want to stop. Your
ability to
stop processes depends on your permissions. Some processes can't be
stopped. For example, if you try
to stop the idle process, you get an error:
PowerShell
Output
Access is denied
At line:1 char:13
You can also force prompting with the Confirm parameter. This parameter is particularly
useful
if you use a wildcard when specifying the process name, because you may
accidentally match some
processes you don't want to stop:
PowerShell
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n
Complex process manipulation is possible by using some of the object filtering cmdlets.
Because a
Process object has a Responding property that's true when it's no longer
responding, you can
stop all nonresponsive applications with the following command:
PowerShell
You can use the same approach in other situations. For example, suppose a secondary
notification
area application automatically runs when users start another application.
You may find that this
doesn't work correctly in Terminal Services sessions, but you still
want to keep it in sessions that
run on the physical computer console. Sessions
connected to the physical computer desktop always
have a session ID of 0, so you can
stop all instances of the process that are in other sessions by
using Where-Object and
the process, SessionId:
PowerShell
PowerShell
PowerShell
Stop-Process -PassThru
Output
See also
Get-Process
Stop-Process
Start-Process
Wait-Process
Debug-Process
Invoke-Command
Managing services
Article • 12/09/2022
There are eight core Service cmdlets, designed for a wide range of service tasks . This
article
only looks at listing and changing running state for services. You can get a list of
service cmdlets
using Get-Command *-Service . You can find information about each
cmdlet by using
Get-Help <Cmdlet-Name> , such as Get-Help New-Service .
Getting services
You can get the services on a local or remote computer by using the Get-Service
cmdlet. As with
Get-Process , using the Get-Service command without parameters
returns all services. You can
filter by name, even using an asterisk as a wildcard:
PowerShell
Because it isn't always apparent what the real name for the service is, you may find you
need to
find services by display name. You can search by specific name, use wildcards, or
provide a list of
display names:
PowerShell
PowerShell
Starting in PowerShell 6.0, the *-Service cmdlets don't have the ComputerName
parameter. You
can still get services on remote computers with PowerShell remoting. For
example, the following
command gets the services on the Server02 remote computer.
PowerShell
You can also manage services with the other *-Service cmdlets. For more information
on PowerShell
remoting, see about_Remote.
PowerShell
PowerShell
The following command gets all services that have dependencies. The Format-Table
cmdlet to display
the Status, Name, RequiredServices, and DependentServices
properties of the
services.
PowerShell
PowerShell
PowerShell
Start-Service -Name spooler
PowerShell
The Restart-Service cmdlet works in the same manner as the other Service cmdlets:
PowerShell
PS>
Notice that you get a repeated warning message about the Print Spooler starting up.
When you perform
a service operation that takes some time, PowerShell notifies you
that it's still attempting to
perform the task.
If you want to restart multiple services, you can get a list of services, filter them, and
then
perform the restart:
PowerShell
it has dependent services. It can only be stopped if the Force flag is set.
At line:1 char:57
These Service cmdlets don't have a ComputerName parameter, but you can run them
on a remote
computer by using the Invoke-Command cmdlet. For example, the following
command restarts the
Spooler service on the Server01 remote computer.
PowerShell
To use Set-Service on Windows Vista and later versions of Windows, open PowerShell
with the Run
as administrator option.
See also
about_Remote
Get-Service
Set-Service
Restart-Service
Suspend-Service
Working with printers in Windows
Article • 12/09/2022
You can use PowerShell to manage printers using WMI and the WScript.Network COM
object from WSH.
PowerShell
You can also list the printers using the WScript.Network COM object that's typically
used in WSH
scripts:
PowerShell
Because this command returns a simple string collection of port names and printer
device names
without any distinguishing labels, it isn't easy to interpret.
PowerShell
(New-Object -ComObject
WScript.Network).AddWindowsPrinterConnection("\\Printserver01\Xerox5")
PowerShell
PowerShell
PowerShell
(New-Object -ComObject
WScript.Network).RemovePrinterConnection("\\Printserver01\Xerox5")
Performing networking tasks
Article • 12/09/2022
Because TCP/IP is the most commonly used network protocol, most low-level network
protocol
administration tasks involve TCP/IP. In this section, we use PowerShell and WMI
to do these tasks.
PowerShell
Output
10.0.0.1
fe80::60ea:29a7:a233:7cb7
2601:600:a27f:a470:f532:6451:5630:ec8b
2601:600:a27f:a470:e167:477d:6c5c:342d
2601:600:a27f:a470:b021:7f0d:eab9:6299
2601:600:a27f:a470:a40e:ebce:1a8c:a2f3
2601:600:a27f:a470:613c:12a2:e0e0:bd89
2601:600:a27f:a470:444f:17ec:b463:7edd
2601:600:a27f:a470:10fd:7063:28e9:c9f3
2601:600:a27f:a470:60ea:29a7:a233:7cb7
2601:600:a27f:a470::2ec1
Using the Get-Member cmdlet, you can see that the IPAddress property is an array:
PowerShell
Output
TypeName:
Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_NetworkAdap
terConfiguration
The IPAddress property for each network adapter is actually an array. The braces in the
definition
indicate that IPAddress isn't a System.String value, but an array of
System.String
values.
PowerShell
The default display for the network adapter configuration object is a very reduced set of
the
available information. For in-depth inspection and troubleshooting, use Select-
Object or a
formatting cmdlet, such as Format-List , to specify the properties to be
displayed.
In modern TCP/IP networks you are probably not interested in IPX or WINS properties.
You can use the
ExcludeProperty parameter of Select-Object to hide properties with
names that begin with
"WINS" or "IPX".
PowerShell
This command returns detailed information about DHCP, DNS, routing, and other minor
IP configuration
properties.
Pinging computers
You can perform a simple ping against a computer using by Win32_PingStatus. The
following
command performs the ping, but returns lengthy output:
PowerShell
A more useful form for summary information a display of the Address, ResponseTime,
and StatusCode
properties, as generated by the following command. The Autosize
parameter of Format-Table
resizes the table columns so that they display properly in
PowerShell.
PowerShell
Output
You can use an array to ping multiple computers with a single command. Because there
is more than
one address, use the ForEach-Object to ping each address separately:
PowerShell
'127.0.0.1','localhost','bing.com' |
ForEach-Object -Process {
You can use the same command format to ping all the addresses on a subnet, such as a
private network
that uses network number 192.168.1.0 and a standard Class C subnet
mask (255.255.255.0)., Only
addresses in the range of 192.168.1.1 through 192.168.1.254
are legitimate local addresses (0 is
always reserved for the network number and 255 is a
subnet broadcast address).
To represent an array of the numbers from 1 through 254 in PowerShell, use the
expression 1..254 .
A complete subnet ping can be performed by adding each value in
the range to a partial address in
the ping statement:
PowerShell
Note that this technique for generating a range of addresses can be used elsewhere as
well. You can
generate a complete set of addresses in this way:
PowerShell
PowerShell
PowerShell
$wql = 'SELECT * FROM Win32_NetworkAdapterConfiguration WHERE
IPEnabled=True'
PowerShell
To exclude adapters with IP configuration problems, you can retrieve only IP-enabled
adapters:
PowerShell
PowerShell
PowerShell
Using the filter statement IPEnabled=True and DHCPEnabled=False avoids enabling DHCP
where it's
already enabled.
PowerShell
The only change for renewing a DHCP lease is to use the RenewDHCPLease method
instead of the
ReleaseDHCPLease method:
PowerShell
7 Note
When using these methods on a remote computer, be aware that you can lose
access to the remote
system if you are connected to it through the adapter with
the released or renewed lease.
PowerShell
You can use the same command format to invoke the RenewDHCPLeaseAll method:
PowerShell
PowerShell
Path = 'C:\temp'
Name = 'TempShare'
MaximumAllowed = [uint32]25
PowerShell
net share tempshare=c:\temp /users:25 /remark:"test share of the temp
folder"
To call a method of a WMI class that takes parameters you must know what parameters
are available
and the types of those parameters. For example, you can list the methods
of the Win32_Class with
the following commands:
PowerShell
Output
GetAccessMask UInt32 {}
{Implemented, MappingStrings}
Delete UInt32 {}
{Destructor, Implemented, MappingStrings}
Use the following command to list the parameters of the Create method.
PowerShell
Output
PowerShell
PowerShell
However, drives created this way are only available to PowerShell session where they're
created. To
map a drive that's available outside of PowerShell (or to other PowerShell
sessions), you must use
the Persist parameter.
PowerShell
7 Note
Applications installed with the Windows Installer can be found through WMI's queries,
but not all
applications use the Windows Installer. The specific techniques for find
applications installed
with other tools depends on the installer software.
For example, applications installed by copying the files to a folder on the computer
usually can't
be managed using techniques discussed here. You can manage these
applications as files and folders
using the techniques discussed in Working With Files
and Folders.
For software installed using an installer package, the Windows Installer can be found
using the
Win32Reg_AddRemovePrograms or the Win32_Product classes. However,
both of these have
problems. The Win32Reg_AddRemovePrograms is only available if
you are using System Center
Configuration Manager (SCCM). And the Win32_Product
class can be slow and has side effects.
U Caution
The Win32_Product class isn't query optimized. Queries that use wildcard filters
cause WMI to
use the MSI provider to enumerate all installed products then parse
the full list sequentially to
handle the filter. This also initiates a consistency check of
packages installed, verifying and
repairing the install. The validation is a slow
process and may result in errors in the event
logs. For more information seek KB
article 974524 .
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall .
We can find the number of installed applications by counting the number
of registry
keys:
PowerShell
$UninstallPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall'
Output
459
We can search this list of applications further using a variety of techniques. To display
the values
of the registry values in the registry keys under Uninstall , use the
GetValue() method of the
registry keys. The value of the method is the name of the
PowerShell
Sort-Object
7 Note
PowerShell
Get-ChildItem $UninstallPath |
ForEach-Object {
} | Select-Object -First 3
For the sake of brevity, this example uses Select-Object to limit the number of items
returned to
three.
Output
InstallDate :
ProdID : 7-Zip
DisplayVersion : 22.01
InstallDate :
ProdID : AutoHotkey
Publisher : Lexikos
DisplayVersion : 1.1.33.10
InstallDate : 20230310
ProdID : BeyondCompare4_is1
At times, you may have a PowerShell process running that's taking up a large amount of
resources.
This process could be running in the context of a Task Scheduler job or a
SQL
Server Agent job. Where there are multiple PowerShell processes running, it can be
difficult to know which process represents the problem. This article shows how to
decode a script
block that a PowerShell process is currently running.
PowerShell
powershell.exe -Command {
$i = 1
while ( $i -le 10 )
Write-Output -InputObject $i
Start-Sleep -Seconds 60
$i++
PowerShell
The following command creates a custom PowerShell object that contains the process
ID and the
encoded command.
PowerShell
@{
name = 'EncodedCommand'
expression = {
return $matches[1]
Now the encoded command can be decoded. The following snippet iterates over the
command details
object, decodes the encoded command, and adds the decoded
command back to the object for further
investigation.
PowerShell
$currentProcess = $_
$commandBytes =
[System.Convert]::FromBase64String($currentProcess.EncodedCommand)
$decodedCommand =
[System.Text.Encoding]::Unicode.GetString($commandBytes)
$commandDetails |
The decoded command can now be reviewed by selecting the decoded command
property.
Output
ProcessId : 8752
EncodedCommand :
IAAKAAoACgAgAAoAIAAgACAAIAAkAGkAIAA9ACAAMQAgAAoACgAKACAACgAgACAAIAAgAHcAaABp
AGwAZQAgACgAIAAkAGkAIAAtAG
wAZQAgADEAMAAgACkAIAAKAAoACgAgAAoAIAAgACAAIAB7ACAACgAKAAoAIAAKACAAIAAgACAAIA
AgACAAIABXAHIAaQB0AGUALQBP
AHUAdABwAHUAdAAgAC0ASQBuAHAAdQB0AE8AYgBqAGUAYwB0ACAAJABpACAACgAKAAoAIAAKACAA
IAAgACAAIAAgACAAIABTAHQAYQ
ByAHQALQBTAGwAZQBlAHAAIAAtAFMAZQBjAG8AbgBkAHMAIAA2ADAAIAAKAAoACgAgAAoAIAAgAC
AAIAAgACAAIAAgACQAaQArACsA
IAAKAAoACgAgAAoAIAAgACAAIAB9ACAACgAKAAoAIAAKAA==
DecodedCommand :
$i = 1
while ( $i -le 10 )
Write-Output -InputObject $i
Start-Sleep -Seconds 60
$i++
Redirecting output
Article • 12/09/2022
PowerShell provides several cmdlets that let you control data output directly. These
cmdlets share
two important characteristics.
First, they generally transform data to some form of text. They do this because they
output the data
to system components that require text input. This means they need to
represent the objects as text.
Therefore, the text is formatted as you see it in the
PowerShell console window.
Second, these cmdlets use the PowerShell verb Out because they send information out
from
PowerShell to somewhere else.
Console output
By default, PowerShell sends data to the host window, which is exactly what the Out-
Host
cmdlet does. The primary use for the Out-Host cmdlet is paging. For example, the
following command
uses Out-Host to page the output of the Get-Command cmdlet:
PowerShell
The host window display is outside of PowerShell. This is important because when data
is sent out of
PowerShell, it's actually removed. You can see this if you try to create a
pipeline that pages data
to the host window, and then attempt to format it as a list, as
shown here:
PowerShell
You might expect the command to display pages of process information in list format.
Instead, it
displays the default tabular list:
Output
...
...
...
The Out-Host cmdlet sends the data directly to the console, so the Format-List
command never
receives anything to format.
The correct way to structure this command is to put the Out-Host cmdlet at the end of
the pipeline
as shown below. This causes the process data to be formatted in a list
before being paged and
displayed.
PowerShell
Output
Id : 2888
Handles : 101
CPU : 0.046875
Name : alg
...
Id : 740
Handles : 612
CPU : 211.703125
Name : explorer
Id : 2560
Handles : 257
CPU : 3.015625
Name : explorer
...
...
This applies to all of the Out cmdlets. An Out cmdlet should always appear at the end of
the
pipeline.
7 Note
All the Out cmdlets render output as text, using the formatting in effect for the
console
window, including line length limits.
Discarding output
The Out-Null cmdlet is designed to immediately discard any input it receives. This is
useful for
discarding unnecessary data that you get as a side-effect of running a
command. When type the
following command, you don't get anything back from the
command:
PowerShell
Get-Command | Out-Null
The Out-Null cmdlet doesn't discard error output. For example, if you enter the
following command,
a message is displayed informing you that PowerShell doesn't
recognize Is-NotACommand :
Printing data
Out-Printer is only available on Windows platforms.
You can print data using the Out-Printer cmdlet. The Out-Printer cmdlet uses your
default
printer if you don't provide a printer name. You can use any Windows-based
printer by specifying its
display name. There is no need for any kind of printer port
mapping or even a real physical printer.
For example, if you have the Microsoft Office
document imaging tools installed, you can send the
data to an image file by typing:
PowerShell
Saving data
You can send output to a file instead of the console window using the Out-File cmdlet.
The
following command line sends a list of processes to the file
C:\temp\processlist.txt :
PowerShell
The results of using the Out-File cmdlet may not be what you expect if you are used to
traditional
output redirection. To understand its behavior, you must be aware of the
context in which the
Out-File cmdlet operates.
On Window PowerShell 5.1, the Out-File cmdlet creates a Unicode file. Some tools, that
expect
ASCII files, don't work correctly with the default output format. You can change
the default output
format to ASCII using the Encoding parameter:
PowerShell
Out-file formats file contents to look like console output. This causes the output to be
truncated
just as it's in a console window in most circumstances. For example, if you run
the following
command:
PowerShell
Output
...
To get output that doesn't force line wraps to match the screen width, you can use the
Width
parameter to specify line width. Because Width is a 32-bit integer parameter, the
maximum value
it can have is 2147483647. Type the following to set the line width to
this maximum value:
PowerShell
The Out-File cmdlet is most useful when you want to save output as it would have
displayed on the
console.
Using Format commands to change
output view
Article • 12/09/2022
PowerShell has a set of cmdlets that allow you to control how properties are displayed
for
particular objects. The names of all the cmdlets begin with the verb Format . They let
you select
which properties you want to show.
PowerShell
Output
Each object type in PowerShell has default properties that are used when you don't
select the
properties to display. Each cmdlet uses the same Property parameter to
specify which properties
you want displayed. Because Format-Wide only shows a single
property, its Property parameter
only takes a single value, but the property parameters
of Format-List and Format-Table accept a
list of property names.
In this example, the default output of Get-Process cmdlet shows that we've two
instances of
Internet Explorer running.
PowerShell
The default format for Process objects displays the properties shown here:
Output
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
PowerShell
Output
Format-Custom Format-Hex
Format-List Format-Table
Format-Wide
PowerShell
Output
Custom Hex
List Table
Wide
PowerShell
Output
Table Wide
PowerShell
Output
Id : 12808
Handles : 578
CPU : 13.140625
SI : 1
Name : iexplore
Id : 21748
Handles : 641
CPU : 3.59375
SI : 1
Name : iexplore
PowerShell
Output
ProcessName : iexplore
Id : 12808
ProcessName : iexplore
Id : 21748
PowerShell
Although the Format-List command is useful for showing detail, if you want an
overview of output
that includes many items, a simpler tabular view is often more useful.
PowerShell
Output
7 Note
Get-Service is only available on Windows platforms.
PowerShell
Output
The Format-Table cmdlet might still truncate data, but it only truncates at the end of the
screen.
Properties, other than the last one displayed, are given as much size as they
need for their longest
data element to display correctly.
PowerShell
Output
ces
The Format-Table command assumes that properties are listed in order of importance.
The cmdlet
attempts to fully display the properties nearest the beginning. If the Format-
Table command can't
display all the properties, it removes some columns from the
PowerShell
Output
ces
iphlpsvc}
TPHKLOAD,
SUService,
smstsmgr…}
Using the Wrap parameter by itself doesn't slow down processing very much. However,
using
AutoSize to format a recursive file listing of a large directory structure can take a
long time
and use lots of memory before displaying the first output items.
If you aren't concerned about system load, then AutoSize works well with the Wrap
parameter.
The initial columns still use as much width as needed to display items on one
line, but the final
column is wrapped, if necessary.
7 Note
Some columns may not be displayed when you specify the widest columns first. For
best results,
specify the smallest data elements first.
PowerShell
Output
FileVersion Path
Nam
----------- ----
---
plo
re
plo
re
PowerShell
Output
StartType: Automatic
StartType: Manual
When navigating folder systems in File Explorer, you usually have a specific working
location -
namely, the current open folder. Items in the current folder can be
manipulated easily by clicking
them. For command-line interfaces such as Cmd.exe,
when you are in the same folder as a particular
file, you can access it by specifying a
relatively short name, rather than needing to specify the
entire path to the file. The
current directory is called the working directory.
PowerShell uses the noun Location to refer to the working directory, and implements a
family of
cmdlets to examine and manipulate your location.
PowerShell
Get-Location
Output
Path
----
7 Note
The Get-Location cmdlet is similar to the pwd command in the BASH shell. The
Set-Location
cmdlet is similar to the cd command in Cmd.exe.
PowerShell
Set-Location -Path C:\Windows
After you enter the command, notice that you don't receive any direct feedback about
the effect of
the command. Most PowerShell commands that perform an action produce
little or no output because the
output isn't always useful. To verify that a successful
directory change has occurred when you enter
the Set-Location command, include the
PassThru parameter when you enter the Set-Location
command:
PowerShell
Output
Path
----
C:\WINDOWS
The PassThru parameter can be used with many Set commands in PowerShell to return
information
about the result for cases in which there is no default output.
You can specify paths relative to your current location in the same way as you would in
most UNIX
and Windows command shells. In standard notation for relative paths, a
period ( . ) represents your
current folder, and a doubled period ( .. ) represents the
parent directory of your current
location.
For example, if you are in the C:\Windows folder, a period ( . ) represents C:\Windows and
double periods ( .. ) represent C: . You can change from your current location to the
root of the
C: drive by typing:
PowerShell
Output
Path
----
C:\
The same technique works on PowerShell drives that aren't file system drives, such as
HKLM: . You
can set your location to the HKLM\Software key in the registry by typing:
PowerShell
Output
Path
----
HKLM:\SOFTWARE
You can then change the directory location to the parent directory, using a relative path:
PowerShell
Output
Path
----
HKLM:\
You can type Set-Location or use any of the built-in PowerShell aliases for Set-Location
( cd ,
chdir , sl ). For example:
PowerShell
cd -Path C:\Windows
PowerShell
PowerShell
PowerShell
Get-Location
Path
----
7 Note
The word stack has a special meaning in many programming settings, including
.NET Framework.
Like a physical stack of items, the last item you put onto the stack
is the first item that you
can pull off the stack. Adding an item to a stack is
colloquially known as "pushing" the item onto
the stack. Pulling an item off the
stack is colloquially known as "popping" the item off the
stack.
To push the current location onto the stack, and then move to the Local Settings folder,
type:
PowerShell
You can then push the Local Settings location onto the stack and move to the Temp
folder by typing:
PowerShell
You can verify that you changed directories by entering the Get-Location command:
PowerShell
Get-Location
Output
Path
----
You can then pop back into the most recently visited directory by entering the Pop-
Location
command, and verify the change by entering the Get-Location command:
PowerShell
Pop-Location
Get-Location
Output
Path
----
Just as with the Set-Location cmdlet, you can include the PassThru parameter when
you enter
the Pop-Location cmdlet to display the directory that you entered:
PowerShell
Pop-Location -PassThru
Output
Path
----
You can also use the Location cmdlets with network paths. If you have a server named
FS01 with an
share named Public, you can change your location by typing
PowerShell
Set-Location \\FS01\Public
or
PowerShell
Push-Location \\FS01\Public
You can use the Push-Location and Set-Location commands to change the location to
any available
drive. For example, if you have a local CD-ROM drive with drive letter D
that contains a data CD,
you can change the location to the CD drive by entering the
Set-Location D: command.
PowerShell
Set-Location D:
Output
When you are using a command-line interface, it's not convenient to use File Explorer to
examine the
available physical drives. Also, File Explorer would not show you the all the
PowerShell drives.
PowerShell provides a set of commands for manipulating PowerShell
drives.
Managing PowerShell drives
Article • 12/09/2022
A PowerShell drive is a data store location that you can access like a filesystem drive in
PowerShell. The PowerShell providers create some drives for you, such as the file
system
drives (including C: and D: ), the registry drives ( HKCU: and HKLM: ), and the
certificate
drive ( Cert: ), and you can create your own PowerShell drives. These drives are
useful,
but they're available only within PowerShell. You can't access them using other Windows
tools, such as File Explorer or Cmd.exe .
PowerShell uses the noun, PSDrive, for commands that work with PowerShell
drives. For
a list of the PowerShell drives in your PowerShell session, use the
Get-PSDrive cmdlet.
PowerShell
Get-PSDrive
Output
A FileSystem A:\
Alias Alias
cert Certificate \
D FileSystem D:\
Env Environment
Function Function
Variable Variable
Although the drives in the display vary with the drives on your system, the listing looks
similar to
the output of the Get-PSDrive command shown above.
filesystem drives are a subset of the PowerShell drives. You can identify the filesystem
drives by
the FileSystem entry in the Provider column. The filesystem drives in
PowerShell are supported by
the PowerShell FileSystem provider.
To see the syntax of the Get-PSDrive cmdlet, type a Get-Command command with the
Syntax
parameter:
PowerShell
Output
The PSProvider parameter lets you display only the PowerShell drives that are
supported by a
particular provider. For example, to display only the PowerShell drives
that are supported by the
PowerShell FileSystem provider, type a Get-PSDrive command
with the PSProvider parameter and
the FileSystem value:
PowerShell
Output
A FileSystem A:\
D FileSystem D:\
To view the PowerShell drives that represent registry hives, use the PSProvider
parameter to
display only the PowerShell drives that are supported by the PowerShell
Registry provider:
PowerShell
Output
Name Provider Root
CurrentLocation
You can also use the standard Location cmdlets with the PowerShell drives:
PowerShell
Set-Location HKLM:\SOFTWARE
Push-Location .\Microsoft
Get-Location
Output
Path
----
HKLM:\SOFTWARE\Microsoft
PowerShell
Output
A name for the drive (you can use any valid PowerShell name)
The PSProvider - use FileSystem for filesystem locations and Registry for registry
locations
The root, that is, the path to the root of the new drive
For example, you can create a drive named Office that's mapped to the folder that
contains the
Microsoft Office applications on your computer, such as C:\Program
Files\MicrosoftOffice\OFFICE11 .
To create the drive, type the following command:
PowerShell
Output
7 Note
A PowerShell drive can make many tasks much simpler. For example, some of the most
important keys in
the Windows registry have extremely long paths, making them
cumbersome to access and difficult to
remember. Critical configuration information
resides under
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion . To view
and change items in the
CurrentVersion registry key, you can create a PowerShell drive
that's rooted in that key by typing:
PowerShell
Output
You can then change location to the cvkey: drive as you would any other drive:
PowerShell
cd cvkey:
or:
PowerShell
Output
Path
----
cvkey:\
The New-PSDrive cmdlet adds the new drive only to the current PowerShell session. If
you close the
PowerShell window, the new drive is lost. To save a PowerShell drive, use
the Export-Console cmdlet
to export the current PowerShell session, and then use the
PowerShell.exe PSConsoleFile
parameter to import it. Or, add the new drive to your
PowerShell
PowerShell
However, you can't delete it while you are in the drive. For example:
PowerShell
cd office:
Output
At line:1 char:15
Navigating through PowerShell drives and manipulating the items on them is similar to
manipulating
files and folders on Windows disk drives. This article discusses how to deal
with specific file and
folder manipulation tasks using PowerShell.
PowerShell
The command lists only the directly contained items, much like using the dir command
in cmd.exe
or ls in a UNIX shell. To show items in subfolder, you need to specify the
Recurse parameter.
The following command lists everything on the C: drive:
PowerShell
Get-ChildItem can filter items with its Path, Filter, Include, and Exclude
parameters, but
those are typically based only on name. You can perform complex filtering based on
other properties of items using Where-Object .
The following command finds all executables within the Program Files folder that were
last modified
after October 1, 2005 and that are neither smaller than 1 megabyte nor
larger than 10 megabytes:
PowerShell
Where-Object -FilterScript {
PowerShell
If the destination file already exists, the copy attempt fails. To overwrite a pre-existing
destination, use the Force parameter:
PowerShell
Folder copying works the same way. This command copies the folder C:\temp\test1 to
the new folder
C:\temp\DeleteMe recursively:
PowerShell
You can also copy a selection of items. The following command copies all .txt files
contained
anywhere in C:\data to C:\temp\text :
PowerShell
You can still use other tools to perform file system copies. XCOPY, ROBOCOPY, and COM
objects, such
as the Scripting.FileSystemObject, all work in PowerShell. For example,
you can use the Windows
Script Host Scripting.FileSystem COM class to back up
C:\boot.ini to C:\boot.bak :
PowerShell
PowerShell
PowerShell
) Important
When using the Force switch with the New-Item command to create a folder, and
the folder
already exists, it won't overwrite or replace the folder. It will simply return
the existing
folder object. However, if you use New-Item -Force on a file that
already exists, the file
is overwritten.
Confirm
The item at C:\temp\DeleteMe has children and the Recurse parameter wasn't
specified. If you continue, all children will be removed with the item. Are
you
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
If you don't want to be prompted for each contained item, specify the Recurse
parameter:
PowerShell
PowerShell
Just as with network drives, drives mapped within PowerShell are immediately visible to
the
PowerShell shell. To create a mapped drive visible from File Explorer, use the Persist
parameter. However, only remote paths can be used with Persist.
timeout=5
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP
Professional"
/noexecute=AlwaysOff /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=" Microsoft Windows XP
Professional
Get-Content treats the data read from the file as an array, with one element per line of
file
content. You can confirm this by checking the Length of the returned content:
This command is most useful for getting lists of information into PowerShell. For
example, you might
store a list of computer names or IP addresses in the file
C:\temp\domainMembers.txt , with one
name on each line of the file. You can use Get-
PowerShell
PowerShell uses the noun Item to refer to items found on a PowerShell drive. When
dealing with
the PowerShell FileSystem provider, an Item might be a file, a folder, or the
PowerShell drive.
Listing and working with these items is a critical basic task in most
administrative settings, so we
want to discuss these tasks in detail.
container such as
a folder.
If you want to return all files and folders that are contained directly within the folder
C:\Windows , type:
Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows
...
The listing looks similar to what you would see when you enter the dir command in
cmd.exe , or
the ls command in a UNIX command shell.
You can perform complex listings using parameters of the Get-ChildItem cmdlet. You
can see the
syntax the Get-ChildItem cmdlet by typing:
PowerShell
These parameters can be mixed and matched to get highly customized output.
Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS
Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS\AppPatch
...
addins
AppPatch
assembly
...
ChildItem .
For example:
PowerShell
This parameter is named Force because you can forcibly override the normal behavior of
the
Get-ChildItem command. Force is a widely used parameter that forces an action
that a cmdlet
wouldn't normally perform, although it can't perform any action that
compromises the security of the
system.
Because wildcard matching is handled by the PowerShell engine, all cmdlets that accepts
wildcards
use the same notation and have the same matching behavior. The PowerShell
wildcard notation
includes:
To find all files in the Windows directory with the suffix .log and exactly five characters
in the
base name, enter the following command:
Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows
...
...
...
To find all files that begin with the letter x in the Windows directory, type:
PowerShell
To find all files whose names begin with "x" or "z", type:
PowerShell
Get-ChildItem -Path C:\Windows\[xz]*
Excluding items
You can exclude specific items using the Exclude parameter of Get-ChildItem . This lets
you
perform complex filtering in a single statement.
For example, suppose you are trying to find the Windows Time Service DLL in the
System32 folder,
and all you can remember about the DLL name is that it begins with
"W" and has "32" in it.
An expression like w*32*.dll will find all DLLs that satisfy the conditions, but you may
want to
further filter out the files and omit any win32 files. You can omit these files using
the
Exclude parameter with the pattern win* :
Directory: C:\WINDOWS\System32
PowerShell
There are no results, even though there are two DLLs that begin with the letter "z" in the
Windows
folder.
No results were returned because we specified the wildcard as part of the path. Even
though the
command was recursive, the Get-ChildItem cmdlet restricted the items to
those that are in the
Windows folder with names ending with .dll .
To specify a recursive search for files whose names match a special pattern, use the
Include
parameter.
Directory:
Microsoft.PowerShell.Core\FileSystem::C:\Windows\System32\Setup
Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows\System32
Because registry entries are properties of keys and, as such, can't be directly browsed,
we need to
take a slightly different approach when working with them.
PowerShell
Get-Item -Path
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion |
Output
DevicePath
MediaPathUnexpanded
ProgramFilesDir
CommonFilesDir
ProductId
PowerShell
Get-ItemProperty -Path
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
Output
DevicePath : C:\WINDOWS\inf
MediaPathUnexpanded : C:\WINDOWS\Media
SM_GamesName : Games
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWA
RE\Microsoft\Windows\CurrentVersion
PSParentPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWA
RE\Microsoft\Windows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
The Windows PowerShell-related properties for the key are all prefixed with "PS", such
as
PSPath, PSParentPath, PSChildName, and PSProvider.
You can use the *.* notation for referring to the current location. You can use Set-
Location to
change to the CurrentVersion registry container first:
PowerShell
Set-Location -Path
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
Alternatively, you can use the built-in HKLM: PSDrive with Set-Location :
PowerShell
You can then use the . notation for the current location to list the properties without
specifying a full path:
PowerShell
Get-ItemProperty -Path .
Output
...
DevicePath : C:\WINDOWS\inf
MediaPathUnexpanded : C:\WINDOWS\Media
...
Path expansion works the same as it does within the filesystem, so from this location
you can get
the ItemProperty listing for HKLM:\SOFTWARE\Microsoft\Windows\Help using
Get-ItemProperty -Path ..\Help .
Using Get-ItemProperty , use the Path parameter to specify the name of the key, and the
Name parameter to specify the name of the DevicePath entry.
PowerShell
Output
DevicePath : C:\WINDOWS\inf
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Wi
ndows\CurrentVersion
PSParentPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Wi
ndows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
This command returns the standard Windows PowerShell properties as well as the
DevicePath
property.
7 Note
Although Get-ItemProperty has Filter, Include, and Exclude parameters, they can't
be used to filter by property name. These parameters refer to registry keys, which
are item
paths and not registry entries, which are item properties.
Another option is to use the reg.exe command line tool. For help with reg.exe , type
reg.exe /?
at a command prompt. To find the DevicePath entry, use reg.exe as shown
in the following
command:
PowerShell
Output
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
You can also use the WshShell COM object to find some registry entries, although this
method
doesn't work with large binary data or with registry entry names that include
characters such as
backslash ( \ ). Append the property name to the item path with a \
separator:
PowerShell
(New-Object -ComObject
WScript.Shell).RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Devic
ePath")
Output
%SystemRoot%\inf
PowerShell
$value = Get-ItemProperty -Path HKCU:\Environment -Name Path
7 Note
Another option is to use the Reg.exe command line tool. For help with reg.exe, type
reg.exe /? at
a command prompt.
The following example changes the Path entry by removing the path added in the
example above.
Get-ItemProperty is still used to retrieve the current value to avoid
having to parse the string
returned from reg query . The SubString and LastIndexOf
methods are used to retrieve the
last path added to the Path entry.
PowerShell
Output
You can add the new entry to the key using the following command, and the command
also returns
information about the new entry:
PowerShell
New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name
PowerShellPath -PropertyType String -Value $PSHome
Output
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wi
ndows\CurrentVersion
PSParentPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wi
ndows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
PropertyType Meaning
Value
ExpandString A string that can contain environment variables that are dynamically
expanded
You can add a registry entry to multiple locations by specifying an array of values for the
Path
parameter:
PowerShell
-Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion,
HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion
You can also overwrite a pre-existing registry entry value by adding the Force parameter
to any
New-ItemProperty command.
Renaming registry entries
To rename the PowerShellPath entry to "PSHome," use Rename-ItemProperty :
PowerShell
To display the renamed value, add the PassThru parameter to the command.
PowerShell
PowerShell
Because registry keys are items on PowerShell drives, working with them is very similar
to working
with files and folders. One critical difference is that every item on a registry-
based PowerShell
drive is a container, just like a folder on a file system drive. However,
registry entries and their
associated values are properties of the items, not distinct items.
PowerShell
Output
Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER
Name
----
HKEY_CURRENT_USER\AppEvents
HKEY_CURRENT_USER\Console
HKEY_CURRENT_USER\Control Panel
HKEY_CURRENT_USER\DirectShow
HKEY_CURRENT_USER\dummy
HKEY_CURRENT_USER\Environment
HKEY_CURRENT_USER\EUDC
HKEY_CURRENT_USER\Keyboard Layout
HKEY_CURRENT_USER\MediaFoundation
HKEY_CURRENT_USER\Microsoft
HKEY_CURRENT_USER\Network
HKEY_CURRENT_USER\Printers
HKEY_CURRENT_USER\Software
HKEY_CURRENT_USER\System
HKEY_CURRENT_USER\Uninstall
HKEY_CURRENT_USER\WXP
HKEY_CURRENT_USER\Volatile Environment
These are the top-level keys visible under HKEY_CURRENT_USER in the Registry Editor
( regedit.exe ).
You can also specify this registry path by specifying the registry provider's name,
followed by
:: . The registry provider's full name is
Microsoft.PowerShell.Core\Registry , but this can be
shortened to just Registry . Any of
PowerShell
Get-ChildItem HKCU:
These commands list only the directly contained items, much like using DIR in cmd.exe
or ls
in a UNIX shell. To show contained items, you need to specify the Recurse
parameter. To list all
registry keys in HKCU: , use the following command.
PowerShell
Get-ChildItem can perform complex filtering capabilities through its Path, Filter,
Include, and Exclude parameters, but those parameters are typically based only on
name. You
can perform complex filtering based on other properties of items using the
Where-Object cmdlet.
The following command finds all keys within HKCU:\Software that
PowerShell
Copying keys
Copying is done with Copy-Item . The following example copies the CurrentVersion
subkey of
HKLM:\SOFTWARE\Microsoft\Windows\ and all of its properties to HKCU:\ .
PowerShell
Copy-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion' -
Destination HKCU:
If you examine this new key in the registry editor or using Get-ChildItem , you notice
that you
don't have copies of the contained subkeys in the new location. In order to
copy all of the contents
of a container, you need to specify the Recurse parameter. To
make the preceding copy command
recursive, you would use this command:
PowerShell
You can still use other tools you already have available to perform filesystem copies. Any
registry
editing tools—including reg.exe , regini.exe , regedit.exe , and COM objects
that support
registry editing, such as WScript.Shell and WMI's StdRegProv class can be
used from within
PowerShell.
Creating keys
Creating new keys in the registry is simpler than creating a new item in a file system.
Because all
registry keys are containers, you don't need to specify the item type. Just
provide an explicit
path, such as:
PowerShell
PowerShell
Deleting keys
Deleting items is essentially the same for all providers. The following commands silently
remove
items:
PowerShell
Remove-Item -Path HKCU:\Software_DeleteMe
PowerShell
Output
Confirm
parameter was not specified. If you continue, all children will be removed
with
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
PowerShell
PowerShell
Script a graphical custom input box using Microsoft .NET Framework form-building
features in Windows
PowerShell 3.0 and later releases.
PowerShell
$form.StartPosition = 'CenterScreen'
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
$form.Controls.Add($label)
$form.Controls.Add($textBox)
$form.Topmost = $true
$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()
$x = $textBox.Text
$x
The script begins by loading two .NET Framework classes: System.Drawing and
System.Windows.Forms. You then start a new instance of the .NET Framework class
System.Windows.Forms.Form. That provides a blank form or window to which you can
start adding
controls.
PowerShell
After you create an instance of the Form class, assign values to three properties of this
class.
PowerShell
$form.StartPosition = 'CenterScreen'
Next, create an OK button for your form. Specify the size and behavior of the OK button.
In
this example, the button position is 120 pixels from the form's top edge, and 75 pixels
from the
left edge. The button height is 23 pixels, while the button length is 75 pixels.
The script uses
predefined Windows Forms types to determine the button behaviors.
PowerShell
$okButton = New-Object System.Windows.Forms.Button
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
Similarly, you create a Cancel button. The Cancel button is 120 pixels from the top, but
150
pixels from the left edge of the window.
PowerShell
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
Next, provide label text on your window that describes the information you want users
to provide.
PowerShell
$form.Controls.Add($label)
Add the control (in this case, a text box) that lets users provide the information you've
described
in your label text. There are many other controls you can apply besides text
boxes. For more
controls, see System.Windows.Forms Namespace.
PowerShell
$form.Controls.Add($textBox)
Set the Topmost property to $true to force the window to open atop other open
windows and
dialog boxes.
PowerShell
$form.Topmost = $true
Next, add this line of code to activate the form, and set the focus to the text box that
you
created.
PowerShell
$form.Add_Shown({$textBox.Select()})
PowerShell
$result = $form.ShowDialog()
Finally, the code inside the If block instructs Windows what to do with the form after
users
provide text in the text box, and then click the OK button or press the Enter key.
PowerShell
$x = $textBox.Text
$x
See also
GitHub: Dave Wyatt's WinFormsExampleUpdates )
Windows PowerShell Tip of the Week: Creating a Custom Input Box
Creating a graphical date picker
Article • 12/09/2022
Use Windows PowerShell 3.0 and later releases to create a form with a graphical,
calendar-style
control that lets users select a day of the month.
PowerShell
StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
Topmost = $true
ShowTodayCircle = $false
MaxSelectionCount = 1
$form.Controls.Add($calendar)
Text = 'OK'
DialogResult = [Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
Text = 'Cancel'
DialogResult = [Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
$result = $form.ShowDialog()
$date = $calendar.SelectionStart
The script begins by loading two .NET Framework classes: System.Drawing and
System.Windows.Forms. You then start a new instance of the .NET Framework class
Windows.Forms.Form. That provides a blank form or window to which you can start
adding controls.
PowerShell
StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
Topmost = $true
This example assigns values to four properties of this class by using the Property
property and
hashtable.
1. StartPosition: If you don't add this property, Windows selects a location when the
form is
opened. By setting this property to CenterScreen, you're automatically
displaying the form in
the middle of the screen each time it loads.
2. Size:
This is the size of the form, in pixels.
The preceding script creates a form
that's 243 pixels wide by 230 pixels tall.
3. Text:
This becomes the title of the window.
4. Topmost: By setting this property to $true , you can force the window to open
atop other
open windows and dialog boxes.
Next, create and then add a calendar control in your form. In this example, the current
day isn't
highlighted or circled. Users can select only one day on the calendar at one
time.
PowerShell
ShowTodayCircle = $false
MaxSelectionCount = 1
$form.Controls.Add($calendar)
Next, create an OK button for your form. Specify the size and behavior of the OK button.
In
this example, the button position is 165 pixels from the form's top edge, and 38 pixels
from the
left edge. The button height is 23 pixels, while the button length is 75 pixels.
The script uses
predefined Windows Forms types to determine the button behaviors.
PowerShell
Text = 'OK'
DialogResult = [Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
Similarly, you create a Cancel button. The Cancel button is 165 pixels from the top, but
113
pixels from the left edge of the window.
PowerShell
Text = 'Cancel'
DialogResult = [Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
PowerShell
$result = $form.ShowDialog()
Finally, the code inside the if block instructs Windows what to do with the form after
users
select a day on the calendar, and then click the OK button or press the Enter key.
Windows
PowerShell displays the selected date to users.
PowerShell
if ($result -eq [Windows.Forms.DialogResult]::OK) {
$date = $calendar.SelectionStart
See also
GitHub: Dave Wyatt's WinFormsExampleUpdates
Windows PowerShell Tip of the Week: Creating a Graphical Date Picker)
Multiple-selection list boxes
Article • 12/09/2022
Use Windows PowerShell 3.0 and later releases to create a multiple-selection list box
control in a
custom Windows Form.
PowerShell
$form.StartPosition = 'CenterScreen'
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
$form.Controls.Add($label)
$listBox.SelectionMode = 'MultiExtended'
$listBox.Height = 70
$form.Controls.Add($listBox)
$form.Topmost = $true
$result = $form.ShowDialog()
$x = $listBox.SelectedItems
$x
The script begins by loading two .NET Framework classes: System.Drawing and
System.Windows.Forms. You then start a new instance of the .NET Framework class
System.Windows.Forms.Form. That provides a blank form or window to which you can
start adding
controls.
PowerShell
After you create an instance of the Form class, assign values to three properties of this
class.
PowerShell
$form.StartPosition = 'CenterScreen'
Next, create an OK button for your form. Specify the size and behavior of the OK button.
In
this example, the button position is 120 pixels from the form's top edge, and 75 pixels
from the
left edge. The button height is 23 pixels, while the button length is 75 pixels.
The script uses
predefined Windows Forms types to determine the button behaviors.
PowerShell
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)
Similarly, you create a Cancel button. The Cancel button is 120 pixels from the top, but
150
pixels from the left edge of the window.
PowerShell
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)
Next, provide label text on your window that describes the information you want users
to provide.
PowerShell
$form.Controls.Add($label)
Add the control (in this case, a list box) that lets users provide the information you've
described
in your label text. There are many other controls you can apply besides text
boxes; for more
controls, see System.Windows.Forms Namespace.
PowerShell
$listBox = New-Object System.Windows.Forms.Listbox
Here's how you specify that you want to allow users to select multiple values from the
list.
PowerShell
$listBox.SelectionMode = 'MultiExtended'
In the next section, you specify the values you want the list box to display to users.
PowerShell
PowerShell
$listBox.Height = 70
Add the list box control to your form, and instruct Windows to open the form atop other
windows and
dialog boxes when it's opened.
PowerShell
$form.Controls.Add($listBox)
$form.Topmost = $true
PowerShell
$result = $form.ShowDialog()
Finally, the code inside the if block instructs Windows what to do with the form after
users
select one or more options from the list box, and then click the OK button or press
the
Enter key.
PowerShell
$x = $listBox.SelectedItems
$x
See also
Weekend Scripter: Fixing PowerShell GUI Examples
GitHub: Dave Wyatt's WinFormsExampleUpdates
Windows PowerShell Tip of the Week: Multi-Select List Boxes - And More!)
Selecting items from a list box
Article • 12/09/2022
Use Windows PowerShell 3.0 and later releases to create a dialog box that lets users
select items
from a list box control.
PowerShell
$form.StartPosition = 'CenterScreen'
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
$form.Controls.Add($label)
$listBox.Height = 80
[void] $listBox.Items.Add('atl-dc-001')
[void] $listBox.Items.Add('atl-dc-002')
[void] $listBox.Items.Add('atl-dc-003')
[void] $listBox.Items.Add('atl-dc-004')
[void] $listBox.Items.Add('atl-dc-005')
[void] $listBox.Items.Add('atl-dc-006')
[void] $listBox.Items.Add('atl-dc-007')
$form.Controls.Add($listBox)
$form.Topmost = $true
$result = $form.ShowDialog()
$x = $listBox.SelectedItem
$x
The script begins by loading two .NET Framework classes: System.Drawing and
System.Windows.Forms. You then start a new instance of the .NET Framework class
System.Windows.Forms.Form. That provides a blank form or window to which you can
start adding
controls.
PowerShell
After you create an instance of the Form class, assign values to three properties of this
class.
PowerShell
$form.Text = 'Select a Computer'
$form.StartPosition = 'CenterScreen'
Next, create an OK button for your form. Specify the size and behavior of the OK button.
In
this example, the button position is 120 pixels from the form's top edge, and 75 pixels
from the
left edge. The button height is 23 pixels, while the button length is 75 pixels.
The script uses
predefined Windows Forms types to determine the button behaviors.
PowerShell
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)
Similarly, you create a Cancel button. The Cancel button is 120 pixels from the top, but
150
pixels from the left edge of the window.
PowerShell
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)
Next, provide label text on your window that describes the information you want users
to provide. In
this case, you want users to select a computer.
PowerShell
$form.Controls.Add($label)
Add the control (in this case, a list box) that lets users provide the information you've
described
in your label text. There are many other controls you can apply besides list
boxes; for more
controls, see System.Windows.Forms Namespace.
PowerShell
$listBox.Height = 80
In the next section, you specify the values you want the list box to display to users.
7 Note
The list box created by this script allows only one selection. To create a list box
control that allows multiple selections, specify a value for the SelectionMode
property,
similarly to the following: $listBox.SelectionMode = 'MultiExtended' . For
more information, see
Multiple-selection List Boxes.
PowerShell
[void] $listBox.Items.Add('atl-dc-001')
[void] $listBox.Items.Add('atl-dc-002')
[void] $listBox.Items.Add('atl-dc-003')
[void] $listBox.Items.Add('atl-dc-004')
[void] $listBox.Items.Add('atl-dc-005')
[void] $listBox.Items.Add('atl-dc-006')
[void] $listBox.Items.Add('atl-dc-007')
Add the list box control to your form, and instruct Windows to open the form atop other
windows and
dialog boxes when it's opened.
PowerShell
$form.Controls.Add($listBox)
$form.Topmost = $true
PowerShell
$result = $form.ShowDialog()
Finally, the code inside the If block instructs Windows what to do with the form after
users
select an option from the list box, and then click the OK button or press the Enter
key.
PowerShell
$x = $listBox.SelectedItem
$x
See also
GitHub: Dave Wyatt's WinFormsExampleUpdates
Windows PowerShell Tip of the Week: Selecting Items from a List Box
Just Enough Administration
Article • 11/17/2022
Highly privileged accounts used to administer your servers pose a serious security risk.
Should an
attacker compromise one of these accounts, they could launch lateral
attacks across your
organization. Each compromised account gives an attacker access
to even more accounts and resources,
and puts them one step closer to stealing
company secrets, launching a denial-of-service attack, and
more.
It's not always easy to remove administrative privileges, either. Consider the common
scenario where
the DNS role is installed on the same machine as your Active Directory
Domain Controller. Your DNS
administrators require local administrator privileges to fix
issues with the DNS server. But to do
so, you must make them members of the highly
privileged Domain Admins security group. This
approach effectively gives DNS
Administrators control over your whole domain and access to all
resources on that
machine.
JEA addresses this problem through the principle of Least Privilege. With JEA, you can
configure
a management endpoint for DNS administrators that gives them access only
to the PowerShell commands
they need to get their job done. This means you can
provide the appropriate access to repair a
poisoned DNS cache or restart the DNS server
without unintentionally giving them rights to Active
Directory, or to browse the file
system, or run potentially dangerous scripts. Better yet, when the
JEA session is
configured to use temporary privileged virtual accounts, your DNS administrators can
connect to the server using non-admin credentials and still run commands that typically
require
admin privileges. JEA enables you to remove users from widely privileged
local/domain administrator
roles and carefully control what they can do on each
machine.
Next steps
To learn more about the requirements to use JEA, see the Prerequisites article.
Just Enough Administration is a feature included in PowerShell 5.0 and higher. This
article
describes the prerequisites that must be satisfied to start using JEA.
PowerShell
$PSVersionTable.PSVersion
Output
5 1 14393 1000
JEA is available with PowerShell 5.0 and higher. For full functionality, it's recommended
that you
install the latest version of PowerShell available for your system. The following
table describes
JEA's availability on Windows Server:
2 The following JEA features aren't supported on Windows 10 versions 1511 and
1603:
Running as a group-managed service account
Conditional access rules in session configurations
The user drive
Granting access to local user accounts
To get support for these features, update Windows to version 1607 (Anniversary
Update) or higher.
It's recommended that you test your workload's compatibility with WMF before
upgrading all of your
servers.
Windows 10 users should install the latest feature updates to obtain the current version
of Windows
PowerShell.
PowerShell Remoting is enabled by default on Windows Server 2012, 2012 R2, and 2016.
You can enable
PowerShell Remoting by running the following command in an elevated
PowerShell window.
PowerShell
Enable-PSRemoting
You can configure the PowerShell Module Logging policy using Group Policy.
1. Open the Local Group Policy Editor on a workstation or a Group Policy Object in
the Group Policy
Management Console on an Active Directory Domain Controller
2. Navigate to Computer Configuration\Administrative Templates\Windows
Components\Windows
PowerShell
3. Double-click on Turn on Module Logging
4. Click Enabled
5. In the Options section, click on Show next to Module Names
6. Type * in the pop-up window to log commands from all modules.
7. Click OK to set the policy
8. Double-click on Turn on PowerShell Script Block Logging
9. Click Enabled
10. Click OK to set the policy
11. (On domain-joined machines only) Run gpupdate or wait for Group Policy to
process the updated
policy and apply the settings
You can also enable system-wide PowerShell transcription through Group Policy.
Next steps
Create a role capability file
Create a session configuration file
See also
WinRM Security
PowerShell ♥ the Blue Team
JEA Role Capabilities
Article • 02/02/2023
When creating a JEA endpoint, you need to define one or more role capabilities that
describe what
someone can do in a JEA session. A role capability is a PowerShell data
file with the .psrc
extension that lists all the cmdlets, functions, providers, and external
programs that are made
available to connecting users.
How you go about this process depends on your organization and goals. The following
tips can help
ensure you're on the right path.
1. Identify the commands users are using to get their jobs done. This may involve
surveying IT
staff, checking automation scripts, or analyzing PowerShell session
transcripts and logs.
2. Update use of command-line tools to PowerShell equivalents, where possible, for
the best
auditing and JEA customization experience. External programs can't be
constrained as granularly
as native PowerShell cmdlets and functions in JEA.
3. Restrict the scope of the cmdlets to only allow specific parameters or parameter
values. This
is especially important if users should manage only part of a system.
4. Create custom functions to replace complex commands or commands that are
difficult to
constrain in JEA. A simple function that wraps a complex command or
applies additional validation
logic can offer additional control for admins and end-
user simplicity.
5. Test the scoped list of allowable commands with your users or automation
services, and adjust
as necessary.
Essential information required for user successCommands in a JEA session are often
run with
elevated privileges.
The following list contains examples of commands that can be used maliciously if
allowed in an
unconstrained state. This isn't an exhaustive list and should only be used
as a cautionary starting
point.
Example:
PowerShell
Related commands:
Add-ADGroupMember
Add-LocalGroupMember
net.exe
dsadd.exe
Example:
PowerShell
Related commands:
Start-Process
New-Service
Invoke-Item
Invoke-WmiMethod
Invoke-CimMethod
Invoke-Expression
Invoke-Command
New-ScheduledTask
Register-ScheduledJob
PowerShell
You should edit the created role capability file to allow only the commands required for
the role.
The PowerShell help documentation contains several examples of how you can
configure the file.
PowerShell
Sometimes the scope of a specific cmdlet or function is too broad for your users' needs.
A DNS
admin, for example, may only need access to restart the DNS service. In multi-
tenant environments,
tenants have access to self-service management tools. Tenants
should be limited to managing their
own resources. For these cases, you can restrict
which parameters are exposed from the cmdlet or
function.
PowerShell
VisibleCmdlets = @{
Name = 'Restart-Computer'
In more advanced scenarios, you may also need to restrict the values a user may use
with these
parameters. Role capabilities let you define a set of values or a regular
expression pattern that
determine what input is allowed.
PowerShell
VisibleCmdlets = @(
@{
Name = 'Restart-Service'
@{
Name = 'Start-Website'
7 Note
The common PowerShell parameters are always allowed, even if you restrict the
available
parameters. You shouldn't explicitly list them in the Parameters field.
The list below describes the various ways you can customize a visible cmdlet or function.
You can
mix and match any of the below in the VisibleCmdlets field.
Use case: Allow the user to run My-Func without any restrictions on the
parameters.
PowerShell
@{ Name = 'My-Func' }
Use case: Allow the user to run My-Func from the module MyModule without any
restrictions on the parameters.
PowerShell
@{ Name = 'MyModule\My-Func' }
Use case: Allow the user to run any cmdlet or function with the verb My .
PowerShell
@{ Name = 'My-*' }
Use case: Allow the user to run any cmdlet or function with the noun Func .
PowerShell
@{ Name = '*-Func' }
Use case: Allow the user to run My-Func with the Param1 and Param2 parameters.
Any
value can be supplied to the parameters.
PowerShell
Use case: Allow the user to run My-Func with the Param1 parameter. Only Value1
and
Value2 can be supplied to the parameter.
PowerShell
@{
Name = 'My-Func'
Use case: Allow the user to run My-Func with the Param1 parameter. Any value
starting
with contoso can be supplied to the parameter.
PowerShell
@{
Name = 'My-Func'
2 Warning
For best security practices, it isn't recommended to use wildcards when defining
visible cmdlets
or functions. Instead, you should explicitly list each trusted
command to ensure no other commands
that share the same naming scheme are
unintentionally authorized.
You can't apply both a ValidatePattern and ValidateSet to the same cmdlet or function.
PowerShell
VisibleExternalCommands = @(
'C:\Windows\System32\whoami.exe'
'C:\Program Files\Contoso\Scripts\UpdateITSoftware.ps1'
Where possible, use PowerShell cmdlet or function equivalents for any external
executables you
authorize since you have control over the parameters allowed with
PowerShell cmdlets and functions.
Many executables allow you to read the current state and then change it by providing
different
parameters.
For example, consider the role of a file server admin that manages network shares
hosted on a
system. One way of managing shares is to use net share . However,
allowing net.exe is dangerous
because the user could use the command to gain admin
privileges with the command
net group Administrators unprivilegedjeauser /add . A
more secure option is to allow the
Get-SmbShare cmdlet, which achieves the same
result but has a much more limited scope.
When making external commands available to users in a JEA session, always specify the
complete path
to the executable. This prevents the execution of similarly named and
potentially malicious programs
located elsewhere on the system.
When necessary, you can allow access to the PowerShell providers using the
VisibleProviders
command. For a full list of providers, run Get-PSProvider .
PowerShell
VisibleProviders = 'Registry'
For simple tasks that require access to the file system, registry, certificate store, or other
sensitive providers, consider writing a custom function that works with the provider on
the user's
behalf. The functions, cmdlets, and external programs available in a JEA
session aren't subject to
the same constraints as JEA. They can access any provider by
default. Also consider using the
user drive when users need to copy files to or from a
JEA endpoint.
PowerShell
VisibleFunctions = 'Get-TopProcess'
FunctionDefinitions = @{
Name = 'Get-TopProcess'
ScriptBlock = {
param($Count = 10)
Get-Process |
) Important
Don't forget to add the name of your custom functions to the VisibleFunctions
field so they
can be run by the JEA users.
The body (script block) of custom functions runs in the default language mode for the
system and
isn't subject to JEA's language constraints. This means that functions can
access the file system
and registry, and run commands that weren't made visible in the
role capability file. Take care to
avoid running arbitrary code when using parameters.
Avoid piping user input directly into cmdlets
like Invoke-Expression .
In the above example, notice that the fully qualified module name (FQMN)
Microsoft.PowerShell.Utility\Select-Object was used instead of the shorthand
Select-Object .
Functions defined in role capability files are still subject to the scope of
By default, Select-Object is a constrained cmdlet in all JEA sessions that doesn't allow
the
selection of arbitrary properties on objects. To use the unconstrained Select-Object
in functions,
you must explicitly request the full implementation using the FQMN. Any
constrained cmdlet in a JEA
session has the same constraints when invoked from a
function. For more information, see
about_Command_Precedence.
If you're writing several custom functions, it's more convenient to put them in a
PowerShell script
module. You make those functions visible in the JEA session using the
VisibleFunctions field
like you would with built-in and third-party modules.
For tab completion to work properly in JEA sessions you must include the built-in
function
tabexpansion2 in the VisibleFunctions list.
folder included
in the $env:PSModulePath environment variable, however you shouldn't
place it in
$env:SystemRoot\System32 or a folder where untrusted users could modify the
files.
The following example creates a PowerShell script module called ContosoJEA in the
$env:ProgramFiles path to host the role capabilities file.
PowerShell
# At least one file in the module folder must have the same name as the
folder itself.
This is why controlling access to the role capabilities folder is so important. Only highly
trusted
administrators should be allowed to change role capability files. If an untrusted
user can change
role capability files, they can easily give themselves access to cmdlets
that allow them to elevate
their privileges.
For administrators looking to lock down access to the role capabilities, ensure Local
System has
read-only access to the role capability files and containing modules.
PowerShell
$roleA = @{
VisibleCmdlets = @(
'Get-Service'
@{
Name = 'Restart-Service'
$roleB = @{
VisibleCmdlets = @(
@{
Name = 'Get-Service';
@{
Name = 'Restart-Service'
$mergedAandB = @{
VisibleCmdlets = @(
'Get-Service'
@{
Name = 'Restart-Service';
Parameters = @{
Name = 'DisplayName'
VisibleExternalCommands, VisibleAliases,
VisibleProviders, ScriptsToProcess
All other fields in the role capability file are added to a cumulative set of allowable
external
commands, aliases, providers, and startup scripts. Any command, alias, provider,
or script available
in one role capability is available to the JEA user.
Be careful to ensure that the combined set of providers from one role capability and
cmdlets/functions/commands from another don't allow users unintentional access to
system resources.
For example, if one role allows the Remove-Item cmdlet and another
allows the FileSystem
provider, you are at risk of a JEA user deleting arbitrary files on
your computer. Additional
information about identifying users' effective permissions can
be found in the auditing JEA
article.
Next steps
Create a session configuration file
JEA Session Configurations
Article • 11/17/2022
These options are defined in a PowerShell data file with a .pssc extension known as a
PowerShell
session configuration file. The session configuration file can be edited using
any text editor.
PowerShell
Tip
Only the most common configuration options are included in the template file by
default. Use the
-Full switch to include all applicable settings in the generated
PSSC.
Get-Command ( gcm )
Get-FormatData
Get-Help
Measure-Object ( measure )
Out-Default
Select-Object ( select )
No PowerShell providers are available, nor are any external programs (executables or
scripts).
PowerShell
RunAsVirtualAccount = $true
If the roles defined by the session configuration don't require full administrative
privilege, you
can specify the security groups to which the virtual account will belong.
On a member server or
workstation, the specified security groups must be local groups,
not groups from a domain.
When one or more security groups are specified, the virtual account isn't assigned to
the local or
domain administrators group.
PowerShell
# Setting the session to use a virtual account that only belongs to the
NetworkOperator and NetworkAuditor local groups
RunAsVirtualAccount = $true
7 Note
Virtual accounts are temporarily granted the Logon as a service right in the local
server security
policy. If one of the VirtualAccountGroups specified has already
been granted this right in the
policy, the individual virtual account will no longer be
added and removed from the policy. This
can be useful in scenarios such as domain
controllers where revisions to the domain controller
security policy are closely
audited. This is only available in Windows Server 2016 with the
November 2018 or
later rollup and Windows Server 2019 with the January 2019 or later rollup.
PowerShell
# Configure JEA sessions to use the GMSA in the local computer's domain
GroupManagedServiceAccount = 'Domain\MyJEAGMSA'
It's difficult to trace back actions to a user when using a GMSA. Every user shares
the same
run-as identity. You must review PowerShell session transcripts and logs
to correlate individual
users with their actions.
The GMSA may have access to many network resources that the connecting user
doesn't need
access to. Always try to limit effective permissions in a JEA session to
follow the principle of
least privilege.
7 Note
Group managed service accounts are only available on domain-joined machines
using PowerShell 5.1
or newer.
Session transcripts
It's recommended that you configure a JEA endpoint to automatically record transcripts
of users'
sessions. PowerShell session transcripts contain information about the
connecting user, the run as
identity assigned to them, and the commands run by the
user. They can be useful to an auditing team
who needs to understand who made a
specific change to a system.
PowerShell
TranscriptDirectory = 'C:\ProgramData\JEAConfiguration\Transcripts'
Transcripts are written to the folder by the Local System account, which requires read
and write
access to the directory. Standard users should have no access to the folder.
Limit the number of
security administrators that have access to audit the transcripts.
User drive
If your connecting users need to copy files to or from the JEA endpoint, you can enable
the user
drive in the session configuration file. The user drive is a PSDrive that's mapped
to a unique
folder for each connecting user. This folder allows users to copy files to or
from the system
without giving them access to the full file system or exposing the
FileSystem provider. The user
drive contents are persistent across sessions to
accommodate situations where network connectivity
may be interrupted.
PowerShell
MountUserDrive = $true
By default, the user drive allows you to store a maximum of 50MB of data per user. You
can limit the
amount of data a user can consume with the UserDriveMaximumSize field.
PowerShell
# Enables the user drive with a per-user limit of 500MB (524288000 bytes)
MountUserDrive = $true
UserDriveMaximumSize = 524288000
If you don't want data in the user drive to be persistent, you can configure a scheduled
task on
the system to automatically clean up the folder every night.
7 Note
Role definitions
Role definitions in a session configuration file define the mapping of users to roles.
Every
user or group included in this field is granted permission to the JEA endpoint
when it's registered.
Each user or group can be included as a key in the hashtable only
once, but can be assigned multiple
roles. The name of the role capability should be the
name of the role capability file, without the
.psrc extension.
PowerShell
RoleDefinitions = @{
If a user belongs to more than one group in the role definition, they get access to the
roles of
each. When two roles grant access to the same cmdlets, the most permissive
parameter set is granted
to the user.
When specifying local users or groups in the role definitions field, be sure to use the
computer
name, not localhost or wildcards. You can check the computer name by
inspecting the
$env:COMPUTERNAME variable.
PowerShell
RoleDefinitions = @{
JEA uses the $env:PSModulePath environment variable to determine which paths to scan
for role
capability files. Within each of those paths, JEA looks for valid PowerShell
modules that contain a
"RoleCapabilities" subfolder. As with importing modules, JEA
prefers role capabilities that are
shipped with Windows to custom role capabilities with
the same name.
For all other naming conflicts, precedence is determined by the order in which Windows
enumerates
the files in the directory. The order isn't guaranteed to be alphabetical. The
first role capability
file found that matches the specified name is used for the connecting
user. Since the role
capability search order isn't deterministic, it's strongly
recommended that role capabilities
have unique filenames.
PowerShell
# The 2 factor authentication group name is "2FA-logon" and the smart card
group
# name is "smartcard-logon"
7 Note
Other properties
Session configuration files can also do everything a role capability file can do, just
without the
ability to give connecting users access to different commands. If you want
to allow all users access
to specific cmdlets, functions, or providers, you can do so right
in the session configuration file.
For a full list of supported properties in the session
configuration file, run
Get-Help New-PSSessionConfigurationFile -Full .
PowerShell
$roles = @{
$parameters = @{
SessionType = 'RestrictedRemoteServer'
Path = '.\JEAConfig.pssc'
RunAsVirtualAccount = $true
TranscriptDirectory = 'C:\ProgramData\JEAConfiguration\Transcripts'
RoleDefinitions = $roles
New-PSSessionConfigurationFile @parameters
Next steps
Register a JEA configuration
Author JEA roles
Registering JEA Configurations
Article • 11/17/2022
Once you have your role capabilities and session configuration file created, the last
step
is to register the JEA endpoint. Registering the JEA endpoint with the system makes the
endpoint available for use by users and automation engines.
Before you begin, ensure that the following prerequisites have been met:
One or more roles has been created and placed in the RoleCapabilities folder of a
PowerShell
module.
A session configuration file has been created and tested.
The user registering the JEA configuration has administrator rights on the system.
You've selected a name for your JEA endpoint.
The name of the JEA endpoint is required when users connect to the system using JEA.
The
Get-PSSessionConfiguration cmdlet lists the names of the endpoints on a system.
Endpoints that
start with microsoft are typically shipped with Windows. The
microsoft.powershell endpoint is
the default endpoint used when connecting to a
remote PowerShell endpoint.
PowerShell
Output
Name
----
microsoft.powershell
microsoft.powershell.workflow
microsoft.powershell32
PowerShell
Register-PSSessionConfiguration -Path .\MyJEAConfig.pssc -Name
'JEAMaintenance' -Force
2 Warning
The previous command restarts the WinRM service on the system. This terminates
all PowerShell
remoting sessions and any ongoing DSC configurations. We
recommended you take production machines
offline before running the command
to avoid disrupting business operations.
After registration, you're ready to use JEA. You may delete the session configuration file
at
any time. The configuration file isn't used after registration of the endpoint.
To deploy JEA with DSC, ensure the following prerequisites are met:
One or more role capabilities have been authored and added to a PowerShell
module.
The PowerShell module containing the roles is stored on a (read-only) file share
accessible by
each machine.
Settings for the session configuration have been determined. You don't need to
create a session
configuration file when using the JEA DSC resource.
You have credentials that allow administrative actions on each machine or access
to the DSC pull
server used to manage the machines.
You've downloaded the JEA DSC resource .
Create a DSC configuration for your JEA endpoint on a target machine or pull server. In
this
configuration, the JustEnoughAdministration DSC resource defines the session
configuration file
and the File resource copies the role capabilities from the file share.
Role Definitions
Virtual account groups
Group-managed service account name
Transcript directory
User drive
Conditional access rules
Startup scripts for the JEA session
The syntax for each of these properties in a DSC configuration is consistent with the
PowerShell
session configuration file.
PowerShell
Configuration JEAMaintenance
File MaintenanceModule
SourcePath = "\\myfileshare\JEA\ContosoMaintenance"
DestinationPath = "C:\Program
Files\WindowsPowerShell\Modules\ContosoMaintenance"
Checksum = "SHA-256"
Ensure = "Present"
Type = "Directory"
Recurse = $true
JeaEndpoint JEAMaintenanceEndpoint
EndpointName = "JEAMaintenance"
TranscriptDirectory = 'C:\ProgramData\JEAConfiguration\Transcripts'
DependsOn = '[File]MaintenanceModule'
The DSC resource also allows you to replace the default Microsoft.PowerShell endpoint.
When
replaced, the resource automatically registers a backup endpoint named
Microsoft.PowerShell.Restricted. The backup endpoint has the default WinRM ACL that
allows
Remote Management Users and local Administrators group members to access it.
Unregistering JEA configurations
The Unregister-PSSessionConfiguration cmdlet removes a JEA endpoint. Unregistering a
JEA
endpoint prevents new users from creating new JEA sessions on the system. It also
allows you to
update a JEA configuration by re-registering an updated session
configuration file using the same
endpoint name.
PowerShell
2 Warning
Unregistering a JEA endpoint causes the WinRM service to restart. This interrupts
most remote
management operations in progress, including other PowerShell
sessions, WMI invocations, and some
management tools. Only unregister
PowerShell endpoints during planned maintenance windows.
Next steps
Test the JEA endpoint
Using JEA
Article • 02/08/2023
This article describes the various ways you can connect to and use a JEA endpoint.
The name of the computer you're connecting to (can be the local machine)
The name of the JEA endpoint registered on that computer
Credentials that have access to the JEA endpoint on that computer
Given that information, you can start a JEA session using the New-PSSession or
Enter-
PSSession cmdlets.
PowerShell
$sessionParams = @{
ComputerName = 'localhost'
ConfigurationName = 'JEAMaintenance'
Credential = Get-Credential
Enter-PSSession @sessionParams
If the current user account has access to the JEA endpoint, you can omit the Credential
parameter.
When the PowerShell prompt changes to [localhost]: PS> you know that you're now
interacting with
the remote JEA session. You can run Get-Command to check which
commands are available. Consult
with your administrator to learn if there are any
restrictions on the available parameters or
allowed parameter values.
Remember, JEA sessions operate in NoLanguage mode. Some of the ways you typically
use PowerShell
may not be available. For instance, you can't use variables to store data
or inspect the properties
on objects returned from cmdlets. The following example
shows two approaches to get the same
commands to work in NoLanguage mode.
PowerShell
# You can use pipes to pass data through to commands that accept input from
the pipeline
# You can also wrap subcommands in parentheses and enter them inline as
arguments
# You can also use parameter sets that don't require extra data to be passed
in
For more complex command invocations that make this approach difficult, consider
using
implicit remoting or creating custom functions that wrap the functionality you
require.
For more information on NoLanguageMode , see about_Language_Modes.
Implicit remoting works by importing cmdlets from an existing PowerShell session. You
can optionally
choose to prefix the nouns of each proxy cmdlet with a string of your
choosing. The prefix allows
you to distinguish the commands that are for the remote
system. A temporary script module containing
all the proxy commands is created and
imported for the duration of your local PowerShell session.
PowerShell
# Import the entire PSSession and prefix each imported cmdlet with "JEA"
# Invoke "Get-Command" on the remote JEA endpoint using the proxy cmdlet
Get-JEACommand
) Important
Some systems may not be able to import an entire JEA session due to constraints in
the default JEA
cmdlets. To get around this, only import the commands you need
from the JEA session by explicitly
providing their names to the -CommandName
parameter. A future update will address the issue with
importing entire JEA sessions
on affected systems.
If you're unable to import a JEA session because of JEA constraints on the default
parameters,
follow the steps below to filter out the default commands from the
imported set. You can continue
use commands like Select-Object , but you'll just use
the local version installed on your computer
instead of the one imported from the
remote JEA session.
PowerShell
$jeaDefaultCmdlets = @(
'Clear-Host'
'Exit-PSSession'
'Get-Command'
'Get-FormatData'
'Get-Help'
'Measure-Object'
'Out-Default'
'Select-Object'
# Import only commands explicitly added in role capabilities and prefix each
You can also persist the proxied cmdlets from implicit remoting using Export-PSSession.
For
more information about implicit remoting, see the documentation for Import-
PSSession and
Import-Module.
For simple, one-off tasks, you can use Invoke-Command to run commands in a JEA
session.
PowerShell
Get-Process
Get-Service
To check which commands are available for use when you connect to a JEA session, run
Get-Command
and iterate through the results to check for the allowed parameters.
PowerShell
$commandParameters = @{
ComputerName = 'SERVER01'
ConfigurationName = 'JEAMaintenance'
ScriptBlock = { Get-Command }
Invoke-Command @commandParameters |
If you're building a C# app, you can create a PowerShell runspace that connects to a JEA
session by
specifying the configuration name in a WSManConnectionInfo object.
C#
// using System.Management.Automation;
// See
https://learn.microsoft.com/dotnet/api/system.management.automation.pscreden
tial
string.Format(
CultureInfo.InvariantCulture,
"http://schemas.microsoft.com/powershell/{0}",
configName
),
creds // Credentials
);
// Now, use the connection info to create a runspace where you can run the
commands
runspace.Open();
ps.Runspace = runspace;
ps.AddCommand("Get-Command");
Console.WriteLine(result);
runspace.Close();
You can use PowerShell Direct with JEA to give a Hyper-V administrator limited access to
your VM.
This can be useful if you lose network connectivity to your VM and need a
datacenter admin to fix
the network settings.
No additional configuration is required to use JEA over PowerShell Direct. However, the
guest
operating system running inside the virtual machine must be Windows 10,
Windows Server 2016, or
higher. The Hyper-V admin can connect to the JEA endpoint
by using the -VMName or -VMId
parameters on PSRemoting cmdlets:
PowerShell
$sharedParams = @{
ConfigurationName = 'NICMaintenance'
# Entering a JEA session using PowerShell Direct when the VM name is unique
It's recommended you create a dedicated user account with the minimum rights needed
to manage the
system for use by a Hyper-V administrator. Remember, even an
unprivileged user can sign into a
Windows machine by default, including using
unconstrained PowerShell. That allows them to browse the
file system and learn more
about your OS environment. To lock down a Hyper-V administrator and limit
them to
only access a VM using PowerShell Direct with JEA, you must deny local logon rights to
the
Hyper-V admin's JEA account.
JEA Security Considerations
Article • 11/17/2022
JEA helps you improve your security posture by reducing the number of permanent
administrators on
your machines. JEA uses a PowerShell session configuration to create
a new entry point for users to
manage the system. Users who need elevated, but not
unlimited, access to the machine to do
administrative tasks can be granted access to the
JEA endpoint. Since JEA allows these users to run
admin commands without having full
admin access, you can then remove those users from highly
privileged security groups.
Run-As account
Each JEA endpoint has a designated run-as account. This is the account under which the
connecting user's actions are executed. This account is configurable in the
session
configuration file, and the account you choose has a significant bearing on the
security
of your endpoint.
Virtual accounts are the recommended way of configuring the run-as account. Virtual
accounts
are one-time, temporary local accounts that are created for the connecting
user to use during the
duration of their JEA session. As soon as their session is
terminated, the virtual account is
destroyed and can't be used anymore. The connecting
user doesn't know the credentials for the
virtual account. The virtual account can't be
used to access the system via other means like
Remote Desktop or an unconstrained
PowerShell endpoint.
By default, virtual accounts belong to the local Administrators group on the machine.
This gives
them full rights to manage anything on the system, but no rights to manage
resources on the network.
When authenticating with other machines, the user context is
that of the local computer account, not
the virtual account.
Domain controllers are a special case since there isn't a local Administrators group.
Instead,
virtual accounts belong to Domain Admins and can manage the directory
services on the domain
controller. The domain identity is still restricted for use on the
domain controller where the JEA
session was instantiated. Any network access appears
to come from the domain controller computer
object instead.
In both cases, you may explicitly define which security groups the virtual account
belongs to. This
is a good practice when the task can be done without local or domain
admin privileges. If you
already have a security group defined for your admins, grant the
virtual account membership to that
group. Virtual account group membership is limited
to local security groups on workstation and
member servers. On domain controllers,
virtual accounts must be members of domain security groups.
Once the virtual account
has been added to one or more security groups, it no longer belongs to the
default
groups (local or domain admins).
The following table summarizes the possible configuration options and resulting
permissions for
virtual accounts:
When you look at security audit events and application event logs, you see that each
JEA user
session has a unique virtual account. This unique account helps you track user
actions in a JEA
endpoint back to the original user who ran the command. Virtual
account names follow the format
WinRM Virtual
Users\WinRM_VA_<ACCOUNTNUMBER>_<DOMAIN>_<sAMAccountName> For example, if user
Alice in
domain Contoso restarts a service in a JEA endpoint, the username associated with
any
service control manager events would be WinRM Virtual
Users\WinRM_VA_1_contoso_alice .
Group-managed service accounts (gMSAs) are useful when a member server needs to
have access to
network resources in the JEA session. For example, when a JEA endpoint
is used to control access to
a REST API service hosted on a different machine. It's easy to
write functions to invoke the REST
APIs, but you need a network identity to authenticate
with the API. Using a group-managed service
account makes the second hop possible
while maintaining control over which computers can use the
account. The effective
permissions of the gMSA are defined by the security groups (local or domain)
to which
the gMSA account belongs.
When a JEA endpoint is configured to use a gMSA, the actions of all JEA users appear to
come from
the same gMSA. The only way to trace actions back to a specific user is to
identify the set of
commands run in a PowerShell session transcript.
Pass-thru credentials are used when you don't specify a run-as account. PowerShell
uses the
connecting user's credential to run commands on the remote server. This
requires you to grant the
connecting user direct access to privileged management
groups. This configuration is not
recommended for JEA. If the connecting user already
has admin privileges, they can avoid JEA and
manage the system via other,
unconstrained means. For more information, see the section below on how
JEA doesn't
protect against admins.
Standard run-as accounts allow you to specify any user account under which the entire
PowerShell
session runs. Session configurations using fixed run-as accounts (with the -
RunAsCredential
parameter) aren't JEA-aware. Role definitions no longer function as
You shouldn't use a RunAsCredential on a JEA endpoint because it's difficult to trace
actions
back to specific users and lacks support for mapping users to roles.
By default, when a JEA endpoint has multiple role capabilities, the WinRM ACL is
configured to allow
access to all mapped users. For example, a JEA session configured
using the following commands
grants full access to CONTOSO\JEA_Lev1 and
CONTOSO\JEA_Lev2 .
PowerShell
PowerShell
Output
Permission
----------
CONTOSO\JEA_Lev1 AccessAllowed
CONTOSO\JEA_Lev2 AccessAllowed
It's possible to create a JEA endpoint that doesn't map a defined role to every user that
has
access. These users can start a JEA session, but only have access to the default
cmdlets. You can
audit user permissions in a JEA endpoint by running Get-
PSSessionCapability . For more information,
see Auditing and Reporting on JEA.
PowerShell
@{
VisibleCmdlets = 'Microsoft.PowerShell.Management\*-Process'
This role capability allows users to run any PowerShell cmdlet with the noun Process
from the
Microsoft.PowerShell.Management module. Users may need to access
cmdlets like Get-Process to
see what applications are running on the system and Stop-
Process to kill applications that aren't
responding. However, this entry also allows
Start-Process , which can be used to start up an
arbitrary program with full
A more secure version of this same role capability would look like:
PowerShell
@{
VisibleCmdlets = 'Microsoft.PowerShell.Management\Get-Process',
'Microsoft.PowerShell.Management\Stop-Process'
A common practice is to use JEA for regular day-to-day maintenance and have a just-in-
time,
privileged access management solution that allows users to temporarily become
local admins in
emergency situations. This helps ensure users aren't permanent admins
on the system, but can get
those rights if, and only when, they complete a workflow that
documents their use of those
permissions.
Auditing and Reporting on JEA
Article • 11/17/2022
After you've deployed JEA, you need to regularly audit the JEA configuration. Auditing
helps you
assess that the correct people have access to the JEA endpoint and their
assigned roles are still
appropriate.
PowerShell
Output
Name : JEAMaintenance
PSVersion : 5.1
StartupScript :
RunAsUser :
CONTOSO\JEA_DNS_AUDITORS AccessAllowed
The effective rights for the endpoint are listed in the Permission property. These users
have
the right to connect to the JEA endpoint. However, the roles and commands they
have access to is
determined by the RoleDefinitions property in the session
configuration file that was used
to register the endpoint. Expand the RoleDefinitions
property to evaluate the role mappings in a
registered JEA endpoint.
PowerShell
Expression = { $_.Value.RoleCapabilities }
PowerShell
function Find-LocalRoleCapability {
$results = @()
if (Test-Path $psrcpath) {
} | Sort-Object Name
7 Note
The order of results from this function isn't necessarily the order in which the role
capabilities
will be selected if multiple role capabilities share the same name.
PowerShell
Get-PSSessionCapability -ConfigurationName 'JEAMaintenance' -Username
'CONTOSO\Alice'
If your users aren't permanent members of groups that would grant them additional JEA
rights, this
cmdlet may not reflect those extra permissions. This happens when using
just-in-time privileged
access management systems to allow users to temporarily belong
to a security group. Carefully
evaluate the mapping of users to roles and capabilities to
ensure that users only get the level of
access needed to do their jobs successfully.
Each event log entry includes information about the session in which the command was
run. For JEA
sessions, the event includes information about the ConnectedUser and the
RunAsUser. The
ConnectedUser is the actual user who created the JEA session. The
RunAsUser is the account
JEA used to execute the command.
Application event logs show changes being made by the RunAsUser. So having module
and script
logging enabled is required to trace a specific command invocation back to
the ConnectedUser.
The WinRM log can also help you correlate run-as users to the connecting user in an
application
event log. Event ID 193 in the Microsoft-Windows-Windows Remote
Management/Operational log
records the security identifier (SID) and account name for
both the connecting user and run as user
for every new JEA session.
Session transcripts
If you configured JEA to create a transcript for each user session, a text copy of every
user's
actions are stored in the specified folder.
PowerShell
Get-PSSessionConfiguration |
Each transcript starts with information about the time the session started, which user
connected to
the session, and which JEA identity was assigned to them.
**********************
Username: CONTOSO\Alice
[...]
The body of the transcript contains information about each command the user invoked.
The exact
syntax of the command used is unavailable in JEA sessions because of the way
commands are
transformed for PowerShell remoting. However, you can still determine
the effective command that was
executed. Below is an example transcript snippet from a
user running Get-Service Dns in a JEA
session:
PS>CommandInvocation(Get-Service): "Get-Service"
See also
PowerShell ♥ the Blue Team blog post on security
Running Remote Commands
Article • 11/17/2022
You can run commands on one or hundreds of computers with a single PowerShell
command. Windows
PowerShell supports remote computing by using various
technologies, including WMI, RPC, and
WS-Management.
For more information about remoting in PowerShell, see the following articles:
Restart-Computer
Test-Connection
Clear-EventLog
Get-EventLog
Get-HotFix
Get-Process
Get-Service
Set-Service
Get-WinEvent
Get-WmiObject
Typically, cmdlets that support remoting without special configuration have the
ComputerName
parameter and don't have the Session parameter. To find these cmdlets
in your session, type:
PowerShell
Get-Command | Where-Object {
To use Windows PowerShell remoting, the remote computer must be configured for
remote management.
For more information, including instructions, see About Remote
Requirements.
Once you have configured Windows PowerShell remoting, many remoting strategies are
available to you.
This article lists just a few of them. For more information, see About
Remote.
PowerShell
Enter-PSSession Server01
The command prompt changes to display the name of the remote computer. Any
commands that you type at
the prompt run on the remote computer and the results are
displayed on the local computer.
PowerShell
Exit-PSSession
For more information about the Enter-PSSession and Exit-PSSession cmdlets, see:
Enter-PSSession
Exit-PSSession
Run a Remote Command
To run a command on one or more computers, use the Invoke-Command cmdlet. For
example, to run
a Get-UICulture command on the Server01 and Server02 remote
computers, type:
PowerShell
Output
Run a Script
To run a script on one or many remote computers, use the FilePath parameter of the
Invoke-Command
cmdlet. The script must be on or accessible to your local computer. The
results are returned to your
local computer.
For example, the following command runs the DiskCollect.ps1 script on the remote
computers, Server01
and Server02.
PowerShell
PowerShell
Now that the sessions are established, you can run any command in them. And because
the sessions are
persistent, you can collect data from one command and use it in
another command.
For example, the following command runs a Get-HotFix command in the sessions in the
$s variable and
it saves the results in the $h variable. The $h variable is created in each
of the sessions in $s,
but it doesn't exist in the local session.
PowerShell
Now you can use the data in the $h variable with other commands in the same session.
The results
are displayed on the local computer. For example:
PowerShell
Advanced Remoting
Windows PowerShell remote management just begins here. By using the cmdlets
installed with Windows
PowerShell, you can establish and configure remote sessions
both from the local and remote ends,
create customized and restricted sessions, allow
users to import commands from a remote session that
actually run implicitly on the
remote session, configure the security of a remote session, and much
more.
Windows PowerShell includes a WSMan provider. The provider creates a WSMAN: drive
that lets you
navigate through a hierarchy of configuration settings on the local
computer and remote computers.
For more information about the WSMan provider, see WSMan Provider and
About WS-
Management Cmdlets, or in the Windows PowerShell console, type Get-Help wsman .
Overview
PowerShell remoting normally uses WinRM for connection negotiation and data
transport. SSH is now
available for Linux and Windows platforms and allows true
multiplatform PowerShell remoting.
WinRM provides a robust hosting model for PowerShell remote sessions. SSH-based
remoting doesn't
currently support remote endpoint configuration and Just Enough
Administration (JEA).
SSH remoting lets you do basic PowerShell session remoting between Windows and
Linux computers. SSH
remoting creates a PowerShell host process on the target
computer as an SSH subsystem. Eventually
we'll implement a general hosting model,
similar to WinRM, to support endpoint configuration and
JEA.
To create a remote session, you specify the target computer with the HostName
parameter and
provide the user name with UserName. When running the cmdlets
interactively, you're prompted for
a password. You can also use SSH key authentication
using a private key file with the
KeyFilePath parameter. Creating keys for SSH
authentication varies by platform.
You can confirm that PowerShell has SSH remoting support by listing the New-
PSSession parameter
sets. You'll notice there are parameter set names that begin
PowerShell
(Get-Command New-PSSession).ParameterSets.Name
Output
Name
----
SSHHost
SSHHostHashParam
7 Note
If you want to set PowerShell as the default shell for OpenSSH, see
Configuring Windows for OpenSSH.
PasswordAuthentication yes
Create the SSH subsystem that hosts a PowerShell process on the remote
computer:
Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -nologo
7 Note
Starting in PowerShell 7.4, you no longer need to use the -nologo parameter
when running
PowerShell in SSH server mode.
7 Note
You must use the 8.3 short name for any file paths that contain spaces. There's
a bug in
OpenSSH for Windows that prevents spaces from working in
subsystem executable paths. For more
information, see this GitHub issue .
The 8.3 short name for the Program Files folder in Windows is usually
Progra~1 . However,
you can use the following command to make sure:
PowerShell
Select-Object EightDotThreeFileName
Output
EightDotThreeFileName
---------------------
c:\progra~1
PubkeyAuthentication yes
Restart-Service sshd
5. Add the path where OpenSSH is installed to your Path environment variable. For
example,
C:\Program Files\OpenSSH\ . This entry allows for the ssh.exe to be
found.
Bash
PasswordAuthentication yes
PubkeyAuthentication yes
For more information about creating SSH keys on Ubuntu, see the manpage for
ssh-keygen .
7 Note
7 Note
Starting in PowerShell 7.4, you no longer need to use the -nologo parameter
when running
PowerShell in SSH server mode.
Bash
Bash
PasswordAuthentication yes
7 Note
7 Note
Starting in PowerShell 7.4, you no longer need to use the -nologo parameter
when running
PowerShell in SSH server mode.
PubkeyAuthentication yes
Bash
Authentication
PowerShell remoting over SSH relies on the authentication exchange between the SSH
client and SSH
service and doesn't implement any authentication schemes itself. The
result is that any configured
authentication schemes including multi-factor
authentication are handled by SSH and independent of
PowerShell. For example, you
can configure the SSH service to require public key authentication and
a one-time
password for added security. Configuration of multi-factor authentication is outside the
scope of this documentation. Refer to documentation for SSH on how to correctly
configure
multi-factor authentication and validate it works outside of PowerShell before
attempting to use it
with PowerShell remoting.
7 Note
Users retain the same privileges in remote sessions. Meaning, Administrators have
access to an
elevated shell, and normal users will not.
Linux to Linux
PowerShell
Output
TestUser@UbuntuVM1s password:
PowerShell
$session
Output
PowerShell
Enter-PSSession $session
Output
PowerShell
Output
Linux to Windows
PowerShell
PTestName@WinVM1s password:
PowerShell
Output
Windows to Windows
PowerShell
C:\Users\PSUser\Documents>pwsh.exe
Output
PowerShell
PowerShell
Output
PSRemoteUser@WinVM2's password:
PowerShell
$session
Output
PowerShell
Enter-PSSession -Session $session
Output
Name Value
---- -----
PSEdition Core
SerializationVersion 1.1.0.1
BuildVersion 3.0.0.0
CLRVersion
PSVersion 6.0.0-alpha
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
GitCommitId v6.0.0-alpha.17
[WinVM2]: PS C:\Users\PSRemoteUser\Documents>
Limitations
The sudo command doesn't work in a remote session to a Linux computer.
PSRemoting over SSH doesn't support Profiles and doesn't have access to
$PROFILE . Once in a
session, you can load a profile by dot sourcing the profile with
the full filepath. This isn't
related to SSH profiles. You can configure the SSH server
to use PowerShell as the default shell
and to load a profile through SSH. See the
SSH documentation for more information.
Prior to PowerShell 7.1, remoting over SSH didn't support second-hop remote
sessions. This
capability was limited to sessions using WinRM. PowerShell 7.1
allows Enter-PSSession and
Enter-PSHostProcess to work from within any
interactive remote session.
See also
Installing PowerShell on Linux
Installing PowerShell on macOS
Installing PowerShell on Windows
Manage Windows with OpenSSH
Managing OpenSSH Keys
Ubuntu SSH
WS-Management (WSMan) Remoting in
PowerShell
Article • 11/17/2022
Motivation
An installation of PowerShell can establish PowerShell sessions to remote computers
using
New-PSSession and Enter-PSSession . To enable it to accept incoming PowerShell
remote
connections, the user must create a WinRM remoting endpoint. This is an
explicit opt-in scenario
where the user runs Install-PowerShellRemoting.ps1 to create the
WinRM endpoint. The installation
script is a short-term solution until we add additional
functionality to Enable-PSRemoting to
perform the same action. For more details, please
see issue #1193 .
Script Actions
The script
Registration
The script must be executed within an Administrator-level PowerShell session and runs
in two modes.
PowerShell
Install-PowerShellRemoting.ps1
PowerShell
For Example:
PowerShell
7 Note
The remoting registration script restarts WinRM. All existing PSRP sessions are
terminated
immediately after the script is run. If run during a remote session, the
script terminates the
connection.
the example
above, use either:
PowerShell
Since the release of PowerShell 6, support for remoting over WS-Management (WSMan)
on non-Windows
platforms has only been available to a limited set of Linux
distributions. All versions of those
distributions that supported WSMan are no longer
supported by the Linux vendors that created them.
Our plan for PowerShell 7.3 is to remove outdated libraries and supporting code for
non-Windows
platforms. WSMan-based remoting is still supported between Windows
systems. Remoting over SSH is
supported for all platforms. For more information, see
PowerShell remoting over SSH.
7 Note
PowerShell Remoting isn't the same as using the ComputerName parameter of a cmdlet
to run it on
a remote computer, which uses Remote Procedure Call (RPC) as its
underlying protocol.
HTTP: 5985
HTTPS: 5986
On private networks, the default Windows Firewall rule for PowerShell Remoting accepts
all
connections. On public networks, the default Windows Firewall rule allows PowerShell
Remoting
connections only from within the same subnet. You have to explicitly change
that rule to open
PowerShell Remoting to all connections on a public network.
2 Warning
The firewall rule for public networks is meant to protect the computer from
potentially malicious
external connection attempts. Use caution when removing this
rule.
Process isolation
PowerShell Remoting uses WinRM for communication between computers. WinRM runs
as a service under
the Network Service account, and spawns isolated processes running
as user accounts to host
PowerShell instances. An instance of PowerShell running as one
user has no access to a process
running an instance of PowerShell as another user.
Regardless of the transport protocol used (HTTP or HTTPS), WinRM always encrypts all
PowerShell
remoting communication after initial authentication.
Initial authentication
Authentication confirms the identity of the client to the server - and ideally - the server
to the
client.
When a client connects to a domain server using its computer name, the default
authentication
protocol is Kerberos. Kerberos guarantees both the user identity and
server identity without
sending any sort of reusable credential.
The NTLM protocol doesn't, however, guarantee server identity. As with all protocols
that use NTLM
for authentication, an attacker with access to a domain-joined
computer's machine account could
invoke the domain controller to compute an NTLM
session-key and thereby impersonate the server.
Since the NTLM authentication protocol can't ensure the identity of the target server
(only that it
already knows your password), you can configure target servers to use SSL
for PowerShell Remoting.
Assigning a SSL certificate to the target server (if issued by a
Certificate Authority that the
client also trusts) enables NTLM-based authentication that
guarantees both the user identity and
server identity.
Ongoing Communication
Once initial authentication is complete, the WinRM encrypts the ongoing
communication. When
connecting over HTTPS, the TLS protocol is used to negotiate the
encryption used to transport data.
When connecting over HTTP, message-level
encryption is determined by initial authentication protocol
used.
There are several ways to avoid this problem. For descriptions of these methods, and the
pros and
cons of each, see Making the second hop in PowerShell Remoting.
References
Windows Remote Management (WinRM)
Web Services for Management (WS-Management)
2.2.9.1 Encrypted Message Types
Kerberos
NTLM authentication protocol
Investigating PowerShell Attacks
Making the second hop in PowerShell
Remoting
Article • 12/16/2022
There are several ways to address this problem. The following table lists the methods in
order of
preference.
Configuration Note
Just Enough Administration (JEA) Can provide the best security but requires more
detailed configuration
Pass credentials inside an Invoke- Simplest to use but you must provide credentials
Command script block
CredSSP
You can use the Credential Security Support Provider (CredSSP) for authentication.
CredSSP
caches credentials on the remote server (ServerB), so using it opens you up to
credential theft
attacks. If the remote computer is compromised, the attacker has access
to the user's credentials.
CredSSP is disabled by default on both client and server
computers. You should enable CredSSP only
in the most trusted environments. For
example, a domain administrator connecting to a domain
controller because the
domain controller is highly trusted.
For more information about security concerns when using CredSSP for PowerShell
Remoting, see
Accidental Sabotage: Beware of CredSSP .
For an example of how to enable and use CredSSP for PowerShell remoting, see
Enable
PowerShell "Second-Hop" Functionality with CredSSP .
Pros
It works for all servers with Windows Server 2008 or later.
Cons
Has security vulnerabilities.
Requires configuration of both client and server roles.
doesn't work with the Protected Users group. For more information, see
Protected
Users Security Group.
Pros
Requires no special coding
Credentials aren't stored.
Cons
Doesn't support the second hop for WinRM.
Requires Domain Administrator access to configure.
Must be configured on the Active Directory object of the remote server (ServerB).
Limited to one domain. Can't cross domains or forests.
Requires rights to update objects and Service Principal Names (SPNs).
ServerB can acquire a Kerberos ticket to ServerC on behalf of the user without user
intervention.
7 Note
Active Directory accounts that have the Account is sensitive and can't be
delegated property
set can't be delegated. For more information, see
Security
Focus: Analysing 'Account is sensitive and can't be delegated' for Privileged
Accounts
and Kerberos Authentication Tools and Settings.
Pros
Credentials aren't stored.
Configured using PowerShell cmdlets. No special coding required.
Doesn't require Domain Administrator access to configure.
Works across domains and forests.
Cons
Requires Windows Server 2012 or later.
Doesn't support the second hop for WinRM.
Requires rights to update objects and Service Principal Names (SPNs).
7 Note
Active Directory accounts that have the Account is sensitive and can't be
delegated property
set can't be delegated. For more information, see
Security
Focus: Analysing 'Account is sensitive and can't be delegated' for Privileged
Accounts
and Kerberos Authentication Tools and Settings.
Example
Let's look at a PowerShell example that configures resource-based constrained
delegation on
ServerC to allow delegated credentials from a ServerB. This example
assumes that all servers are
running Windows Server 2012 or later, and that there is at
least one Windows Server 2012 domain
controller each domain to which any of the
servers belong.
Before you can configure constrained delegation, you must add the RSAT-AD-PowerShell
feature to
install the Active Directory PowerShell module, and then import that module
into your session:
PowerShell
Add-WindowsFeature RSAT-AD-PowerShell
Import-Module ActiveDirectory
Output
Now let's set up the variables we'll use to represent the servers:
PowerShell
$ServerA = $env:COMPUTERNAME
WinRM (and therefore PowerShell remoting) runs as the computer account by default.
You can see this
by looking at the StartName property of the winrm service:
PowerShell
Output
StartName
---------
NT AUTHORITY\NetworkService
For ServerC to allow delegation from a PowerShell remoting session on ServerB, we must
set the
PrincipalsAllowedToDelegateToAccount parameter on ServerC to the computer
object of ServerB:
PowerShell
$x.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access
The Kerberos Key Distribution Center (KDC) caches denied-access attempts (negative
cache) for
15 minutes. If ServerB has previously attempted to access ServerC, you need
to clear the
cache on ServerB by invoking the following command:
PowerShell
You could also restart the computer, or wait at least 15 minutes to clear the cache.
After clearing the cache, you can successfully run code from ServerA through ServerB to
ServerC:
PowerShell
# Capture a credential
Test-Path \\$($using:ServerC.Name)\C$
In this example, the $using variable is used to make the $ServerC variable visible to
ServerB.
For more information about the $using variable, see about_Remote_Variables.
To allow multiple servers to delegate credentials to ServerC, set the value of the
PrincipalsAllowedToDelegateToAccount parameter on ServerC to an array:
PowerShell
$servers = @(
$ServerB1,
$ServerB2,
$ServerB3
If you want to make the second hop across domains, use the Server parameter to
specify
fully-qualified domain name (FQDN) of the domain controller of the domain to
which ServerB
belongs:
PowerShell
To remove the ability to delegate credentials to ServerC, set the value of the
PrincipalsAllowedToDelegateToAccount parameter on ServerC to $null :
PowerShell
2 Warning
This method provides no control of where delegated credentials are used. It's less
secure than
CredSSP. This method should only be used for testing scenarios.
Just Enough Administration (JEA)
JEA allows you to restrict what commands an administrator can run during a PowerShell
session. It
can be used to solve the second hop problem.
Pros
No password maintenance when using a virtual account.
Cons
Requires WMF 5.0 or later.
Requires configuration on every intermediate server (ServerB).
For information about using PSSessionConfiguration and RunAs to solve the second
hop
problem, see Another solution to multi-hop PowerShell remoting.
Pros
Works with any server with WMF 3.0 or later.
Cons
Requires configuration of PSSessionConfiguration and RunAs on every
intermediate server
(ServerB).
Requires password maintenance when using a domain RunAs account
Cons
Requires an awkward code technique.
If running WMF 2.0, requires different syntax for passing arguments to a remote
session.
Example
The following example shows how to pass credentials in an script block:
PowerShell
hostname
See also
PowerShell Remoting Security Considerations
PowerShell Remoting FAQ
FAQ
When you work remotely, you type commands in PowerShell on one computer (known
as the "local
computer"), but the commands run on another computer (known as the
"remote computer"). The
experience of working remotely should be as much like
working directly at the remote computer as
possible.
7 Note
You must have permission to connect to the remote computer, permission to run
PowerShell,
and permission to access data stores (such as files and folders), and the
registry on the
remote computer.
Beginning in Windows PowerShell 3.0, remote sessions are stored on the remote
computer.
This enables you to disconnect from the session and reconnect from a
different session or
a different computer without interrupting the commands or losing
state.
To add additional protection, you can configure the remote computer to use Secure
Sockets
Layer (SSL) instead of HTTP to listen for Windows Remote Management
(WinRM) requests.
Then, users can use the UseSSL parameter of the Invoke-Command ,
New-PSSession , and
Enter-PSSession cmdlets when establishing a connection. This
option uses the more secure
HTTPS channel instead of HTTP.
These cmdlets do not use PowerShell remoting. So, you can use them on any computer
that is
running PowerShell, even if the computer is not configured for PowerShell
remoting or if
the computer does not meet the requirements for PowerShell remoting.
Get-Hotfix
Rename-Computer
Restart-Computer
Stop-Computer
# or
PowerShell
For example:
PowerShell
Enclose your command in braces ( {} ) to make it a script block. Use the ScriptBlock
parameter of Invoke-Command to specify the command.
PowerShell
# - OR -
For more information about remote commands, see about_Remote and the Help topics
for the
cmdlets that support remoting.
PowerShell
Enter-PSSession <ComputerName>
The command prompt changes to show that you are connected to the remote
computer.
<ComputerName>\C:>
Now, the commands that you type run on the remote computer just as though you
typed them
directly on the remote computer.
PowerShell
Exit-PSSession
When you use the New-PSSession cmdlet to create a PSSession, PowerShell establishes a
persistent connection for the PSSession. Then, you can run multiple commands in the
PSSession, including commands that share data.
Typically, you create a PSSession to run a series of related commands that share data.
Otherwise, the temporary connection created by the ComputerName parameter is
sufficient for most commands.
When you run an Invoke-Command command, PowerShell runs the commands on all of
the
specified computers or in all of the specified PSSessions.
For more information, see the example in the Invoke-Command Help topic.
For example, the following command runs the CurrentUserCurrentHost profile from the
local computer in the session in $s .
The following command runs the CurrentUserCurrentHost profile from the remote
computer
in the session in $s . Because the $profile variable is not populated, the
command uses
the explicit path to the profile.
PowerShell
Invoke-Command -Session $s {
. "$home\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
After running this command, the commands that the profile adds to the session are
available in $s .
You can also use a startup script in a session configuration to run a profile in every
remote session that uses the session configuration.
The default is 32 concurrent connections, but you can use the ThrottleLimit parameter
of the cmdlets to set a custom throttle limit for particular commands.
When you use the throttling feature, remember that it is applied to each command, not
to
the entire session or to the computer. If you are running commands concurrently in
several
sessions or PSSessions, the number of concurrent connections is the sum of the
concurrent
connections in all the sessions.
-or-
However, because most live objects cannot be transmitted over the network, PowerShell
"serializes" most of the objects sent in remote commands, that is, it converts each object
into a series of XML (Constraint Language in XML [CLiXML]) data elements for
transmission.
When PowerShell receives a serialized object, it converts the XML into a deserialized
object type. The deserialized object is an accurate record of the properties of the
program or component at a previous time, but it is no longer "live", that is, it is no
longer directly associated with the component. And, the methods are removed because
they
are no longer effective.
Typically, you can use deserialized objects just as you would use live objects, but you
must be aware of their limitations. Also, the objects that are returned by the
Invoke-
Command cmdlet have additional properties that help you to determine the origin
of the
command.
Some object types, such as DirectoryInfo objects and GUIDs, are converted back into live
objects when they are received. These objects do not need any special handling or
formatting.
For information about interpreting and formatting remote output, see
about_Remote_Output.
You can start a background job even while other commands are running because
background
jobs always run asynchronously in a temporary session.
You can run background jobs on a local or remote computer. By default, a background
job
runs on the local computer. However, you can use the AsJob parameter of the
Invoke-Command cmdlet to run any remote command as a background job. And, you can
use
Invoke-Command to run a Start-Job command remotely.
However, you cannot use PowerShell commands to open the user interface for any
program on
a remote computer.
When you start a Windows program on a remote computer, the command is not
completed, and
the PowerShell command prompt does not return, until the program is
finished or until you
press CTRL + C to interrupt the command. For example, if you run
the
Ipconfig.exe program on a remote computer, the command prompt does not
return until
Ipconfig.exe is completed.
If you use remote commands to start a program that has a user interface, the program
process starts, but the user interface does not appear. The PowerShell command is not
completed, and the command prompt does not return until you stop the program
process or
until you press CTRL + C , which interrupts the command and stops the
process.
For example, if you use a PowerShell command to run Notepad on a remote computer,
the
Notepad process starts on the remote computer, but the Notepad user interface
does not
appear. To interrupt the command and restore the command prompt, press
CTRL + C .
A session configuration configures the environment for the session. You can define the
configuration by using an assembly that implements a new configuration class or by
using a
script that runs in the session. The configuration can determine the commands
that are
available in the session. And, the configuration can include settings that protect
the
computer, such as settings that limit the amount of data that the session can receive
remotely in a single object or command. You can also specify a security descriptor that
determines the permissions that are required to use the configuration.
You can use the session configuration cmdlets to edit the default session configurations,
to create new session configurations, and to change the security descriptors of all the
session configurations.
For more information about session configurations, see the Help for the session
configuration cmdlets. To find the session configuration cmdlets, type:
PowerShell
Get-Command *PSSessionConfiguration
For the fan-out configuration, PowerShell uses the Web Services for Management
(WS-
Management) protocol and the WinRM service that supports the Microsoft
implementation
of WS-Management. When a local computer connects to a remote
computer, WS-Management
establishes a connection and uses a plug-in for PowerShell
to start the PowerShell host
process (Wsmprovhost.exe) on the remote computer. The
user can specify an alternate port,
an alternate session configuration, and other features
to customize the remote connection.
To support the "fan-in" configuration, PowerShell uses internet Information Services (IIS)
to host WS-Management, to load the PowerShell plug-in, and to start PowerShell. In this
scenario, instead of starting each PowerShell session in a separate process, all
PowerShell sessions run in the same host process.
You can also specify an authentication mechanism and prohibit or allow redirection from
HTTP and HTTPS endpoints.
Caution: These settings affect all users on the system and they can make the system
more
vulnerable to a malicious attack. Use caution when making these changes.
Create the following registry entry, and then set its value to 1:
LocalAccountTokenFilterPolicy in
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
You can use the following PowerShell command to add this entry:
PowerShell
$parameters = @{
Path='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
Name='LocalAccountTokenFilterPolicy'
propertyType='DWord'
Value=1
New-ItemProperty @parameters
Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows
Server 2012 R2:
No changes are needed because the default setting of the "Network Access:
Sharing and
security model for local accounts" policy is "Classic". Verify the setting
in case it
has changed.
However, if the remote computer is not in a domain that the local computer trusts, the
remote computer might not be able to authenticate the user's credentials.
To enable authentication, use the following command to add the remote computer to
the list
of trusted hosts for the local computer in WinRM. Type the command at the
PowerShell
prompt.
PowerShell
For example, to add the Server01 computer to the list of trusted hosts on the local
computer, type the following command at the PowerShell prompt:
PowerShell
See also
about_Remote
about_Profiles
about_PSSessions
about_Remote_Jobs
about_Remote_Variables
Invoke-Command
New-PSSession
PowerShell security features
Article • 05/26/2023
PowerShell has several features designed to improve the security of your scripting
environment.
Execution policy
PowerShell's execution policy is a safety feature that controls the conditions under which
PowerShell loads configuration files and runs scripts. This feature helps prevent the
execution of
malicious scripts. You can use a Group Policy setting to set execution
policies for computers and
users. Execution policies only apply to the Windows platform.
Script Block Logging enables logging for the processing of commands, script blocks,
functions, and
scripts - whether invoked interactively, or through automation. This
information is logged to the
Microsoft-Windows-PowerShell/Operational event log.
about_Group_Policy_Settings
about_Logging_Windows
about_Logging_Non-Windows
AMSI Support
The Windows Antimalware Scan Interface (AMSI) is an API that allows application
actions to be passed
to an antimalware scanner, such as Windows Defender, to be
scanned for malicious payloads. Beginning
with PowerShell 5.1, PowerShell running on
Windows 10 (and higher) passes all script blocks to AMSI.
PowerShell 7.3 extends the data that's sent to AMSI for inspection. It now includes all
invocations
of .NET method members.
For more information about AMSI, see How AMSI helps.
Application Control
Windows 10 includes two technologies, Windows Defender Application Control (WDAC)
and
AppLocker that you can use to control applications. They allow you to create a
lockdown
experience to help secure your PowerShell environment.
For more information about how PowerShell supports AppLocker and WDAC, see
Using
Windows Defender Application Control.
PowerShell 7.2 now disallows the use of the Add-Type cmdlet in a NoLanguage
mode PowerShell
session on a locked down machine.
PowerShell 7.2 now disallows scripts from using COM objects in AppLocker system
lock down
conditions. Cmdlet that use COM or DCOM internally aren't affected.
The PowerShell team is also producing SBOMs for modules that they own but ship
separately from
PowerShell. SBOMs will be added in the next release of the module. For
modules, the SBOM is
installed in the module's folder under
_manifest/spdx_2.2/manifest.spdx.json .
For more information about this initiative, see the blog post
Generating Software Bills of
Materials (SBOMs) with SPDX at Microsoft .
Using Windows Defender Application
Control
Article • 05/26/2023
7 Note
WDAC was introduced with Windows 10 and allows organizations to control the drivers
and
applications are allowed to run on their Windows devices. WDAC is designed as a
security feature
under the servicing criteria defined by the Microsoft Security Response
Center (MSRC).
For more information about AppLocker and WDAC, see Application Controls for
Windows and
WDAC and AppLocker feature availability.
Or, you can run the following command from an elevated PowerShell session.
PowerShell
You can view the events in the Windows Event Viewer or use the Get-WinEvent cmdlet to
retrieve the
events.
PowerShell
Output
ProviderName : PowerShellCore
Id : 16387
At C:\scripts\Test1.ps1:3 char:1
+ [System.Console]::WriteLine("pwnd!")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FullyQualifiedId: MethodOrPropertyInvocationNotAllowed
The event message includes the script position where the restriction would be applied.
This
information helps you understand where you need to change your script so that it
runs under the WDAC
policy.
) Important
Once you have reviewed the audit events, you should disable the Analytic log.
Analytic logs grow
quickly and consume large amounts of disk space.
An experimental feature is one where the design isn't finalized. The feature is available
for users
to test and provide feedback. Once an experimental feature is finalized, the
design changes become
breaking changes.
U Caution
Available features
This article describes the experimental features that are available and how to use the
feature.
Legend
The icon indicates that the experimental feature is available in the version
of
PowerShell
The icon indicates the version of PowerShell where the experimental feature
became mainstream
The icon indicates the version of PowerShell where the experimental feature
was
removed
PSCommandNotFoundSuggestion
Name 7.2 7.3 7.4
PSNativePSPathResolution
PSSubsystemPluginModel
PSNativeCommandArgumentPassing
PSAnsiRenderingFileInfo
PSLoadAssemblyFromNativeCode
PSNativeCommandErrorActionPreference
PSCustomTableHeaderLabelDecoration
PSFeedbackProvider
PSModuleAutoLoadSkipOfflineFiles
PSCommandWithArgs
PSConstrainedAuditLogging
PSNativeCommandPreserveBytePipe
PSAnsiRenderingFileInfo
7 Note
This experiment was added in PowerShell 7.2. This feature adds the $PSStyle.FileInfo
member and
enables coloring of specific file types.
PSCommandNotFoundSuggestion
Recommends potential commands based on fuzzy matching search after a
CommandNotFoundException.
PowerShell
PS> get
Output
get: The term 'get' isn't recognized as the name of a cmdlet, function,
script file,
Suggestion [4,General]: The most similar commands are: set, del, ft, gal,
gbp, gc, gci,
PSCommandWithArgs
This feature enables the -CommandWithArgs parameter for pwsh . This parameter allows
you to
execute a PowerShell command with arguments. Unlike -Command , this parameter
populates the $args
built-in variable that can be used by the command.
The first string is the command and subsequent strings delimited by whitespace are the
arguments.
For example:
PowerShell
arg: arg1
arg: arg2
PSConstrainedAuditLogging
On Windows, when PowerShell runs under a Windows Defender Application Control
(WDAC) policy, it
changes its behavior based on the defined security policy. Under a
WDAC policy, PowerShell runs
trusted scripts and modules allowed by the policy in Full
Language mode. All other scripts and
script blocks are untrusted and run in Constrained
Language mode. PowerShell throws errors when the
untrusted scripts attempt to
perform disallowed actions. It's difficult to know why a script fails
to run correctly in
Constrained Language mode.
PSCustomTableHeaderLabelDecoration
When this feature is enabled, $PSStyle includes formatting differentiation for table
header labels
that aren't property members. For example, the default output from Get-
Process includes the
following columns: NPM(K) , PM(M) , WS(M) , and CPU(s) .
PowerShell
Get-Process pwsh
Output
With this feature enabled these column headers are displayed in italics to distinguish
these column
names from property names.
PSDesiredStateConfiguration.InvokeDscResource
Enables compilation to MOF on non-Windows systems and enables the use of Invoke-
DSCResource
without an LCM.
In earlier previews of PowerShell 7.2, this feature was enabled by default. Beginning with
PowerShell 7.2, the PSDesiredStateConfiguration module was removed and this feature
is disabled
by default. To enable this feature you must install the
PSDesiredStateConfiguration v2.0.5
module from the PowerShell Gallery and enable the
feature using Enable-ExperimentalFeature .
DSC v3 doesn't have this experimental feature. DSC v3 only supports Invoke-
DSCResource and doesn't
use or support MOF compilation. For more information, see
PSFeedbackProvider
Replace the hard-coded suggestion framework with the extensible feedback provider.
PSLoadAssemblyFromNativeCode
Exposes an API to allow assembly loading from native code.
PSModuleAutoLoadSkipOfflineFiles
With this feature enabled, if a user's PSModulePath contains a folder from a cloud
provider,
such as OneDrive, PowerShell no longer triggers the download of all files
contained within that
folder. Any file marked as not downloaded are skipped. Users who
use cloud providers to sync their
modules between machines should mark the module
folder as Pinned or the equivalent status for
providers other than OneDrive. Marking the
module folder as Pinned ensures that the files are
always kept on disk.
PSNativeCommandArgumentPassing
7 Note
When this experimental feature is enabled PowerShell uses the ArgumentList property
of the
StartProcessInfo object rather than our current mechanism of reconstructing a
string when invoking
a native executable.
U Caution
The new behavior is a breaking change from current behavior. This may break
scripts and
automation that work around the various issues when invoking native
applications. Historically,
quotes must be escaped and it isn't possible to provide
empty arguments to a native application.
Use the stop-parsing token ( --% ) or the
Start-Process cmdlet to sidestep native
argument passing when needed.
Legacy is the historic behavior. The behavior of Windows and Standard mode are the
same
except, in Windows mode, invocations of the following files automatically use the
Legacy style
argument passing.
cmd.exe
find.exe
cscript.exe
wscript.exe
sqlcmd.exe - Added in PowerShell 7.3.1
The default behavior is platform specific. On Windows platforms, the default setting is
Windows
and non-Windows platforms is Standard .
7 Note
The following examples use the TestExe.exe tool. You can build TestExe from the
source code.
See TestExe in the PowerShell source repository.
Literal or expandable strings with embedded quotes the quotes are preserved:
PowerShell
PowerShell
Arg 0 is <>
Arg 1 is <a>
Arg 2 is <b>
Arg 3 is <>
PowerShell 7.3 also added the ability to trace parameter binding for native commands.
For more
information, see Trace-Command.
PSNativeCommandErrorActionPreference
Native commands usually return an exit code to the calling application that's zero for
success or
non-zero for failure. However, native commands currently don't participate in
the PowerShell error
stream. Redirected stderr output isn't interpreted the same as the
PowerShell error stream. Many
native commands use stderr as an information or
verbose stream, thus only the exit code matters.
Users working with native commands in
their scripts need to check the exit status after each call
using similar to the following
example:
PowerShell
if ($LASTEXITCODE -ne 0) {
However, this example doesn't support all cases where $? can be false from a cmdlet or
function
error, making $LASTEXITCODE stale.
PowerShell
Enable-ExperimentalFeature PSNativeCommandErrorActionPreference
You must start a new PowerShell session for this change to be in effect. Beginning in
PowerShell
7.4, $PSNativeCommandUseErrorActionPreference is set to $true by default.
With the preference
set to $true you get the following behavior:
PSNativeCommandPreserveBytePipe
This feature preserves the byte-stream data when redirecting the stdout stream of a
native
command to a file or when piping byte-stream data to the stdin stream of a
native command.
For example, using the native command curl you can download a binary file and save it
to disk
using redirection.
PowerShell
$uri =
'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershel
l-7.3.4-linux-arm64.tar.gz'
You can also pipe the byte-stream data to the stdin stream of another native command.
The
following example downloads a zipped TAR file using curl . The downloaded file
data is streamed
to the tar command to extract the contents of the archive.
PowerShell
You can also pipe the byte-stream output of a PowerShell command to the input of
native command. The
following examples use Invoke-WebRequest to download the same
TAR file as the previous example.
PowerShell
This feature doesn't support byte-stream data when redirecting stderr output to stdout.
When
you combine the stderr and stdout streams, the combined streams are treated as
string data.
PSNativePSPathResolution
7 Note
Also, on Windows, if the path starts with ~ , that's resolved to the full path and passed to
the
native command. In both cases, the path is normalized to the directory separators
for the relevant
operating system.
If the path isn't a PSDrive or ~ (on Windows), then path normalization doesn't
occur
If the path is in single quotes, then it's not resolved and treated as literal
PSSubsystemPluginModel
This feature enables the subsystem plugin model in PowerShell. The feature makes it
possible to
separate components of System.Management.Automation.dll into individual
subsystems that reside in
their own assembly. This separation reduces the disk footprint
of the core PowerShell engine and
allows these components to become optional
features for a minimal PowerShell installation.
The experimental feature includes a new cmdlet, Get-PSSubsystem. This cmdlet is only
available
when the feature is enabled. This cmdlet returns information about the
subsystems that are available
on the system.
Using aliases
Article • 11/17/2022
PowerShell
Output
Use the Get-Alias cmdlet to list the aliases available in your environment. To list the
aliases for a single cmdlet, use the Definition parameter and specify the executable
name.
PowerShell
Output
CommandType Name
----------- ----
PowerShell
Output
CommandType Name
----------- ----
md mkdir New-Item ni
The aliases in this table are Windows-specific. Some aliases aren't available on
other platforms.
This is to allow the native command to work in a PowerShell
session. For example, ls isn't
defined as a PowerShell alias on macOS or Linux so
that the native command is run instead of
Get-ChildItem .
In addition to parameter aliases, PowerShell lets you specify the parameter name using
the fewest
characters needed to uniquely identify the parameter. For example, the Get-
ChildItem cmdlet has
the Recurse and ReadOnly parameters. To uniquely identify the
Recurse parameter you only
need to provide -rec . If you combine that with the
command alias, Get-ChildItem -Recurse can be
shortened to dir -rec .
Learn modules
Microsoft Learn is a free, online training platform that provides interactive learning for
Microsoft
products and more. Our goal is to help you become proficient on our
technologies and learn more
skills with fun, guided, hands-on, interactive content that's
specific to your role and goals.
PowerShell modules
PowerShell Team Blog . The best resource for learning directly from the
PowerShell product
team.
PowerShell Community Blog articles are scenario-driven. Written by the
community, for the
community.
Have questions about using PowerShell? Connect with hundreds of other people
who have similar
interests in one of the many community forums listed on the
PowerShell Community page.
PowerShell SDK
PowerShell SDK API Browser
PowerShell Glossary
Article • 10/14/2022
binary module
A PowerShell module whose root module is a binary ( .dll ) file. A binary module may or
may not
include a module manifest.
CommonParameter
A parameter that's added to all cmdlets, advanced functions, and workflows by the
PowerShell engine.
dot source
In PowerShell, to start a command by typing a dot and a space before the command.
Commands that are
dot sourced run in the current scope instead of in a new scope. Any
variables, aliases, functions,
or drives that command creates are created in the current
scope and are available to users when the
command is completed.
dynamic module
A module that exists only in memory. The New-Module and Import-PSSession cmdlets
create dynamic
modules.
dynamic parameter
A parameter that's added to a PowerShell cmdlet, function, or script under certain
conditions.
Cmdlets, functions, providers, and scripts can add dynamic parameters.
F
format file
A PowerShell XML file that has the .format.ps1xml extension and that defines how
PowerShell
displays an object based on its .NET Framework type.
Host
The interface that the PowerShell engine uses to communicate with the user. For
example, the host
specifies how prompts are handled between PowerShell and the user.
host application
A program that loads the PowerShell engine into its process and uses it to perform
operations.
M
manifest module
A PowerShell module that has a manifest and whose RootModule key is empty.
member-access enumeration
A PowerShell convenience feature to automatically enumerate items in a collection when
using the
member-access operator ( . ).
module
A self-contained reusable unit that allows you to partition, organize, and abstract your
PowerShell
code. A module can contain cmdlets, providers, functions, variables, and
other types of resources
that can be imported as a single unit.
module manifest
A PowerShell data file ( .psd1 ) that describes the contents of a module and that controls
how a
module is processed.
non-terminating error
An error that doesn't stop PowerShell from continuing to process the command.
noun
The word that follows the hyphen in a PowerShell cmdlet name. The noun describes the
resources upon
which the cmdlet acts.
P
parameter set
A group of parameters that can be used in the same command to perform a specific
action.
pipe
In PowerShell, to send the results of the preceding command as input to the next
command in the
pipeline.
pipeline
A series of commands connected by pipeline operators ( | ). Each pipeline operator
sends the results
of the preceding command as input to the next command.
PowerShell cmdlet
A single command that participates in the pipeline semantics of PowerShell. This
includes binary
(C#) cmdlets, advanced script functions, CDXML, and Workflows.
PowerShell command
The elements in a pipeline that cause an action to be carried out. PowerShell commands
are either
typed at the keyboard or invoked programmatically.
PowerShell drive
A virtual drive that provides direct access to a data store. It can be defined by a
PowerShell
provider or created at the command line. Drives created at the command
line are session-specific
drives and are lost when the session is closed.
provider
A Microsoft .NET Framework-based program that makes the data in a specialized data
store available
in PowerShell so that you can view and manage it.
PSSession
A type of PowerShell session that's created, managed, and closed by the user.
root module
The module specified in the RootModule key in a module manifest.
runspace
In PowerShell, the operating environment in which each command in a pipeline is
executed.
script block
In the PowerShell programming language, a collection of statements or expressions that
can be used
as a single unit. A script block can accept arguments and return values.
script file
A file that has the .ps1 extension and contains a script written in the PowerShell
language.
script module
A PowerShell module whose root module is a script module ( .psm1 ) file. A script module
may include
a module manifest. The script defines the members that the script module
exports.
shell
The command interpreter that's used to pass commands to the operating system.
switch parameter
A parameter that doesn't take an argument. The value of a switch parameter defaults to
$false .
When a switch parameter is used, its value becomes $true .
terminating error
An error that stops PowerShell from processing the command.
transaction
An atomic unit of work. The work in a transaction must be completed as a whole. If any
part of the
transaction fails, the entire transaction fails.
type file
A PowerShell XML file that has the .types.ps1xml extension and that extends the
properties of Microsoft
.NET Framework types in PowerShell.
verb
The word that precedes the hyphen in a PowerShell cmdlet name. The verb describes
the action that
the cmdlet performs.
h WHAT'S NEW
h WHAT'S NEW
h WHAT'S NEW
Module compatibility
h WHAT'S NEW
What's new in PowerShell 6.2
For a complete list of changes, see the Change Log in the GitHub repository.
Breaking changes
Nano server docker images aren't available for this release
Add the ProgressAction parameter to the common parameters
Update some PowerShell APIs to throw ArgumentException instead of
ArgumentNullException
when the argument is an empty string (#19215 )
(Thanks @xtqqczze!)
Installer updates
The Windows MSI package now provides an option to disable PowerShell telemetry
during installation.
For more information, see Install the msi package from the command
line.
Fix issue when completing the first command in a script with an empty array
expression
([#18355 )
Fix positional argument completion (#17796 )
Prioritize the default parameter set when completing positional arguments
(#18755 )
Improve pseudo binding for dynamic parameters (#18030 )
Improve type inference of hashtable keys (#17907 )
Fix type inference error for empty return statements (#18351 )
Improve type inference for Get-Random (#18972 )
Fix type inference for all scope variables (#18758 )
Improve enumeration of inferred types in pipeline (#17799 )
Add completion for values in comparisons when comparing Enums (#17654 )
Add property assignment completion for enums (#19178 )
Fix completion for PSCustomObject variable properties (#18682 )
Fix member completion in attribute argument (#17902 )
Fix class member completion for classes with base types (#19179 )
Add completion for Using keywords (#16514 )
Web cmdlets get Retry-After interval from response headers if the status code is
429
(#18717 )
Web cmdlets set default charset encoding to UTF8 (#18219 )
Preserve WebSession.MaximumRedirection from changes (#19190 )
WebCmdlets parse XML declaration to get encoding value, if present. (#18748 )
Fix using xml -Body in webcmdlets without an encoding (#19281 )
Adjust PUT method behavior to POST one for default content type in WebCmdlets
(#19152 )
Take into account ContentType from Headers in WebCmdlets (#19227 )
Allow to preserve the original HTTP method by adding -
PreserveHttpMethodOnRedirect to Web cmdlets
(#18894 )
Webcmdlets display an error on https to http redirect (#18595 )
Add AllowInsecureRedirect switch to Web cmdlets (#18546 )
Improve verbose message in web cmdlets when content length is unknown
(#19252 )
Build the relative URI for links from the response in Invoke-WebRequest
(#19092 )
Fix redirection for -CustomMethod POST in WebCmdlets (#19111 )
Dispose previous response in Webcmdlets (#19117 )
Improve Invoke-WebRequest xml and json errors format (#18837 )
Add ValidateNotNullOrEmpty to OutFile and InFile parameters of WebCmdlets
(#19044 )
HttpKnownHeaderNames update headers list (#18947 )
Invoke-RestMethod -FollowRelLink fix links containing commas (#18829 )
Fix bug with managing redirection and KeepAuthorization in Web cmdlets
(#18902 )
Add StatusCode to HttpResponseException (#18842 )
Support HTTP persistent connections in Web Cmdlets (#19249 ) (Thanks
@stevenebutler!)
Other cmdlets
Add Path and LiteralPath parameters to Test-Json cmdlet (#19042 ) (Thanks
@ArmaanMcleod!)
Add NoHeader parameter to ConvertTo-Csv and Export-Csv cmdlets (#19108 )
(Thanks
@ArmaanMcleod!)
Add Confirm and WhatIf parameters to Stop-Transcript (#18731 ) (Thanks
@JohnLBevan!)
Add FuzzyMinimumDistance parameter to Get-Command (#18261 )
Make Encoding parameter able to take ANSI encoding in PowerShell (#19298 )
(Thanks
@CarloToso!)
Add progress to Copy-Item (#18735 )
Update-Help now reports an error when using implicit culture on non-US systems.
Updates to $PSStyle
Make PowerShell class not affiliate with Runspace when declaring the
NoRunspaceAffinity
attribute (#18138 )
Add the ValidateNotNullOrWhiteSpace attribute (#17191 ) (Thanks @wmentha!)
Add sqlcmd to the list for legacy argument passing (#18559 )
Add the function cd~ (#18308 ) (Thanks @GigaScratch!)
Experimental Features
PowerShell 7.4 introduces the following experimental features:
PSNativeCommandErrorActionPreference -
$PSNativeCommandUseErrorActionPreference is set to
$true when feature is enabled
(#18695 )
PSCommandNotFoundSuggestion - This feature now uses an extensible
feedback provider rather
than hard-coded suggestions (#18726 )
For more information about the Experimental Features, see Using Experimental
Features .
What's New in PowerShell 7.3
Article • 02/27/2023
PowerShell 7.3 includes the following features, updates, and breaking changes.
Updated cmdlets
Add -HttpVersion parameter to web cmdlets (#15853 ) (Thanks @hayhay27!)
Add support to web cmdlets for open-ended input tags (#16193 ) (Thanks
@farmerau!)
Fix ConvertTo-Json -Depth to allow 100 at maximum (#16197 ) (Thanks
@KevRitchie!)
@rkeithhill!)
Improve variable handling when calling Invoke-Command with the $using:
expression
(#16113 ) (Thanks @dwtaber!)
Add -StrictMode to Invoke-Command to allow specifying strict mode when invoking
command
locally (#16545 ) (Thanks @Thomas-Yu!)
Add clean block to script block as a peer to begin , process , and end to allow easy
resource cleanup (#15177 )
Add -Amended switch to Get-CimClass cmdlet (#17477 ) (Thanks @iSazonov)
Changed ConvertFrom-Json -AsHashtable to use ordered hashtable (#17405 )
Removed ANSI escape sequences in strings before sending to Out-GridView
(#17664 )
Added the Milliseconds parameter to New-TimeSpan (#17621 ) (Thanks
@NoMoreFood!)
Show optional parameters when displaying method definitions and overloads
(#13799 )
(Thanks @eugenesmlv!)
Allow commands to still be executed even if the current working directory no
longer exists
(#17579 )
Add support for HTTPS with Set-AuthenticodeSignature -TimeStampServer
(#16134 ) (Thanks
@Ryan-Hutchison-USAF!)
Render decimal numbers in a table using current culture (#17650 )
Add type accelerator ordered for OrderedDictionary (#17804 ) (Thanks @fflaten!)
Add find.exe to legacy argument binding behavior for Windows (#17715 )
Add -noprofileloadtime switch to pwsh (#17535 ) (Thanks @rkeithhill!)
For a complete list of changes, see the Change Log in the GitHub repository.
Experimental Features
In PowerShell 7.3, following experimental features became mainstream:
PSCleanBlock - Adds clean block to script block as a peer to begin , process , and
end
to allow easy resource cleanup.
include all
invocations of .NET method members.
PowerShell 7.3.1 adds sqlcmd.exe to the list of native commands in Windows that
use the Legacy
style of argument passing.
PSExec - Adds the new Switch-Process cmdlet (alias exec ) to provide exec
compatibility for
non-Windows systems.
PowerShell 7.3.1 changed the exec alias to a function that wraps Switch-Process .
The function
allows you to pass parameters to the native command that might
have erroneously bound to the
WithCommand parameter.
native commands
to be PowerShell errors.
For more information about the Experimental Features, see Using Experimental Features.
What's New in PowerShell 7.2
Article • 01/23/2023
PowerShell 7.2 is the next Long Term Servicing (LTS) release is built on .NET 6.0.
PowerShell 7.2 includes the following features, updates, and breaking changes.
For a complete list of changes, see the Change Log in the GitHub repository.
Installation updates
Check the installation instructions for your preferred operating system:
Windows
macOS
Linux
Additionally, PowerShell 7.2 supports ARM64 versions of Windows and macOS and
ARM32 and ARM64
versions of Debian and Ubuntu.
For up-to-date information about supported operating systems and support lifecycle,
see the
PowerShell Support Lifecycle.
ENABLE_MU
1 (default) - Opts into using Microsoft Update the Automatic Updates or
Windows Update
0 - don't opt into using Microsoft Update the Automatic Updates or Windows
Update
Experimental Features
The following experimental features are now mainstream features in this release:
Microsoft.PowerShell.Utility.PSImportPSDataFileSkipLimitCheck - see
Import-
PowerShellDataFile
Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace
PSAnsiRendering - see about_ANSI_Terminals
PSCultureInvariantReplaceOperator
PSNotApplyErrorActionToStderr
PSUnixFileStat
For more information about the Experimental Features, see Using Experimental Features.
Fix tab completion for unlocalized about* topics (#15265) (Thanks @MartinGC94)
Fix splatting being treated as positional parameter in completions (#14623)
(Thanks @MartinGC94)
Add completions for comment-based help keywords (#15337) (Thanks
@MartinGC94)
Add completion for Requires statements (#14596) (Thanks @MartinGC94)
Added tab completion for View parameter of Format-* cmdlets (#14513) (Thanks
@iSazonov)
PowerShell
PowerShell
) Important
Be sure to include the parameter MaximumVersion or you could install version 3 (or
higher) of
PSDesireStateConfiguration that contains significant differences.
Engine updates
Add LoadAssemblyFromNativeMemory function to load assemblies in memory from a
native PowerShell
host by awakecoding · Pull Request #14652
Designed for cloud, on-premises, and hybrid environments, PowerShell 7 is packed with
enhancements
and new features.
PowerShell 7 works side-by-side with Windows PowerShell letting you easily test and
compare between
editions before deployment. Migration is simple, quick, and safe.
PowerShell 7 also runs on macOS and several Linux distributions. For a list of supported
operating
systems and information about the support lifecycle, see the PowerShell Support
Lifecycle.
Installing PowerShell 7
For flexibility and to support the needs of IT, DevOps engineers, and developers, there are
several
options available to install PowerShell 7. In most cases, the installation options can be
reduced to
the following methods:
7 Note
The MSI package can be deployed and updated with management products such as
System Center Configuration Manager (SCCM). Download the packages from
GitHub
Release page .
Deploying the MSI package requires Administrator permission. The ZIP package can be
deployed by any
user. The ZIP package is the easiest way to install PowerShell 7 for testing,
before committing to a
full installation.
You may also install PowerShell 7 via the Windows Store or winget . For more information
about both
of these methods, see the detailed instructions in Installing PowerShell on
Windows.
The new location is added to your PATH allowing you to run both Windows PowerShell 5.1
and
PowerShell 7. If you're migrating from PowerShell 6.x to PowerShell 7, PowerShell 6 is
removed and
the PATH replaced.
Separate PSModulePath
By default, Windows PowerShell and PowerShell 7 store modules in different locations.
PowerShell 7
combines those locations in the $Env:PSModulePath environment variable.
When importing a module by
name, PowerShell checks the location specified by
$Env:PSModulePath . This allows PowerShell 7 to
load both Core and Desktop modules.
AllUsers
scope
CurrentUser
scope
The following examples show the default values of $Env:PSModulePath for each version.
PowerShell
Output
C:\Users\<user>\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules
For PowerShell 7:
PowerShell
Output
C:\Users\<user>\Documents\PowerShell\Modules
C:\Program Files\PowerShell\Modules
C:\Program Files\PowerShell\7\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules
Notice that PowerShell 7 includes the Windows PowerShell paths and the PowerShell 7 paths
to provide
autoloading of modules.
7 Note
Additional paths may exist if you have changed the PSModulePath environment variable
or installed
custom modules or applications.
Separate profiles
A PowerShell profile is a script that executes when PowerShell starts. This script customizes
your
environment by adding commands, aliases, functions, variables, modules, and
PowerShell drives. The
profile script makes these customizations available in every session
without having to manually
recreate them.
PowerShell
CurrentUserAllHosts : C:\Users\<user>\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\
<user>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
7 Note
PowerShell Remoting
PowerShell remoting lets you run any PowerShell command on one or more remote
computers. You can
establish persistent connections, start interactive sessions, and run
scripts on remote computers.
WS-Management remoting
Windows PowerShell 5.1 and below use the WS-Management (WSMAN) protocol for
connection negotiation
and data transport. Windows Remote Management (WinRM) uses
the WSMAN protocol. If WinRM has been
enabled, PowerShell 7 uses the existing Windows
PowerShell 5.1 endpoint named Microsoft.PowerShell
for remoting connections. To update
PowerShell 7 to include its own endpoint, run the
Enable-PSRemoting cmdlet. For information
about connecting to specific endpoints, see
WS-Management Remoting in PowerShell
To use Windows PowerShell remoting, the remote computer must be configured for remote
management.
For more information, including instructions, see About Remote Requirements.
For more information about working with remoting, see About Remote
SSH-based remoting
SSH-based remoting was added in PowerShell 6.x to support other operating systems that
can't use
Windows native components like WinRM. SSH remoting creates a PowerShell host
process on the
target computer as an SSH subsystem. For details and examples on setting up
SSH-based remoting on
Windows or Linux, see: PowerShell remoting over SSH.
7 Note
The PowerShell Gallery (PSGallery) contains a module and cmdlet that automatically
configures
SSH-based remoting. Install the Microsoft.PowerShell.RemotingTools
module from the
PSGallery and run the Enable-SSH cmdlet.
The New-PSSession , Enter-PSSession , and Invoke-Command cmdlets have new parameter sets
to
support SSH connections.
PowerShell
To create a remote session, specify the target computer with the HostName parameter and
provide
the user name with UserName. When running the cmdlets interactively, you're
prompted for a
password.
PowerShell
Alternatively, when using the HostName parameter, provide the username information
followed by
the at sign ( @ ), followed by the computer name.
PowerShell
You may set up SSH key authentication using a private key file with the KeyFilePath
parameter.
For more information, see OpenSSH Key Management.
PowerShell
Output
PowerShell
To make the transition to Visual Studio Code easier, use the Enable ISE Mode function
available
in the Command Palette. This function switches VSCode into an ISE-style layout.
The ISE-style
layout gives you all the new features and capabilities of PowerShell in a familiar
user experience.
To switch to the new ISE layout, press Ctrl + Shift + P to open the
Command Palette, type
PowerShell and select PowerShell: Enable ISE Mode.
To set the layout to the original layout, open the Command Palette, select
PowerShell:
Disable ISE Mode (restore to defaults).
7 Note
There are no plans to update the ISE with new features. In the latest versions of
Windows 10 or
Windows Server 2019 and higher, the ISE is now a user-uninstallable
feature. There are no plans to
permanently remove the ISE. The PowerShell Team and its
partners are focused on improving the
scripting experience in the PowerShell extension
for Visual Studio Code.
Next Steps
Armed with the knowledge to effectively migrate, install PowerShell 7 now!
Differences between Windows
PowerShell 5.1 and PowerShell 7.x
Article • 11/17/2022
Windows PowerShell 5.1 is built on top of the .NET Framework v4.5. With the release of
PowerShell
6.0, PowerShell became an open source project built on .NET Core 2.0.
Moving from the .NET Framework
to .NET Core allowed PowerShell to become a cross-
platform solution. PowerShell runs on Windows,
macOS, and Linux.
There are few differences in the PowerShell language between Windows PowerShell and
PowerShell. The
most notable differences are in the availability and behavior of
PowerShell cmdlets between Windows
and non-Windows platforms and the changes
that stem from the differences between the .NET Framework
and .NET Core.
This article summarizes the significant differences and breaking changes between
Windows PowerShell
and the current version of PowerShell. This summary does not
include new features or cmdlets that
have been added. Nor does this article discuss
what changed between versions. The goal of this
article is to present the current state of
PowerShell and how that is different from Windows
PowerShell. For a detailed
discussion of changes between versions and the addition of new features,
see the
What's New articles for each version.
Each new release of PowerShell is built on a newer version of .NET. There can be
breaking changes in
.NET that affect PowerShell.
PowerShell 7.3 - Built on .NET 7.0
PowerShell 7.2 (LTS-current) - Built on .NET 6.0 (LTS-current)
PowerShell 7.1 - Built on .NET 5.0
PowerShell 7.0 (LTS) - Built on .NET Core 3.1 (LTS)
PowerShell 6.2 - Built on .NET Core 2.1
PowerShell 6.1 - Built on .NET Core 2.1
PowerShell 6.0 - Built on .NET Core 2.0
With the advent of .NET Standard 2.0 , PowerShell can load many traditional Windows
PowerShell modules without modification. Additionally, PowerShell 7 includes a
Windows PowerShell
Compatibility feature that allows you to use Windows PowerShell
modules that still require the full
framework.
about_Windows_PowerShell_Compatibility
PowerShell 7 module compatibility
ISE
Microsoft.PowerShell.LocalAccounts
Microsoft.PowerShell.ODataUtils
Microsoft.PowerShell.Operation.Validation
PSScheduledJob
PSWorkflow
PSWorkflowUtility
PowerShell Workflow
PowerShell Workflow is a feature in Windows PowerShell that builds on top of
Windows
Workflow Foundation (WF) that enables the creation of robust runbooks
for long-
running or parallelized tasks.
Due to the lack of support for Windows Workflow Foundation in .NET Core, we removed
PowerShell
Workflow from PowerShell.
CimCmdlets
Export-BinaryMiLog
Microsoft.PowerShell.Core
Add-PSSnapin
Export-Console
Get-PSSnapin
Remove-PSSnapin
Resume-Job
Suspend-Job
Microsoft.PowerShell.Diagnostics
Export-Counter
Import-Counter
Microsoft.PowerShell.Management
Add-Computer
Checkpoint-Computer
Clear-EventLog
Complete-Transaction
Disable-ComputerRestore
Enable-ComputerRestore
Get-ComputerRestorePoint
Get-ControlPanelItem
Get-EventLog
Get-Transaction
Get-WmiObject
Invoke-WmiMethod
Limit-EventLog
New-EventLog
New-WebServiceProxy
Register-WmiEvent
Remove-Computer
Remove-EventLog
Remove-WmiObject
Reset-ComputerMachinePassword
Restore-Computer
Set-WmiInstance
Show-ControlPanelItem
Show-EventLog
Start-Transaction
Test-ComputerSecureChannel
Undo-Transaction
Use-Transaction
Write-EventLog
Microsoft.PowerShell.Utility
Convert-String
ConvertFrom-String
PSDesiredStateConfiguration
Disable-DscDebug
Enable-DscDebug
Get-DscConfiguration
Get-DscConfigurationStatus
Get-DscLocalConfigurationManager
Publish-DscConfiguration
Remove-DscConfigurationDocument
Restore-DscConfiguration
Set-DscLocalConfigurationManager
Start-DscConfiguration
Stop-DscConfiguration
Test-DscConfiguration
Update-DscConfiguration
WMI v1 cmdlets
The following WMI v1 cmdlets were removed from PowerShell:
Register-WmiEvent
Set-WmiInstance
Invoke-WmiMethod
Get-WmiObject
Remove-WmiObject
The CimCmdlets module (aka WMI v2) cmdlets perform the same function and provide
new functionality
and a redesigned syntax.
.NET Core does not support the Windows Communication Framework, which provide
services for using the
SOAP protocol. This cmdlet was removed because it requires
SOAP.
These cmdlets had very limited usage. The decision was made to discontinue support
for them.
Complete-Transaction
Get-Transaction
Start-Transaction
Undo-Transaction
Use-Transaction
*-EventLog cmdlets
Due to the use of unsupported APIs, the *-EventLog cmdlets have been removed from
PowerShell.
Get-WinEvent and New-WinEvent are available to get and create events on
Windows.
Changed the first positional parameter from -Command to -File . This change fixes
the usage of
#! (aka as a shebang) in PowerShell scripts that are being executed
from non-PowerShell shells
on non-Windows platforms. It also means that you can
run commands like pwsh foo.ps1 or
pwsh fooScript without specifying -File .
However, this change requires that you explicitly
specify -c or -Command when
trying to run commands like pwsh.exe -Command Get-Command .
pwsh accepts the -i (or -Interactive ) switch to indicate an interactive shell.
This
allows PowerShell to be used as a default shell on Unix platforms.
Removed parameters -ImportSystemModules and -PSConsoleFile from pwsh.exe .
Changed pwsh -version and built-in help for pwsh.exe to align with other native
tools.
Invalid argument error messages for -File and -Command and exit codes consistent
with Unix
standards
Added -WindowStyle parameter on Windows. Similarly, package-based
installations updates on
non-Windows platforms are in-place updates.
The shortened name is also consistent with naming of shells on non-Windows
platforms.
PowerShell process to
implicitly run any cmdlets contained in that module. For more
information, see Import-Module.
For more information on which Microsoft modules work with PowerShell 7.0, see the
Module Compatibility Table .
ENABLE_MU
Engine changes
Support PowerShell as a default Unix shell
On Unix, it is a convention for shells to accept -i for an interactive shell and many tools
expect this behavior ( script for example, and when setting PowerShell as the default
shell) and
calls the shell with the -i switch. This change is breaking in that -i
previously could be used
as short hand to match -inputformat , which now needs to be
-in .
Custom snap-ins
PowerShell snap-ins are a predecessor to PowerShell modules that do not have
widespread
adoption in the PowerShell community.
Due to the complexity of supporting snap-ins and their lack of usage in the community,
we no longer
support custom snap-ins in PowerShell.
$? is not set to $false when native command writes to stderr . It is common for native
commands
to write to stderr without intending to indicate a failure. $? is set to $false
only when the
native command has a non-zero exit code.
The -Encoding value Byte has been removed from the filesystem provider cmdlets. A
new parameter,
-AsByteStream , is now used to specify that a byte stream is required as
input or that the output
is a stream of bytes.
behavior of
$ErrorActionPreference .
For example:
PowerShell
function SimpleTest {
param(
$Name,
$Path
In the previous behavior, MyPath is not bound to -Path because it's the third argument
in the
argument list. ## So it ends up being stuffed into '$args' along with Blah =
"World"
PowerShell
With this change, the arguments from @hash are moved to the end of the argument list.
MyPath
becomes the first argument in the list, so it is bound to -Path .
PowerShell
Language changes
Null-coalescing operator ??
The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null.
Otherwise, it evaluates the right-hand operand and returns its result. The ?? operator
doesn't
evaluate its right-hand operand if the left-hand operand evaluates to non-null.
PowerShell
$x = $null
$x ?? 100
Output
100
PowerShell
$todaysDate ?? (Get-Date).ToShortDateString()
Output
1/10/2020
non-null.
PowerShell
$x = $null
$x ??= 100
$x
Output
100
PowerShell
Output
1/10/2020
Null-conditional operators
7 Note
Since PowerShell allows ? to be part of the variable name, formal specification of the
variable
name is required for using these operators. So it is required to use {} around
the variable names
like ${a} or when ? is part of the variable name ${a?} .
PowerShell
$a = @{ PropName = 100 }
${a}?.PropName
Output
100
The following example will return null, without trying to access the member
name
PropName.
PowerShell
$a = $null
${a}?.PropName
PowerShell
$a = 1..10
${a}?[0]
Output
And when the operand is null, the element isn't accessed and null is returned.
PowerShell
$a = $null
${a}?[0]
7 Note
The variable name syntax of ${<name>} should not be confused with the $()
subexpression
operator. For more information, see Variable name section of
about_Variables.
PowerShell
$PSCustomObject = [pscustomobject]@{foo = 1}
$PSCustomObject.Length
Output
PowerShell
$PSCustomObject.Count
Output
1
This work also includes ForEach and Where methods that allow you to operate and filter
on
PSCustomObject items:
PowerShell
$PSCustomObject.ForEach({$_.foo + 1})
Output
PowerShell
Output
foo
---
PowerShell
class M {
[long] $res = 0
foreach($s in $values){
$res += $selector.Invoke($s)
return $res
[M]::AggregateString((gci).Name, [M]::DoubleStrLen)
PowerShell
Output
True
New cmdlets
Disable-ExperimentalFeature
Enable-ExperimentalFeature
Get-ExperimentalFeature
With ConciseView, if an error is not from a script or parser error, then it's a single line
error message:
PowerShell
Output
If the error occurs during script execution or is a parsing error, PowerShell returns a
multiline
error message that contains the error, a pointer, and an error message showing
where the error is in
that line. If the terminal doesn't support ANSI color escape
sequences (VT100), then colors are not
displayed.
The default view in PowerShell 7 is ConciseView. The previous default view was
NormalView
and you can select this by setting the preference variable $ErrorView .
PowerShell
7 Note
The new Get-Error cmdlet provides a complete detailed view of the fully qualified error
when
desired. By default the cmdlet displays the full details, including inner exceptions,
of the last
error that occurred.
The Get-Error cmdlet supports input from the pipeline using the built-in variable
$Error .
Get-Error displays all piped errors.
PowerShell
$Error | Get-Error
The Get-Error cmdlet supports the Newest parameter, allowing you to specify how
many errors
from the current session you wish displayed.
PowerShell
Get-Error -Newest 3 # Displays the lst three errors that occurred in the
session
By default, parallel script blocks use the current working directory of the caller that
started the
parallel tasks.
This example retrieves 50,000 log entries from 5 system logs on a local Windows
machine:
PowerShell
$logNames = 'Security','Application','System','Windows
PowerShell','Microsoft-Windows-Store/Operational'
} -ThrottleLimit 5
$logEntries.Count
50000
The Parallel parameter specifies the script block that is run in parallel for each input log
name.
The new ThrottleLimit parameter limits the number of script blocks running in parallel
at a
given time. The default is 5.
Use the $_ variable to represent the current input object in the script block. Use the
$using:
scope to pass variable references to the running script block.
You can override this behavior to show all modules using the -SkipEditionCheck switch
parameter.
We've also added a PSEdition property to the table output.
We created a standard parameter alias -lp for all the built-in PowerShell cmdlets that
have a
-LiteralPath parameter.
Rename-Computer
Restart-Computer
Stop-Computer
Changes to Format-Hex
The -Raw parameter is now a "no-op" (in that it does nothing). Going forward all output
is
displayed with a true representation of numbers that includes all of the bytes for its
type. This is
what the -Raw parameter was doing prior to this change.
correct spelling.
MACTripleDES
RIPEMD160
Get-Credential -UserName
Get-Event -SourceIdentifier
Get-EventSubscriber -SourceIdentifier
Get-Help -Name
Get-PSBreakpoint -Script
Get-PSProvider -PSProvider
Get-PSSessionConfiguration -Name
Get-Runspace -Name
Get-RunspaceDebug -RunspaceName
Get-Service -Name
Get-TraceSource -Name
Get-Variable -Name
Previously, the Import-Csv cmdlet cannot be used to directly import the log files in W3C
extended
log format and additional action would be required. With this change, W3C
extended log format is
supported.
Previously, the Export-CSV cmdlet would output a comment as the first line containing
the type
name of the object. The change excludes the type information by default
because it's not understood
by most CSV tools. This change was made to address
customer feedback.
PowerShell
Output
Count : 308
Average : 31.3720576298701
Sum : 9662.59375
Maximum : 4416.046875
Minimum :
StandardDeviation : 264.389544720926
Property : CPU
Get-PfxCertificate -Password
Get-PfxCertificate now has the Password parameter, which takes a SecureString . This
allows you
to use it non-interactively:
PowerShell
$certFile = '\\server\share\pwd-protected.pfx'
PowerShell
C:\Windows\System32> cd C:\
C:\> cd -
C:\Windows\System32>
Or on Linux:
ShellSession
PS /etc> cd /usr/bin
PS /usr/bin> cd -
PS /etc>
Update-Help as non-admin
Where-Object -Not
With the addition of -Not parameter to Where-Object , can filter an object at the pipeline
for
the non-existence of a property, or a null/empty property value.
For example, this command returns all services that don't have any dependent services
defined:
PowerShell
always returns a
BasicHtmlWebResponseObject object. The ParsedHtml and Forms
properties have been removed.
BasicHtmlWebResponseObject.Headers values are now String[] instead of String .
BasicHtmlWebResponseObject.BaseResponse is now a
System.Net.Http.HttpResponseMessage object.
exceed the
provided limit instead of returning the results of the last redirection.
In PowerShell 6.2, a change was made to default to UTF-8 encoding for JSON
responses. When a
charset is not supplied for a JSON response, the default
encoding should be UTF-8 per RFC 8259.
Default encoding set to UTF-8 for application-json responses
Added -SkipHeaderValidation parameter to allow Content-Type headers that
aren't
standards-compliant
Added -Form parameter to support simplified multipart/form-data support
Compliant, case-insensitive handling of relation keys
Added -Resume parameter for web cmdlets
Invoke-RestMethod returns useful info when no data is
returned
When an API returns just null , Invoke-RestMethod was serializing this as the string
"null"
instead of $null . This change fixes the logic in Invoke-RestMethod to properly
serialize a valid
single value JSON null literal as $null .
Beginning in PowerShell 7.1, the OutFile parameter of the web cmdlets works like
LiteralPath
and does not process wildcards.
API changes
CommandInvocationIntrinsics.InvokeScript bind
arguments to $input instead of $args
An incorrect position of a parameter resulted in the args passed as input instead of as
args.
The ClrVersion property of $PSVersionTable is not useful with CoreCLR. End users
should not be
using that value to determine compatibility.
The BuildVersion property was tied to the Windows build version, which is not available
on
non-Windows platforms. Use the GitCommitId property to retrieve the exact build
version of
PowerShell.
value which
itself is an array.
When the value is converted to the delegate return type, the PSObject essentially
gets
unwrapped. So the PSObject is unneeded.
When the delegate return type is object , it gets wrapped in a PSObject making it
hard to work
with in C# code.
Remoting Support
PowerShell Remoting (PSRP) using WinRM on Unix platforms requires NTLM/Negotiate
or Basic Auth over
HTTPS. PSRP on macOS only supports Basic Auth over HTTPS.
Kerberos-based authentication is not
supported for non-Windows platforms.
PowerShell also supports PowerShell Remoting (PSRP) over SSH on all platforms
(Windows, macOS, and
Linux). For more information, see SSH remoting in PowerShell.
In the past, PowerShell Direct connected using the built-in Windows PowerShell instance
on the
Container. Now, PowerShell Direct first attempts to connect using any available
pwsh.exe on the
PATH environment variable. If pwsh.exe isn't available, PowerShell
One for the major version of PowerShell. For example, PowerShell.6 . This endpoint
that can be
relied upon across minor version updates as the "system-wide"
PowerShell 6 session configuration
One version-specific session configuration, for example: PowerShell.6.1.0
This behavior is useful if you want to have multiple PowerShell 6 versions installed and
accessible
on the same machine.
Additionally, preview versions of PowerShell now get their own remoting session
configurations after
running the Enable-PSRemoting cmdlet:
PowerShell
C:\WINDOWS\system32> Enable-PSRemoting
Output
Then you can see separate PowerShell session configurations for the preview and stable
builds of
PowerShell 6, and for each specific version.
PowerShell
Get-PSSessionConfiguration
Output
Name : PowerShell.6.2-preview.1
PSVersion : 6.2
StartupScript :
RunAsUser :
Name : PowerShell.6-preview
PSVersion : 6.2
StartupScript :
RunAsUser :
Name : powershell.6
PSVersion : 6.1
StartupScript :
RunAsUser :
Name : powershell.6.1.0
PSVersion : 6.1
StartupScript :
RunAsUser :
SSH clients typically support a connection string in the format user@host:port . With the
addition
of SSH as a protocol for PowerShell Remoting, we've added support for this
format of connection
string:
PowerShell strives to provide feature parity across all supported platforms. But, due to
differences
in .NET Core and platform-specific differences, some features behave
differently or aren't
available. Additional changes have been made to improve
interoperability of PowerShell on
non-Windows platforms.
Execution policy
The -ExecutionPolicy parameter is ignored when running PowerShell on non-Windows
platforms.
Get-ExecutionPolicy returns Unrestricted on Linux and macOS. Set-
ExecutionPolicy does
nothing on Linux and macOS.
Case-sensitivity in PowerShell
Historically, PowerShell has been uniformly case-insensitive, with few exceptions. On
UNIX-like
operating systems, the file system is predominantly case-sensitive and
PowerShell adheres to the
standard of the file system.
module's name.
Logging
On macOS, PowerShell uses the native os_log APIs to log to Apple's unified logging
system .
On Linux, PowerShell uses Syslog , a ubiquitous logging solution.
Job Control
There is no Unix-style job-control support in PowerShell on Linux or macOS. The fg and
bg
commands aren't available. You can use PowerShell jobs that do work across all
platforms.
Putting & at the end of a pipeline causes the pipeline to be run as a PowerShell job.
When a
pipeline is backgrounded, a job object is returned. Once the pipeline is running
as a job, all
*-Job cmdlets can be used to manage the job. Variables (ignoring process-
specific variables) used
in the pipeline are automatically copied to the job so Copy-Item
$foo $bar & just works. The job
is also run in the current directory instead of the user's
home directory.
Remoting Support
PowerShell Remoting (PSRP) using WinRM on Unix platforms requires NTLM/Negotiate
or Basic Auth over
HTTPS. PSRP on macOS only supports Basic Auth over HTTPS.
Kerberos-based authentication isn't
supported.
PowerShell supports PowerShell Remoting (PSRP) over SSH on all platforms (Windows,
macOS, and
Linux). For more information, see SSH remoting in PowerShell.
Just-Enough-Administration (JEA) Support
The ability to create constrained administration (JEA) remoting endpoints isn't available
in
PowerShell on Linux or macOS.
Missing Cmdlets
A large number of the commands (cmdlets) normally available in PowerShell aren't
available on Linux
or macOS. In many cases, these commands make no sense on these
platforms (e.g. Windows-specific
features like the registry). Other commands like the
service control commands are present, but not
functional. Future releases may correct
these problems by fixing the broken cmdlets and adding new
ones over time.
For a comprehensive list of modules and cmdlets and the platforms they support, see
Release history of modules and cmdlets.
ISE
Microsoft.PowerShell.LocalAccounts
Microsoft.PowerShell.ODataUtils
Microsoft.PowerShell.Operation.Validation
PSScheduledJob
PSWorkflow
PSWorkflowUtility
CimCmdlets
Microsoft.PowerShell.Diagnostics
Microsoft.WSMan.Management
PSDiagnostics
Microsoft.PowerShell.Archive
Microsoft.PowerShell.Core
Microsoft.PowerShell.Host
Microsoft.PowerShell.Management
Microsoft.PowerShell.Security
Microsoft.PowerShell.Utility
PackageManagement
PowerShellGet
PSDesiredStateConfiguration
PSReadLine
ThreadJob
However, some cmdlets have been removed from PowerShell, and others aren't
available or may work
differently on non-Windows platforms. For a comprehensive list
of cmdlets removed from PowerShell,
see Cmdlets removed from PowerShell.
Microsoft.PowerShell.Core
The ShowWindow parameter of Get-Help isn't available for non-Windows platforms.
Microsoft.PowerShell.Security cmdlets
The following cmdlets aren't available on Linux or macOS:
Get-Acl
Set-Acl
Get-AuthenticodeSignature
Set-AuthenticodeSignature
New-FileCatalog
Test-FileCatalog
Protect-CmsMessage
Unprotect-CmsMessage
Microsoft.PowerShell.Management cmdlets
The following cmdlets aren't available on Linux and macOS:
Clear-RecycleBin
Get-HotFix
Microsoft.PowerShell.Utility cmdlets
The following cmdlets aren't available on Linux and macOS:
Convert-String
ConvertFrom-String
Out-GridView
Out-Printer
Show-Command
Alias Cmdlet
ac Add-Content
cat Get-Content
clear Clear-Host
cnsn Connect-PSSession
Alias Cmdlet
compare Compare-Object
cp Copy-Item
cpp Copy-ItemProperty
diff Compare-Object
dnsn Disconnect-PSSession
gsv Get-Service
kill Stop-Process
ls Get-ChildItem
man help
mount New-PSDrive
mv Move-Item
ogv Out-GridView
ps Get-Process
rm Remove-Item
rmdir Remove-Item
sasv Start-Service
shcm Show-Command
sleep Start-Sleep
sort Sort-Object
spsv Stop-Service
start Start-Process
tee Tee-Object
write Write-Output
For more information about using DSC on Linux, see Get started with DSC for Linux.
This article lists the modules and cmdlets that are included in various versions of
PowerShell. This
is a summary of information found in the release notes. More detailed
information can be found in
the release notes:
Microsoft.PowerShell.Archive
Microsoft.PowerShell.Core
Microsoft.PowerShell.Host
Microsoft.PowerShell.Management
Microsoft.PowerShell.Security
Microsoft.PowerShell.Utility
PackageManagement
CimCmdlets
Get-IseSnippet
Import-IseSnippet
New-IseSnippet
Microsoft.PowerShell.Archive
Compress-Archive
Expand-Archive
Microsoft.PowerShell.Core
Add-History
Clear-History
Clear-Host
Debug-Job
Enter-PSSession
Exit-PSSession
Export-ModuleMember
ForEach-Object
Get-Command
Get-Help
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Get-History
Get-Job
Get-Module
Get-PSSession
Get-PSSessionCapability
Get-PSSessionConfiguration
Get-Verb Moved to
Microsoft.PowerShell.Utility 6.0+
Import-Module
Invoke-Command
Invoke-History
New-Module
New-ModuleManifest
New-PSRoleCapabilityFile
New-PSSession
New-PSSessionOption
New-PSTransportOption
Out-Default
Out-Host
Out-Null
Receive-Job
Register-ArgumentCompleter
Remove-Job
Remove-Module
Remove-PSSession
Resume-Job
Save-Help
Set-PSDebug
Set-StrictMode
Start-Job
Stop-Job
Test-ModuleManifest
Update-Help
Wait-Job
Where-Object
Microsoft.PowerShell.Diagnostics
Microsoft.PowerShell.Host
Start-Transcript
Stop-Transcript
Add-LocalGroupMember
Disable-LocalUser
Enable-LocalUser
Get-LocalGroup
Get-LocalGroupMember
Get-LocalUser
New-LocalGroup
New-LocalUser
Remove-LocalGroup
Remove-LocalGroupMember
Remove-LocalUser
Rename-LocalGroup
Cmdlet name 5.1 Note
Rename-LocalUser
Set-LocalGroup
Set-LocalUser
Microsoft.PowerShell.Management
Add-Content
Clear-Content
Clear-Item
Clear-ItemProperty
Convert-Path
Copy-Item
Copy-ItemProperty
Debug-Process
Get-ChildItem
Get-Clipboard NotsupportedonmacOS
Get-Content
Get-Item
Get-ItemProperty
Get-ItemPropertyValue
Get-Location
Get-Process
Get-PSDrive
Get-PSProvider
Invoke-Item
Join-Path
Move-Item
Move-ItemProperty
New-Item
New-ItemProperty
New-PSDrive
Pop-Location
Push-Location
Remove-Item
Remove-ItemProperty
Remove-PSDrive
Rename-Item
Rename-ItemProperty
Resolve-Path
Set-Clipboard
Set-Content
Set-Item
Set-ItemProperty
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Set-Location
Split-Path
Start-Process
Stop-Process
Test-Connection
Test-Path
Wait-Process
Microsoft.PowerShell.ODataUtils
This modules is only available in Windows PowerShell.
Export-ODataEndpointProxy
Microsoft.PowerShell.Operation.Validation
This modules is only available in Windows PowerShell.
Get-OperationValidation
Invoke-OperationValidation
Microsoft.PowerShell.Security
ConvertFrom-
SecureString
ConvertTo-SecureString
Get-Credential
Get-PfxCertificate
Microsoft.PowerShell.Utility
Add-Member
Add-Type
Clear-Variable
Compare-Object
ConvertFrom-Csv
ConvertFrom-Json
ConvertFrom-String
ConvertFrom-
StringData
Convert-String
ConvertTo-Csv
ConvertTo-Html
ConvertTo-Json
ConvertTo-Xml
Debug-Runspace
Disable-PSBreakpoint
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Disable-
RunspaceDebug
Enable-PSBreakpoint
Enable-RunspaceDebug
Export-Alias
Export-Clixml
Export-Csv
Export-FormatData
Export-PSSession
Format-Custom
Format-Hex
Format-List
Format-Table
Format-Wide
Get-Alias
Get-Culture
Get-Date
Get-Error
Get-EventSubscriber
Get-FileHash
Get-FormatData
Get-Host
Get-Member
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Get-PSBreakpoint
Get-PSCallStack
Get-Random
Get-Runspace
Get-RunspaceDebug
Get-TraceSource
Get-TypeData
Get-UICulture
Get-Unique
Get-Uptime
Get-Variable
Group-Object
Import-Alias
Import-Clixml
Import-Csv
Import-LocalizedData
Import-
PowerShellDataFile
Import-PSSession
Invoke-Expression
Invoke-RestMethod
Invoke-WebRequest
Join-String
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Measure-Command
Measure-Object
New-Alias
New-Guid
New-Object
New-TemporaryFile
New-TimeSpan
New-Variable
Out-File
Out-String
Read-Host
Register-ObjectEvent
Remove-Alias
Remove-PSBreakpoint
Remove-TypeData
Remove-Variable
Select-Object
Select-String
Select-Xml
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Send-MailMessage
Set-Alias
Set-Date
Set-PSBreakpoint
Set-TraceSource
Set-Variable
Sort-Object
Start-Sleep
Tee-Object
Test-Json
Trace-Command
Update-FormatData
Update-List
Update-TypeData
Wait-Debugger
Wait-Event
Write-Debug
Write-Error
Write-Host
Write-Information
Cmdlet name 5.1 7.2 7.3 7.4 Note
(preview)
Write-Output
Write-Progress
Write-Verbose
Write-Warning
Microsoft.WsMan.Management
PackageManagement
Find-Package
Find-PackageProvider
Cmdlet name 5.1 7.2 7.3 7.4 (preview) Note
Get-Package
Get-PackageProvider
Get-PackageSource
Import-PackageProvider
Install-Package
Install-PackageProvider
Register-PackageSource
Save-Package
Set-PackageSource
Uninstall-Package
Unregister-PackageSource
PowershellGet 2.x
Find-Command
Find-DscResource
Find-Module
Find-RoleCapability
Find-Script
Get-CredsFromCredentialProvider
Get-InstalledModule
Get-InstalledScript
Get-PSRepository
Install-Module
Install-Script
New-ScriptFileInfo
Cmdlet name 5.1 7.2 7.3 7.4 (preview) Note
Publish-Module
Publish-Script
Register-PSRepository
Save-Module
Save-Script
Set-PSRepository
Test-ScriptFileInfo
Uninstall-Module
Uninstall-Script
Unregister-PSRepository
Update-Module
Update-ModuleManifest
Update-Script
Update-ScriptFileInfo
Name Note
Find-PSResource
Get-InstalledPSResource
Get-PSResourceRepository
Install-PSResource
Publish-PSResource
Register-PSResourceRepository
Save-PSResource
Set-PSResourceRepository
Name Note
Uninstall-PSResource
Unregister-PSResourceRepository
Update-PSResource
PSDesiredStateConfiguration v1.1
This modules is only available from in Windows PowerShell.
Configuration
Disable-DscDebug
Enable-DscDebug
Get-DscConfiguration
Get-DscConfigurationStatus
Get-DscLocalConfigurationManager
Get-DscResource
Invoke-DscResource
New-DSCCheckSum
Publish-DscConfiguration
Remove-DscConfigurationDocument
Restore-DscConfiguration
Set-DscLocalConfigurationManager
Start-DscConfiguration
Stop-DscConfiguration
Test-DscConfiguration
Update-DscConfiguration
PSDesiredStateConfiguration v2.0.5
This modules is only available from the PowerShell Gallery.
Configuration
Get-DscResource
Invoke-DscResource Experimental
New-DSCCheckSum
Configuration
ConvertTo-DscJsonSchema
Get-DscResource
Invoke-DscResource Experimental
New-DscChecksum
PSDiagnostics
PSReadLine
Get-PSReadLineKeyHandler
Get-PSReadLineOption
PSConsoleHostReadLine
Remove-PSReadLineKeyHandler
Set-PSReadLineKeyHandler
Set-PSReadLineOption
PSScheduledJob
This modules is only available in Windows PowerShell.
Add-JobTrigger
Disable-JobTrigger
Disable-ScheduledJob
Enable-JobTrigger
Enable-ScheduledJob
Get-JobTrigger
Get-ScheduledJob
Get-ScheduledJobOption
New-JobTrigger
New-ScheduledJobOption
Register-ScheduledJob
Remove-JobTrigger
Cmdlet name 5.1 Note
Set-JobTrigger
Set-ScheduledJob
Set-ScheduledJobOption
Unregister-ScheduledJob
New-PSWorkflowExecutionOption
New-PSWorkflowSession
Invoke-AsWorkflow
ThreadJob
The PowerShell team is working with the various feature teams that create PowerShell
modules to help
them produce modules that work in PowerShell 7. These modules are
not owned by the PowerShell team.
Azure PowerShell
The Az PowerShell module is a set of cmdlets for managing Azure resources directly
from PowerShell.
PowerShell 7.0.6 LTS or higher is the recommended version of
PowerShell for use with the Azure Az
PowerShell module on all platforms.
These modules are installed in different ways depending on the Edition of Windows, and
how the
module is packaged for that Edition.
SqlServer: This module includes new cmdlets to support the latest SQL features,
including
updated versions of the cmdlets in SQLPS.
SQLPS: The SQLPS is the module used by SQL Agent to run agent jobs in agent job
steps using
the PowerShell subsystem.
If you are interested in PowerShell 7 and later, you need to install PowerShell instead of
Windows
PowerShell. For more information, see
Installing PowerShell on Windows.
The following tables should help you find PowerShell in your Windows version. All
versions listed
here are the original version, as released, with no updates.
For Console
For Windows 10 and 11 - Click Windows icon (lower left corner for Windows 10,
lower center for
Windows 11), start typing PowerShell.
For Windows 8.1 - On the start screen, start typing PowerShell. If on desktop, click
left lower
corner Windows icon, start typing PowerShell.
For ISE
For Windows 10 and 11 - Click Windows icon (lower left corner for Windows 10,
lower center for
Windows 11), start typing ISE.
For Windows 8.1 - On the start screen, type PowerShell ISE. If on desktop, click left
lower
corner Windows icon, type PowerShell ISE.
Type powershell and press ENTER to start PowerShell inside the command prompt
session.
Type exit to close the PowerShell session and return to command prompt.
The only exception to the above rule is the ISE in Windows Server 2008 R2 SP1. In this
case, click
the left lower corner Windows icon, type PowerShell ISE.
If you need to update your existing version of PowerShell, in Windows, use the following
table to
locate the installer for the version of PowerShell you want to update to.
Windows 11
- - - installed
Windows Server 2022
Windows 8.1
- installed not supported WMF 5.1
Windows Server 2012 R2
Windows 8
installed not supported not supported WMF 5.1
Windows Server 2012
Windows PS 3.0 PS 4.0 PS 5.0 PS 5.1
Windows 7 SP1
not supported not supported not supported WMF 5.1
Windows Server 2008 R2 SP1
7 Note
On the initial release of Windows 10, with automatic updates enabled, PowerShell
gets updated from
version 5.0 to 5.1. If the original version of Windows 10 is not
updated through Windows Updates,
the version of PowerShell is 5.0.
See Also
Windows PowerShell System Requirements
Starting Windows PowerShell
Installing the Windows PowerShell 2.0
Engine
Article • 10/25/2022
This topic explains how to install the Windows PowerShell 2.0 Engine.
To maintain backward compatibility with commands and host programs that are
affected by these
changes, the Windows PowerShell 2.0, Windows PowerShell 3.0, and
Windows PowerShell 4.0 engines are
designed to run side-by-side. Also, the Windows
PowerShell 2.0 Engine is included in Windows Server
2012 R2, Windows 8.1, Windows 8,
Windows Server 2012, and Windows Management Framework 3.0. The
Windows
PowerShell 2.0 Engine is intended to be used only when an existing script or host
program
cannot run because it is incompatible with Windows PowerShell 3.0, Windows
PowerShell 4.0, or
Microsoft .NET Framework 4. Such cases are expected to be rare.
The Windows PowerShell 2.0 Engine is an optional feature of Windows Server 2012 R2,
Windows 8.1,
Windows 8 and Windows Server 2012. On earlier versions of Windows,
when you install Windows
Management Framework 3.0, the Windows PowerShell 3.0
installation completely replaces the Windows
PowerShell 2.0 installation in the Windows
PowerShell installation directory. However, the Windows
PowerShell 2.0 Engine is
retained.
For information about starting the Windows PowerShell 2.0 Engine, see
Starting the
Windows PowerShell 2.0 Engine.
2. On the Apps bar, click Settings, and then click Turn Windows features on or off.
3. In the Windows Features box, click .NET Framework 3.5 (includes .NET 2.0 and
3.0 to
select it.
When you select .NET Framework 3.5 (includes .NET 2.0 and 3.0, the box fills to
indicate that
only part of the feature is selected. However, this is sufficient for the
Windows PowerShell 2.0
Engine.
Or in Server Manager, click All Servers, right-click a server name, and then select
Add Roles and Features.
3. On the Features page, expand the .NET 3.5 Framework Features node and select
.NET
Framework 3.5 (includes .NET 2.0 and 3.0).
The other options under that node are not required for the Windows PowerShell
2.0 Engine.
To add the Windows PowerShell 2.0 Engine feature
In Server Manager, from the Manage menu, select Add Roles and Features.
Or Server Manager, click All Servers, right-click a server name, and then select
Add
Roles and Features.
On the Features page, expand the Windows PowerShell (Installed) node and
select Windows
PowerShell 2.0 Engine.
For information about starting the Windows PowerShell 2.0 Engine, see
Starting the
Windows PowerShell 2.0 Engine.
See Also
Windows PowerShell System Requirements
Installing Windows PowerShell
Starting Windows PowerShell)
Starting the Windows PowerShell 2.0 Engine
Windows PowerShell System
Requirements
Article • 10/25/2022
This article lists the system requirements for Windows PowerShell 3.0, Windows
PowerShell 4.0,
Windows PowerShell 5.0, and Windows PowerShell 5.1. And, special
features, such as Windows
PowerShell Integrated Scripting Environment (ISE), Common
Information Model (CIM) commands, and
workflows.
Windows 8.1 and Windows Server 2012 R2 include all required programs. This article is
designed for
users of earlier releases of Windows.
Windows Server 2008 R2 with Service Pack 1 Install Windows Management Framework 5.1
Windows Server 2008 R2 with Service Pack 1 Install Windows Management Framework 5.1
WS-Management 3.0
Windows PowerShell 3.0 and Windows PowerShell 4.0 require WS-Management 3.0,
which supports the
WinRM service and WSMan protocol. This program is included in
Windows 8.1, Windows Server 2012 R2,
Windows 8, Windows Server 2012, Windows
Management Framework 4.0, and Windows Management Framework
3.0.
Some items require a graphical user interface. For details, see the help article for each
item.
Windows PowerShell Integrated Scripting Environment (ISE). For more information,
see
Introducing the Windows PowerShell ISE.
Cmdlets
Out-GridView
Show-Command
Show-ControlPanelItem
Show-EventLog
Parameters
ShowWindow parameter of the Get-Help cmdlet.
ShowSecurityDescriptorUI parameter of the
Register-PSSessionConfiguration
and
Set-PSSessionConfiguration
cmdlets.
However, due to a change in the runtime activation policy in Microsoft .NET Framework
4, Windows
PowerShell host programs that were written for Windows PowerShell 2.0
and compiled with Common
Language Runtime (CLR) 2.0 can't run without modification
in Windows PowerShell 3.0, which is
compiled with CLR 4.0.
For information about adding or installing the Windows PowerShell 2.0 engine, and
adding or
installing the required versions of the Microsoft .NET Framework, see
Installing the Windows PowerShell 2.0 Engine. For
information about starting the
Windows PowerShell 2.0 engine, see
Starting the Windows PowerShell 2.0 Engine.
See also
Installing Windows PowerShell
Starting Windows PowerShell
Windows Management Framework
Optimizing your shell experience
Article • 12/01/2022
Similar to other shells like bash or cmd.exe , PowerShell allows you to run any command
available
on your system, not just PowerShell commands.
Windows PowerShell 5.0 includes significant new features that extend its use, improve
its usability,
and allow you to control and manage Windows-based environments more
easily and comprehensively.
To install Windows PowerShell 5.0 on Windows Server 2012 R2, Windows 8.1 Enterprise,
or Windows 8.1
Pro, download and install Windows Management Framework 5.0 . Be
sure to read the download
details, and meet all system requirements, before you install
Windows Management Framework 5.0.
In this topic
Windows PowerShell 4.0 DSC updates in KB 3000850
New features in Windows PowerShell 5.0
New features in Windows PowerShell 4.0
New features in Windows PowerShell 3.0
Language enhancements
DependsOn now supports composite resources.
DependsOn now supports numbers in resource instance names.
Node expressions that evaluate to empty no longer throw errors.
An error that occurs if a node expression evaluates to empty has been fixed.
Configurations calling configurations now work in the Windows PowerShell
console.
Resiliency improvements
New DebugMode lets you reload resource modules.
If a configuration failure occurs, the pending.mof file is not deleted.
The Local Configuration Manager (LCM) is now more resilient when
metaconfiguration settings have
become corrupted.
Diagnostic improvements
A warning is displayed when the LCM sets the timer to different settings than
you have
specified.
Error log files now contain the call stack for Windows PowerShell resources.
Flexibility improvements
The LocalConfigurationManager resource has a new property,
ActionAfterReboot.
ContinueConfiguration (default value): Automatically resumes a configuration
after a target
node restarts.
StopConfiguration: Do not automatically resume a configuration after a node
restarts.
A consistency run can now occur more often than a PULL operation, or vice-
versa.
Versioning support: DSC can now recognize a document that was generated on
a newer client
(included with WMF 5.0 ).
A new language keyword, Hidden, has been added to specify that a member (a
property or a
method) is not shown by default in Get-Member results (unless you
add the -Force parameter).
Properties or methods that have been marked hidden
also do not show up in IntelliSense results,
unless you are in a context where the
member should be visible; for example, the automatic
variable $This should show
hidden members when in the class method.
Get-ChildItem also has a new -Depth parameter, which you use with the -Recurse
parameter to limit
the recursion. For example, Get-ChildItem -Recurse -Depth 2
returns results from the current
folder, all of the child folders within the current
folder, and all of the folders within the
child folders.
Copy-Item now lets you copy files or folders from one Windows PowerShell
session to another,
meaning that you can copy files to sessions that are connected
to remote computers, (including
computers that are running Nano Server, and thus
have no other interface). To copy files, specify
PSSession IDs as the value of the
new -FromSession and -ToSession parameters, and add -Path and
-Destination to
specify origin path and destination, respectively. For example, Copy-Item -Path
c:\myFile.txt -ToSession $s -Destination d:\destinationFolder.
A new detailed script tracing feature lets you enable detailed tracking and analysis
of Windows
PowerShell scripting use on a system. After you enable detailed script
tracing, Windows PowerShell
logs all script blocks to the Event Tracing for
Windows (ETW) event log,
Microsoft-Windows-PowerShell/Operational.
The Out-File, Add-Content, and Set-Content cmdlets now have a new -NoNewline
parameter, which
omits a new line after the output.
The New-Guid cmdlet leverages the .NET Framework Guid class to generate a
GUID, useful when you
are writing scripts or DSC resources.
A new state, AtBreakpoint, has been added for Windows PowerShell jobs. The
AtBreakpoint state
applies when a job is running a script that includes set
breakpoints, and the script has hit a
breakpoint. When a job is stopped at a debug
breakpoint, you must debug the job by running the
Debug-Job cmdlet.
You can now perform module version validation by running the Test-
ModuleManifest cmdlet.
Results of the Get-Command cmdlet now display a Version column; a new Version
property has been
added to the CommandInfo class. Get-Command shows
commands from multiple versions of the same
module. The Version property is
also part of derived classes of CmdletInfo: CmdletInfo and
ApplicationInfo.
Get-Command has a new parameter, -ShowCommandInfo, that returns
ShowCommand information as
PSObjects. This is especially useful functionality for
when Show-Command is run in Windows
PowerShell ISE using Windows
PowerShell remoting. The -ShowCommandInfo parameter replaces the
existing
Get-SerializedCommand function in the Microsoft.PowerShell.Utility module, but
the
Get-SerializedCommand script is still available to support downlevel scripting.
A new Get-ItemPropertyValue cmdlet lets you get the value of a property without
using dot
notation. For example, in older releases of Windows PowerShell, you can
run the following command
to get the value of the Application Base property of
the PowerShellEngine registry key:
(Get-ItemProperty -Path
HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name
ApplicationBase).ApplicationBase. Starting in Windows PowerShell 5.0, you can
run
Get-ItemPropertyValue -Path
HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name
ApplicationBase.
The Windows PowerShell console now uses syntax coloring, just as in Windows
PowerShell ISE.
A new NetworkSwitch module contains cmdlets that enable you to apply switch,
virtual LAN (VLAN),
and basic Layer 2 network switch port configuration to
Windows Server 2012 R2 logo-certified
network switches.
WMF 5.0 (PowerShell 5.0) includes the Pester module. Pester is a unit testing
framework for
PowerShell. It provides a few simple-to-use keywords that let you
create tests for your scripts.
Windows PowerShell 4.0 is installed by default on Windows 8.1 and Windows Server
2012 R2. To install
Windows PowerShell 4.0 on Windows 7 with SP1, or Windows Server
2008 R2, download and install
Windows Management Framework 4.0. Be sure to read
the download details, and meet all system
requirements, before you install Windows
Management Framework 4.0.
Workflows are also portable; they can be exported as or imported from XAML files. You
can write
custom session configurations that allow workflow or activities in a workflow
to be run by delegated
or subordinate users.
Disconnected Sessions
Beginning in Windows PowerShell 3.0, persistent user-managed sessions ("PSSessions")
that you create
using the New-PSSession cmdlet are saved on the remote computer.
They are no longer dependent on
the session in which they were created.
You can now disconnect from a session without disrupting the commands that are
running in the
session. You can close the session and shut down your computer. Later,
you can reconnect to the
session from a different session on the same or on a different
computer.
The ComputerName parameter of the Get-PSSession cmdlet now gets all of the user's
sessions
that connect to the computer, even if they were started in a different session on
a different
computer. You can connect to the sessions, get the results of commands,
start new commands, and then
disconnect from the session.
New cmdlets have been added to support the Disconnected Sessions feature, including
Disconnect-PSSession , Connect-PSSession , and Receive-PSSession , and new parameters
have been
added to cmdlets that manage PSSessions, such as the
InDisconnectedSession parameter of the
Invoke-Command cmdlet.
The Disconnected Sessions feature is supported only when the computers at both the
originating
("client") and terminating ("server") ends of the connection are running
Windows PowerShell 3.0.
If the disconnected session was started using the InvokeCommand, Windows PowerShell
creates a job
for the disconnected session to make it easier to reconnect and resume
execution.
These features provide a more reliable and recoverable remoting experience and allow
users to
perform long-running tasks that require robust sessions, such as workflows.
To support users who don't have Internet access and users behind firewalls, the new
Save-Help
cmdlet downloads help files to a file system directory, such as a file share.
You can use the Update-Help cmdlet to update help files for all or particular modules in
all
supported UI cultures. You can even put an Update-Help command in your Windows
PowerShell profile.
By default, Windows PowerShell downloads the help files for a
module no more than once each day.
Windows 8 and Windows Server 2012 modules do not include help files. To download
the latest help
files, type Update-Help . For more information, type Get-Help (without
parameters) or see
about_Updatable_Help.
When the help files for a cmdlet are not installed on the computer, the Get-Help cmdlet
now
displays auto-generated help. The auto-generated help includes the command
syntax and instructions
for using the Update-Help cmdlet to download help files.
Any module author can support Updatable Help for their module. You can include help
files in the
module and use Updatable Help to update them or omit the help files and
use Updatable Help to
install them. For more information about supporting Updatable
Help, see
Supporting Updatable Help.
Windows PowerShell opens the online version of the help topic in your default Internet
browser.
The Get-Help -Online feature in Windows PowerShell 3.0 is now even more powerful
because it
works even when help files for the cmdlet are not installed on the computer.
The Get-Help
-Online feature gets the URI for online help topic from the HelpUri
property of cmdlets and
advanced functions.
PS C:\>(Get-Command Get-ScheduledJob).HelpUri
https://go.microsoft.com/fwlink/?LinkID=223923
Beginning in Windows PowerShell 3.0, authors of C# cmdlets can populate the HelpUri
property by
creating a HelpUri attribute on the cmdlet class. Authors of advanced
functions can define a
HelpUri property on the CmdletBinding attribute. The value of
the HelpUri property must
begin with "http" or "https".
You can also include a HelpUri value in the first related link of an XML-based cmdlet
help file
or the .Link directive of comment-based help in a function.
For more information about supporting online help, see Supporting Online Help.
CIM integration
Windows PowerShell 3.0 includes support for the Common Information Model (CIM),
which provides
common definitions of management information for systems, networks,
applications, and services,
allowing them the exchange of management information
between heterogeneous systems. Support for CIM
in Windows PowerShell 3.0, including
the ability to author Windows PowerShell cmdlets based on new
or existing CIM classes,
commands based on cmdlet definition XML files, support for CIM .NET
Framework. API,
CIM management cmdlets and WMI 2.0 providers.
You can design a session in which users can only run the cmdlets from one particular
module, or a
session in which users have full language, access to all modules, and access
to scripts that perform
advanced tasks.
In previous versions of Windows PowerShell, control at this level was available only to
those who
could write a C# program or a complex start-up script. Now, any member of
the Administrators group
on the computer can customize a session configuration using
a configuration file.
Like Windows PowerShell background jobs, scheduled jobs run asynchronously in the
background.
Instances of scheduled jobs that have completed can be managed using
the job cmdlets, such as
Start-Job and Get-Job .
Like Task Scheduler tasks, you can run scheduled jobs on a one-time or recurrent
schedule, or in
response to an action or event. You can view and manage scheduled jobs
in Task Scheduler, enable and
disable them as needed, run them or use them as
templates, and set conditions under which the jobs
start.
In addition, scheduled jobs come with a customized set of cmdlets for managing them.
The cmdlets let
you create, edit, manage, disable, and re-enable scheduled jobs, create
scheduled job triggers and
set scheduled job options.
CimCmdlets
Get-CimAssociatedInstance
Get-CimClass
Get-CimInstance
Get-CimSession
Invoke-CimMethod
New-CimInstance
New-CimSession
New-CimSessionOption
Register-CimIndicationEvent
Remove-CimInstance
Remove-CimSession
Set-CimInstance
Microsoft.PowerShell.Core
Connect-PSSession
Disconnect-PSSession
New-PSSessionConfigurationFile
New-PSTransportOption
Receive-PSSession
Resume-Job
Save-Help
Suspend-Job
Test-PSSessionConfigurationFile
Update-Help
Microsoft.PowerShell.Diagnostics
New-WinEvent
Microsoft.PowerShell.Management
Get-ControlPanelItem
Rename-Computer
Show-ControlPanelItem
Microsoft.PowerShell.Utility
ConvertFrom-Json
ConvertTo-Json
Get-TypeData
Invoke-RestMethod
Invoke-WebRequest
Remove-TypeData
Show-Command
Unblock-File
PSScheduledJob
Add-JobTrigger
Disable-JobTrigger
Disable-ScheduledJob
Enable-JobTrigger
Enable-ScheduledJob
Get-JobTrigger
Get-ScheduledJob
Get-ScheduledJobOption
New-JobTrigger
New-ScheduledJobOption
Register-ScheduledJob
Set-JobTrigger
Set-ScheduledJob
Set-ScheduledJobOption
Unregister-ScheduledJob
PSWorkflow
New-PSWorkflowExecutionOption
New-PSWorkflowSession
PSWorkflowUtility
Invoke-AsWorkflow
ISE
Get-IseSnippet
Import-IseSnippet
New-IseSnippet
For more information, see the help topics for the Get-Module and Import-Module
cmdlets.
Module Auto-Loading
The Get-Command cmdlet now gets all cmdlets and functions from all modules that are
installed on
the computer, even if the module is not imported into the current session.
When you get the cmdlet that you need, you can use it immediately without importing
any modules.
Windows PowerShell modules are now imported automatically when you
use any cmdlet in the module. You
no longer need to search for the module and import
it to use its cmdlets.
You can enable, disable, and configure automatic importing of modules using the
$PSModuleAutoLoadingPreference preference variable.
The new Show-Command cmdlet is designed especially for beginners. You can search for
commands in a
window. You can view all commands or filter by module, import a
module by clicking a button, use
text boxes and drop-down lists to construct a valid
command, and then copy or run the command
without ever leaving the window.
Performance Improvements
Significant performance improvements in Windows PowerShell come from the new
language parser, which
is built on Dynamic Runtime Language (DLR) in .NET Framework
4., along with runtime script
compilation, engine reliability improvements, and changes
to the algorithm of the Get-ChildItem
that improve its performance, especially when
searching network shares.
The RunAs feature, designed for Windows PowerShell Workflow, lets users of a session
configuration
create sessions that run with the permission of a shared user account. This
enables less privileged
users to run particular commands and scripts with administrator
permissions, and reduces the need
for adding less senior users to the Administrators
group.
The SharedHost feature allows multiple users on multiple computers to connect to a
workflow
session concurrently and monitor the progress of a workflow. Users can start a
workflow on one
computer and then connect to the workflow session on another
computer without disconnecting the
session from the original computer. Users must
have the same permissions and be using the same
session configuration. For more
information, see "Running a Windows PowerShell Workflow" in Getting
Started with
Windows PowerShell Workflow.
See Also
about_Windows_PowerShell_5.0
Windows PowerShell
What's New in the Windows PowerShell
5.0 ISE
Article • 10/06/2021
This article explains the new and updated features that have been introduced in version
5.0 of the
Windows PowerShell Integrated Scripting Environment (ISE).
7 Note
There is no support for the ISE in PowerShell v6 and beyond. Users looking for
replacement for the
ISE should use Visual Studio Code with the
PowerShell
Extension .
Feature description
The Windows PowerShell ISE is a host application that enables you to write, run, and test
scripts
and modules in a graphical and intuitive environment. Key features such as
syntax-coloring, tab
completion, visual debugging, Unicode compliance, and context-
sensitive Help provide a rich
scripting experience.
The following table lists the new and changed features for this release of Windows
PowerShell ISE in
Windows PowerShell.
IntelliSense
Added in ISE 3.0
When you type cmdlets in the Windows PowerShell ISE, a scrollable and clickable menu
displays,
allowing you to browse and select the appropriate commands.
Snippets
Added in ISE 3.0
Snippets are short sections of Windows PowerShell code that you can insert into the
scripts you
create in Windows PowerShell ISE. Windows PowerShell ISE comes with a
default set of snippets. You
can add snippets by using the New-Snippet cmdlet while
working in Windows PowerShell ISE.
By using snippets, you can quickly assemble and create scripts to automate your
environment.
To use snippets in Windows PowerShell 3.0 or later, on the Edit menu, click Start
Snippets,
or press Ctrl + J .
Add-on tools
Added in PowerShell 3.0
Windows PowerShell ISE now supports add-on tools using the object model. These add-
ons are Windows
Presentation Foundation (WPF) controls that are displayed as a vertical
or horizontal pane in the
console. Multiple add-on tools in a pane are displayed as a
tabbed control. You can also add or
remove add-on tools that are produced by non-
Microsoft parties. For more information, see
The Purpose of the Windows PowerShell ISE
Scripting Object Model.
Windows PowerShell ISE 3.0 and later come with the Commands add-on. The
Commands add-on
allows you to browse cmdlets, and access help about the cmdlets
side-by-side with the Script and
Console Panes.
Additional add-ons can be found by using the Open Add-on Tools Website command
on the
Add-ons menu.
Windows PowerShell ISE now automatically saves your open scripts every two minutes,
in a separate
location. When Windows PowerShell ISE restarts after an unexpected crash
or reboot, it recovers
scripts that were open in the last session, even if the scripts
weren't saved.
To change the automatic saving interval, run the following command in the Console
pane:
$psise.Options.AutoSaveMinuteInterval .
You can now work within Windows PowerShell ISE knowing that your open scripts are
automatically
saved.
Windows PowerShell ISE now has a most-recently used list for files. When you open a
file in Windows
PowerShell ISE, the file is added to the most-recently used list on the
File menu.
To change the default number of files in the most-recently used list, run the following
command in
the Console Pane: $psise.Options.MruCount .
You can now use the most-recently used list to easily access your frequently used files.
Console Pane
Added in PowerShell 3.0
The separate Command and Output Panes that were available in the first release of
Windows PowerShell
ISE have been combined into a single Console Pane. The Console
Pane is similar in function and
appearance to a typical Windows PowerShell console, but
it includes the following enhancements:
Syntax coloring for input text (not output text), including XML syntax
IntelliSense
Brace matching
Error indication
Full Unicode support
F1 context-sensitive help
Ctrl + F1 context-sensitive Show-Command
Complex script and right-to-left support
Font support
Zoom
Line-select and block-select modes
Preservation of typed content at the command line when you press the UpArrow to
view history
in the console
The addition of these Console Pane changes provides a scripting experience that is more
consistent
with the console interface.
Windows PowerShell ISE 2.0 has separate Command and Output Panes.
Command-line switches
Added in PowerShell 3.0
If you start Windows PowerShell ISE from the command line (by typing
powershell_ise.exe), you
can add the following new command-line switches.
The addition of these command-line switches allows you to control the environment in
which the
Windows PowerShell ISE runs.
XML syntax coloring - Windows PowerShell ISE now colors XML syntax in the
same way as it colors
Windows PowerShell syntax.
Brace matching - Windows PowerShell ISE includes brace matching and
highlighting, and can be
used in the following ways: (for example, using the Go to
Match command or
Ctrl + ] locates the closing brace, if you have an opening
brace selected).
Outline view The Script Pane supports outlining, which allows collapsing or
expanding sections
of code by clicking plus or minus signs in the left margin. You
can use braces or the #region
and #endregion tags to mark the beginning or end
of a collapsible section. To expand or collapse
all regions, press Ctrl + M .
Drag and drop text editing - Windows PowerShell ISE now supports drag and
drop text editing. You
can select any block of text and drag that text to another
location in the editor or the console
to move the text. If you hold down the Ctrl
key while you drag the selected text, when
you release the mouse button the text
is copied to the new location. In this version of Windows
PowerShell ISE, when you
drag and drop files onto Windows PowerShell ISE, Windows PowerShell ISE
opens
the file.
Parse error display - Parse errors are indicated with red underlines. When you
hover over an
indicated error, tooltip text displays the problem that was found in
the code.
Zoom - The zoom percentage of the console's content can be set by using the
zoom slider (in the
lower right corner of Windows PowerShell ISE window), or by
entering the command
$psise.options.Zoom in the Console Pane.
Rich text copy and paste - Copying to the clipboard in Windows PowerShell ISE
preserves the
font, size, and color information of the original selection.
Block selection - You can select a block of text by holding down the ALT key while
selecting text in the Script Pane with your mouse, or by pressing
Alt + Shift +
Arrow .
The additional editing features provide a more consistent and powerful editing
environment.
If you press F1 when your cursor is in a cmdlet, or you have part of a cmdlet
highlighted, the new Help viewer opens context-sensitive Help about the highlighted
cmdlet. To
display Windows PowerShell About help, type operators in the console pane,
and then press
F1 .
Before you use this feature, download the most current version of Windows PowerShell
Help topics
from the Microsoft website. The simplest method for downloading the Help
topics is to run the
Update-Help cmdlet in the Console Pane when running Windows
PowerShell ISE as administrator.
You can alter where the F1 key looks for Help. In the Tools/Options menu, on the
General Settings tab, under Other Settings, you can set or clear the checkbox Use local
help content instead of online content. When checked, the client looks for the cmdlet
Help in the
downloaded Help found in the modules folder. If the checkbox is cleared,
the client looks for help
online.
Pressing F1 in previous versions of Windows PowerShell ISE opened the help file on the
local computer. In Windows PowerShell ISE 3.0 and later, a window opens that contains
the help for
the cmdlet that is searchable and configurable. This Help experience is new
for Windows PowerShell
ISE 3.0, and Updatable Help is new for Windows PowerShell 3.0.
Show-Command cmdlet
Added in PowerShell 3.0
The Show-Command cmdlet enables you to compose or run a cmdlet or function by filling
in a
graphical form. The form lets users work with Windows PowerShell in a graphical
environment.
Show-Command also enables advanced scripters to create a quick Windows
PowerShell-based GUI.
By using Show-Command in your Windows PowerShell scripts, you can provide your users
with the
graphical environment with which they're familiar. Show-Command can also help
introductory users
learn Windows PowerShell.
See also
For more information about using Windows PowerShell ISE, see
Exploring the Windows
PowerShell Integrated Scripting Environment.
The Windows PowerShell ISE
Article • 10/07/2021
The Windows PowerShell Integrated Scripting Environment (ISE) is a host application for
Windows
PowerShell. In the ISE, you can run commands and write, test, and debug
scripts in a single
Windows-based graphic user interface. The ISE provides multiline
editing, tab completion, syntax
coloring, selective execution, context-sensitive help, and
support for right-to-left languages. Menu
items and keyboard shortcuts are mapped to
many of the same tasks that you would do in the Windows
PowerShell console. For
example, when you debug a script in the ISE, you can right-click on a line
of code in the
edit pane to set a breakpoint.
Support
The ISE was first introduced with Windows PowerShell V2 and was re-designed with
PowerShell V3. The
ISE is supported in all supported versions of Windows PowerShell up
to and including Windows
PowerShell V5.1.
7 Note
There is no support for the ISE in PowerShell v6 and beyond. Users looking for
replacement for the
ISE should use Visual Studio Code with the
PowerShell
Extension .
Key Features
Key features in Windows PowerShell ISE include:
Multiline editing: To insert a blank line under the current line in the Command
pane, press
SHIFT + ENTER .
Selective execution: To run part of a script, select the text you want to run, and
then click the
Run Script button. Or, press F5 .
Context-sensitive help: Type Invoke-Item , and then press F1 . The Help file opens
to
the article for the Invoke-Item cmdlet.
The Windows PowerShell ISE lets you customize some aspects of its appearance. It also
has its own
Windows PowerShell profile script.
You can use the Windows PowerShell Integrated Scripting Environment (ISE) to create,
run, and debug
commands and scripts.
The Windows PowerShell ISE consists of the menu bar, Windows PowerShell tabs,
the
toolbar, script tabs, a Script Pane, a Console Pane, a status bar, a text-size slider and
context-sensitive Help.
Menu Bar
The menu bar contains the File, Edit, View, Tools, Debug, Add-ons, and
Help menus.
The buttons on the menus allow you to perform tasks related to writing and running
scripts and
running commands in the Windows PowerShell ISE. Additionally, an add-on
tool may be placed on
the menu bar by running scripts that use the The ISE Object
Model Hierarchy.
Toolbar
Button Function
New Remote Creates a new PowerShell Tab that establishes a session on a remote computer.
PowerShell A dialog box appears and prompts you to enter details required to establish the
Tab remote connection.
Show Script Moves the Script Pane to the top in the display.
Pane Top
Show Script Moves the Script Pane to the right in the display.
Pane Right
Button Function
Show Shows the Commands Pane for installed Modules, as a separate Window.
Command
Window
Show Shows the Commands Pane for installed Modules, as a sidebar Add-on.
Command
Add-on
For more information, see How to Create a PowerShell Tab in Windows PowerShell ISE.
Script Tab
Displays the name of the script you are editing. You can click a script tab to select the
script you
want to edit.
When you point to the script tab, the fully qualified path to the script file appears in a
tooltip.
Script Pane
Allows you to create and run scripts. You can open, edit and run existing scripts in the
Script
Pane. For more information, see How to Write and Run Scripts in the Windows
PowerShell ISE.
Console Pane
Displays the results of the commands and scripts you have run. You can run commands
in the Console
pane. You can also copy and clear the contents in the Console Pane.
Status Bar
Allows you to see whether the commands and scripts that you run are complete. The
status bar is at
the bottom of the window. Selected portions of error messages are
displayed on the status bar.
Text-Size Slider
Increases or decreases the size of the text on the screen.
Help
Help for Windows PowerShell ISE is available on Microsoft Learn. You can open the Help
by clicking
Windows PowerShell ISE Help on the Help menu or by pressing the F1 key
anywhere
except when the cursor is on a cmdlet name in either the Script Pane or the
Console Pane. From the
Help menu you can also run the Update-Help cmdlet, and
display the Command Window which
assists you in constructing commands by showing
you all the parameters for a cmdlet and enabling you
to fill in the parameters in an easy-
to-use form.
See Also
Introducing the Windows PowerShell ISE
How to Use Profiles in Windows PowerShell ISE
Accessibility in Windows PowerShell ISE
Keyboard Shortcuts for the Windows PowerShell ISE
How to Create a PowerShell Tab in
Windows PowerShell ISE
Article • 10/07/2021
Tabs in the Windows PowerShell Integrated Scripting Environment (ISE) allow you to
simultaneously
create and use several execution environments within the same
application. Each PowerShell tab
corresponds to a separate execution environment or
session.
7 Note
Variables, functions, and aliases that you create in one tab do not carry over to
another. They
are different Windows PowerShell sessions.
Use the following steps to open or close a tab in Windows PowerShell. To rename a tab,
set the
DisplayName property on the Windows
PowerShell Tab scripting object.
Note that clicking the New or Open icons on the toolbar does not create a new tab with
a
separate session. Instead, those buttons open a new or existing script file on the
currently active
tab with a session. You can have multiple script files open with each tab
and session. The script
tabs for a session only appear below the session tabs when the
associated session is active.
To make a PowerShell tab active, click the tab. To select from all PowerShell tabs that are
open, on
the View menu, click the PowerShell tab you want to use.
On the File menu, click Close PowerShell Tab, or click the Close button (X) on an
active tab to close the tab.
If you have unsaved files open in the PowerShell tab that you are closing, you are
prompted to save
or discard them. For more information about how to save a script, see
How to Save a Script.
See Also
Introducing the Windows PowerShell ISE
How to Use the Console Pane in the Windows PowerShell ISE
How to Debug Scripts in Windows
PowerShell ISE
Article • 03/20/2023
This article describes how to debug scripts on a local computer by using the Windows
PowerShell
Integrated Scripting Environment (ISE) visual debugging features.
You can set three types of breakpoints in the Windows PowerShell debugging
environment:
1. Line breakpoint. The script pauses when the designated line is reached during the
operation
of the script
2. Variable breakpoint. The script pauses whenever the designated variable's value
changes.
Of these, in the Windows PowerShell ISE debugging environment, only line breakpoints
can be set by
using the menu or the keyboard shortcuts. The other two types of
breakpoints can be set, but they
are set from the Console Pane by using the
Set-
PSBreakpoint cmdlet. This
section describes how you can perform debugging tasks in
Windows PowerShell ISE by using the menus
where available, and perform a wider range
of commands from the Console Pane by using scripting.
To set a breakpoint
A breakpoint can be set in a script only after it has been saved. Right-click the line where
you
want to set a line breakpoint, and then click Toggle Breakpoint. Or, click the line
where you
want to set a line breakpoint, and press F9 or, on the Debug menu, click
Toggle
Breakpoint.
The following script is an example of how you can set a variable breakpoint from the
Console Pane by
using the Set-PSBreakpoint
cmdlet.
PowerShell
On the Debug menu, click List Breakpoints. The following script is an example of how
you can
list all breakpoints from the Console Pane by using the
Get-PSBreakpoint
cmdlet.
PowerShell
Get-PSBreakpoint
Remove a breakpoint
Removing a breakpoint deletes it.
PowerShell
Remove-PSBreakpoint -Id 2
The following script is an example of how to remove all breakpoints from the Console
Pane by using
the Remove-PSBreakpoint
cmdlet.
PowerShell
Get-PSBreakpoint | Remove-PSBreakpoint
Disable a Breakpoint
Disabling a breakpoint does not remove it. It turns it off until it is enabled. To disable a
specific line breakpoint, right-click the line where you want to disable a breakpoint, and
then
click Disable Breakpoint.
Or, click the line where you want to disable a breakpoint, and press F9 or, on the
Debug menu, click Disable Breakpoint. The following script is an example of how you
can
remove a breakpoint with a specified ID from the Console Pane using the
Disable-
PSBreakpoint cmdlet.
PowerShell
Disable-PSBreakpoint -Id 0
PowerShell
Get-PSBreakpoint | Disable-PSBreakpoint
Enable a Breakpoint
To enable a specific breakpoint, right-click the line where you want to enable a
breakpoint, and
then click Enable Breakpoint. Or, click the line where you want to
enable a breakpoint, and then
press F9 or, on the Debug menu, click Enable
Breakpoint. The following script is
an example of how you can enable specific
breakpoints from the Console Pane by using the
Enable-PSBreakpoint cmdlet.
PowerShell
Enable-PSBreakpoint -Id 0, 1, 5
PowerShell
# You can abbreviate the command by using their aliases: "gbp | ebp".
Get-PSBreakpoint | Enable-PSBreakpoint
To start debugging
Press F5 or, on the toolbar, click the Run Script icon, or on the Debug menu
click
Run/Continue. The script runs until it encounters the first breakpoint. It pauses
operation there and highlights the line on which it paused.
To continue debugging
Press F5 or, on the toolbar, click the Run Script icon, or on the Debug menu,
click
Run/Continue or, in the Console Pane, type C and then press ENTER . This
causes the
script to continue running to the next breakpoint or to the end of the script if no
further
breakpoints are encountered.
While paused, to see the current call stack, press CTRL + SHIFT + D or,
on the Debug
menu, click Display Call Stack or, in the Console Pane, type K and then press
ENTER .
To stop debugging
Press SHIFT + F5 or, on the Debug menu, click Stop Debugger, or, in the
Console Pane,
type Q and then press ENTER .
Step Into Executes the current statement and then stops at the Press F11 or, on the
next statement. If the current statement is a function or Debug menu, click Step
script call, then the debugger steps into that function or Into, or in the Console
script, otherwise it stops at the next statement. Pane, type S and press
ENTER .
Debugging Description How to accomplish it
Task in PowerShell ISE
Step Over Executes the current statement and then stops at the Press F10 or, on the
next statement. If the current statement is a function or Debug menu, click Step
script call, then the debugger executes the whole Over, or in the Console
function or script, and it stops at the next statement Pane, type V and press
after the function call. ENTER .
Step Out Steps out of the current function and up one level if the Press SHIFT + F11 , or
function is nested. If in the main body, the script is on the Debug menu,
executed to the end, or to the next breakpoint. The click Step Out, or in the
skipped statements are executed, but not stepped Console Pane, type O
through. and press ENTER .
Continue Continues execution to the end, or to the next Press F5 or, on the
breakpoint. The skipped functions and invocations are Debug menu, click
executed, but not stepped through. Run/Continue, or in the
Console Pane, type C
and press ENTER .
In the Script Pane, hover over the variable to display its value as a tool tip.
In the Console Pane, type the variable name and press ENTER .
All panes in ISE are always in the same scope. Therefore, while you are debugging a
script, the
commands that you type in the Console Pane run in script scope. This allows
you to use the Console
Pane to find the values of variables and call functions that are
defined only in the script.
$_
$Input
$MyInvocation
$PSBoundParameters
$Args
If you try to display the value of any of these variables, you get the value of that variable
for in
an internal pipeline the debugger uses, not the value of the variable in the script.
You can work
around this for a few variables ( $_ , $Input , $MyInvocation ,
$PSBoundParameters , and $Args )
by using the following method:
1. In the script, assign the value of the automatic variable to a new variable.
2. Display the value of the new variable, either by hovering over the new variable in
the Script
Pane, or by typing the new variable in the Console Pane.
For example, to display the value of the $MyInvocation variable, in the script, assign the
value
to a new variable, such as $scriptName , and then hover over or type the
$scriptName variable to
display its value.
PowerShell
# In C:\ps-test\MyScript.ps1
$scriptName = $MyInvocation.PSCommandPath
PowerShell
.\MyScript.ps1
$scriptName
Output
C:\ps-test\MyScript.ps1
See Also
Exploring the Windows PowerShell ISE
How to Use Profiles in Windows
PowerShell ISE
Article • 10/07/2021
This article explains how to use Profiles in Windows PowerShell® Integrated Scripting
Environment
(ISE). We recommend that before performing the tasks in this section, you
review
about_Profiles, or in the
Console Pane, type, Get-Help about_Profiles and press
ENTER .
A profile is a Windows PowerShell ISE script that runs automatically when you start a
new session.
You can create one or more Windows PowerShell profiles for Windows
PowerShell ISE and use them to
add the configure the Windows PowerShell or Windows
PowerShell ISE environment, preparing it for
your use, with variables, aliases, functions,
and color and font preferences that you want
available. A profile affects every Windows
PowerShell ISE session that you start.
7 Note
The Windows PowerShell execution policy determines whether you can run scripts
and load a profile.
The default execution policy, "Restricted," prevents all scripts
from running, including profiles.
If you use the "Restricted" policy, the profile
cannot load. For more information about execution
policy, see
about_Execution_Policies.
The profile that you use is determined by how you use Windows PowerShell and
Windows PowerShell ISE.
If you use only Windows PowerShell ISE to run Windows PowerShell, then save all
your items in one
of the ISE-specific profiles, such as the CurrentUserCurrentHost
profile for Windows PowerShell
ISE or the AllUsersCurrentHost profile for
Windows PowerShell ISE.
If you use multiple host programs to run Windows PowerShell, save your functions,
aliases,
variables, and commands in a profile that affects all host programs, such as
the
CurrentUserAllHosts or the AllUsersAllHosts profile, and save ISE-specific
features, like color
and font customization in the CurrentUserCurrentHost profile
for Windows PowerShell ISE profile or
the AllUsersCurrentHost profile for
Windows PowerShell ISE.
The following are profiles that can be created and used in Windows PowerShell ISE. Each
profile is
saved to its own specific path.
PowerShell
To create a new "All users, Windows PowerShell ISE" profile, run this command:
PowerShell
To create a new "Current user, All Hosts" profile, run this command:
PowerShell
To edit a profile
1. To open the profile, run the command psEdit with the variable that specifies the
profile you want
to edit. For example, to open the "Current user, Windows
PowerShell ISE" profile, type:
psEdit $PROFILE
2. Add some items to your profile. The following are a few examples to get you
started:
To change the default background color of the Console Pane to blue, in the
profile file type:
$psISE.Options.OutputPaneBackground = 'blue' . For more
information about the $psISE
variable, see Windows PowerShell ISE Object
Model Reference.
To change font size to 20, in the profile file type: $psISE.Options.FontSize =20
3. To save your profile file, on the File menu, click Save. Next time you open the
Windows
PowerShell ISE, your customizations are applied.
See Also
about_Profiles
Introducing the Windows PowerShell ISE
How to Use Tab Completion in the
Script Pane and Console Pane
Article • 09/17/2021
Tab completion provides automatic help when you are typing in the Script Pane or in the
Command
Pane. Use the following steps to take advantage of this feature:
7 Note
In the Script Pane, pressing TAB will automatically complete a command only when
you are editing
.ps1 , .psd1 , or .psm1 files. Tab completion works any time when
you are typing in the Command Pane.
For example, type Get-Process - and then press TAB multiple times to display each of
the parameters for the cmdlet in turn.
See Also
Introducing the Windows PowerShell ISE
How to Create a PowerShell Tab
How to Use the Console Pane in the
Windows PowerShell ISE
Article • 09/17/2021
The Console pane in the Windows PowerShell Integrated Scripting Environment (ISE)
operates exactly
like the stand-alone Windows PowerShell ISE console window.
To run a command in the Console Pane, type a command, and then press ENTER . To
enter
multiple commands that you want to execute in sequence, type SHIFT + ENTER
Beginning in Windows PowerShell v3, the Output pane was combined with the Console
pane. This has the
benefit of behaving like the stand-alone Windows PowerShell console
and eliminates the differences
in procedures that were needed when they were
separate. You can:
Select and copy text from the Console pane to the Clipboard for pasting in any
other window. To
select text, click and hold the mouse in the output pane while
dragging the mouse over the text
you want to capture. You can also use the cursor
arrow keys while holding SHIFT to
select text. Then press CTRL + C or click the
Copy icon in the toolbar.
Paste the selected text at a current cursor position. Click the Paste icon on the
toolbar.
Clear all the text in the Console pane. To clear the Console pane, you can click the
Clear
Console Pane icon on the toolbar, or run the command Clear-Host or its
alias, cls .
See Also
Introducing the Windows PowerShell ISE
How to Write and Run Scripts in the
Windows PowerShell ISE
Article • 06/29/2022
This article describes how to create, edit, run, and save scripts in the Script Pane.
7 Note
The Windows PowerShell execution policy determines whether you can run scripts
and load Windows
PowerShell profiles and configuration files. The default
execution policy, Restricted, prevents
all scripts from running, and prevents loading
profiles. To change the execution policy to allow
profiles to load and be used, see
Set-ExecutionPolicy and
about_Signing.
If the file has been altered since it was last saved, you're prompted to save or discard it.
To run a script
On the toolbar, click Run Script, or on the File menu, click Run.
Pressing CTRL + C also works unless some text is currently selected, in which
case CTRL +
C maps to the copy function for the selected text.
2. Press CTRL + C or, on the toolbar, click the Copy icon, or on the
Edit menu, click
Copy.
To save a script
Press CTRL + S or, on the toolbar, click the Save icon, or on the File
menu, click Save.
The following command saves a new script as MyScript.ps1 with ASCII encoding.
PowerShell
$psISE.CurrentFile.SaveAs("MyScript.ps1", [System.Text.Encoding]::ASCII)
The following command replaces the current script file with a file with the same name,
but with
ASCII encoding.
PowerShell
$psISE.CurrentFile.Save([System.Text.Encoding]::ASCII)
PowerShell
$psISE.CurrentFile.encoding
Windows PowerShell ISE doesn't change the encoding of script files when you use the
Save or
Save As commands.
See Also
Exploring the Windows PowerShell ISE
Keyboard Shortcuts for the Windows
PowerShell ISE
Article • 10/25/2022
Help F1 Script Pane Important: You can specify that F1 help comes from
Microsoft Learn or downloaded Help (see Update-Help ). To select,
click Tools, Options, then on the General Settings tab, set or clear
Use local help content instead of online content.
New CTRL + N
Open CTRL + O
Run F5
Run F8
Selection
Action Keyboard Shortcut
Stop CTRL + BREAK . CTRL + C can be used when the context is unambiguous (when there
Execution is no text selected).
Tab (to CTRL + TAB Note: Tab to next script works only when you have a single Windows
next PowerShell tab open, or when you have more than one Windows PowerShell tab
script) open, but the focus is in the Script Pane.
Tab (to CTRL + SHIFT + TAB Note: Tab to previous script works when you have only one
previous Windows PowerShell tab open, or if you have more than one Windows PowerShell
script) tab open, and the focus is in the Script Pane.
Zoom In CTRL + +
Display Call Stack CTRL + SHIFT + D Script Pane, when debugging a script
Remove All Breakpoints CTRL + SHIFT + F9 Script Pane, when debugging a script
7 Note
You can also use the keyboard shortcuts designed for the Windows PowerShell
console when you debug
scripts in Windows PowerShell ISE. To use these shortcuts,
you must type the shortcut in the
Command Pane and press ENTER .
Repeat Last Command (for Step Into or ENTER Console Pane, when debugging a
Step Over) script
Previous PowerShell CTRL + SHIFT + TAB . This shortcut works only when no files are open on
tab any Windows PowerShell tab.
Next Windows CTRL + TAB . This shortcut works only when no files are open on any
PowerShell tab Windows PowerShell tab.
Exit ALT + F4
See Also
PowerShell Magazine: The Complete List of Windows PowerShell ISE Keyboard
Shortcuts
Accessibility in Windows PowerShell ISE
Article • 09/17/2021
How to change the size and location of the Console and Script Panes
Keyboard shortcuts for editing text
Keyboard shortcuts for running scripts
Keyboard shortcuts for customizing the view
Keyboard shortcuts for debugging scripts
Keyboard shortcuts for Windows PowerShell tabs
Keyboard shortcuts for starting and exiting
Breakpoint management with cmdlets
Microsoft is committed to making its products and services easier for everyone to use.
The following
topics provide information about the features, products, and services that
make Windows PowerShell
ISE more accessible for people with disabilities.
Keyboard Shortcuts
Syntax Coloring Table and the ability to modify several other color settings using
the
$psISE.Options scripting object.
To move the Script Pane above the Console Pane, press CTRL + 1 or, on the
toolbar, click the Show Script Pane Top icon, or in the View menu, click Show
Script
Pane Top.
To move the Script Pane to the right of the Console Pane, press CTRL + 2 or,
on the
toolbar, click the Show Script Pane Right icon, or in the View menu, click Show
Script Pane Right.
To maximize the Script Pane, press CTRL + 3 or, on the toolbar, click the
Show
Script Pane Maximized icon, or in the View menu, click Show Script Pane
Maximized.
To maximize the Console Pane and hide the Script Pane, on the far right edge of
the row of tabs,
click the Hide Script Pane icon, in the View menu, click to deselect
the Show Script
Pane menu option.
To display the Script Pane when the Console Pane is maximized, on the far right
edge of the row of
tabs, click the Show Script Pane icon, or in the View menu, click
to select the Show
Script Pane menu option.
New CTRL + N
Open CTRL + O
Run F5
Run F8
Selection
Stop CTRL + BREAK . CTRL + C can be used when the context is unambiguous (when there
Execution is no text selected).
Tab (to CTRL + TAB Note: Tab to next script works only when you have a single PowerShell
next tab open, or when you have more than one PowerShell tab open, but the focus is in
script) the Script Pane.
Tab (to CTRL + SHIFT + TAB Note: Tab to previous script works when you have only one
previous PowerShell tab open, or if you have more than one PowerShell tab open, and the
script) focus is in the Script Pane.
Display Call Stack CTRL + SHIFT + D Script Pane, when debugging a script
Remove All Breakpoints CTRL + SHIFT + F9 Script Pane, when debugging a script
7 Note
You can also use the keyboard shortcuts designed for the Windows PowerShell
console when you debug
scripts in Windows PowerShell ISE. To use these shortcuts,
you must type the shortcut in the
Console Pane and press ENTER .
Action Keyboard Use in
Shortcut
Previous PowerShell tab CTRL + SHIFT + TAB (Only when no files are open on any
PowerShell tab)
Next Windows PowerShell CTRL + TAB (Only when no files are open on any PowerShell tab)
tab
Keyboard shortcuts for starting and exiting
You can use the following keyboard shortcuts to start the Windows PowerShell console
(PowerShell.exe) or to exit Windows PowerShell ISE.
Exit ALT + F4
Breakpoint Management
For the visually impaired, breakpoint information is available through the cmdlets for
managing
breakpoints, such as
Get-PSBreakpoint and
Set-PSBreakpoint. For more
information please see 'How to manage breakpoints' in
How to Debug Scripts in the
Windows PowerShell ISE.
See Also
Introducing the Windows PowerShell ISE
Purpose of the Windows PowerShell ISE
Scripting Object Model
Article • 09/17/2021
Objects are associated with the form and function of Windows PowerShell Integrated
Scripting
Environment (ISE). The object model reference provides details about the
member properties and
methods that these objects expose. Examples are provided to
show how you can use scripts to
directly access these methods and properties. The
scripting object model makes the following range
of tasks easier.
Change the color of errors, warnings, verbose outputs, and debug outputs.
Get or set the background colors for the Command pane, the Output pane, and
the Script pane.
Set the foreground color for the Output pane.
Set the font name and font size for Windows PowerShell ISE.
Configure warnings. This setting includes warnings that are issued when a file is
opened
in multiple PowerShell tabs or when a script in the file is run before the file
has been saved.
Switch between a view where the Script pane and the Output pane are side-by-
side and a
view where the Script pane is on top of the Output pane.
Dock the Command pane to the bottom or the top of the Output pane.
Add and modify the instance of Windows PowerShell ISE itself. For example, to
change the menus,
you can add new menu items and map the new menu items to
scripts.
Create scripts that perform some of the tasks that you can perform by using the
menu commands and
buttons in Windows PowerShell ISE. For example, you can
add, remove, or select a PowerShell tab.
Complement tasks that can be performed by using menu commands and buttons.
For example, you can
rename a PowerShell tab.
Manipulate text buffers for the Command pane, the Output pane, and the Script
pane that are
associated with a file. For example, you can:
Get or set all text.
Get or set a text selection.
Run a script or run a selected portion of a script.
Scroll a line into view.
Insert text at a caret position.
Select a block of text.
Get the last line number.
Perform file operations. For example, you can:
Open a file, save a file, or save a file by using a different name.
Determine whether a file has been changed after it was last saved.
Get the file name.
Select a file.
Automating tasks
You can use the scripting object model to create keyboard shortcuts for frequent
operations.
See also
The ISE Object Model Hierarchy
The ISE Object Model Hierarchy
Article • 09/17/2021
This article shows the hierarchy of objects that are part of Windows PowerShell
Integrated Scripting
Environment (ISE). Windows PowerShell ISE is included in Windows
PowerShell 3.0, 4.0, and 5.1. Click
an object to take you to the reference documentation
for the class that defines the object.
$psISE Object
The $psISE object is the root object of the Windows PowerShell
ISE object hierarchy.
Located at the top level, it makes the following objects available for
scripting:
$psISE.CurrentFile
The $psISE.CurrentFile object is an instance of the ISEFile class.
$psISE.CurrentPowerShellTab
The $psISE.CurrentPowerShellTab object is an instance of the PowerShellTab class.
$psISE.CurrentVisibleHorizontalTool
The $psISE.CurrentVisibleHorizontalTool object is an instance of the ISEAddOnTool
class. It represents the installed add-on tool that is currently docked to the top edge of
the
Windows PowerShell ISE window.
$psISE.CurrentVisibleVerticalTool
The $psISE.CurrentVisibleHorizontalTool object is an instance of the ISEAddOnTool
class. It represents the installed add-on tool that is currently docked to the right-hand
edge of
the Windows PowerShell ISE window.
$psISE.Options
The $psISE.Options object is an instance of the ISEOptions class. The
ISEOptions object
represents various settings for Windows PowerShell ISE. It is an instance of the
Microsoft.PowerShell.Host.ISE.ISEOptions class.
$psISE.PowerShellTabs
The $psISE.PowerShellTabs object is an instance of the PowerShellTabCollection
class. It
is a collection of all the currently open PowerShell tabs that represent the available
Windows PowerShell run environments on the local computer or on connected remote
computers. Each
member in the collection is an instance of the PowerShellTab class.
See Also
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ObjectModelRoot Object
Article • 09/17/2021
The $psISE object, which is the principal root object in Windows PowerShell®
Integrated Scripting
Environment (ISE) is an instance of the
Microsoft.PowerShell.Host.ISE.ObjectModelRoot class. This
topic describes the
properties of the ObjectModelRoot object.
Properties
CurrentFile
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the file, which is associated with this host object that
currently
has the focus.
CurrentPowerShellTab
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the PowerShell tab that has the focus.
CurrentVisibleHorizontalTool
Supported in Windows PowerShell ISE 2.0 and later.
CurrentVisibleVerticalTool
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the currently visible Windows PowerShell ISE add-on
tool that is
located in the vertical tool pane on the right side of the editor.
Options
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the various options that can change settings in
Windows PowerShell
ISE.
PowerShellTabs
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the collection of the PowerShell tabs, which are open
in Windows
PowerShell ISE. By default, this object contains one PowerShell tab.
However, you can add more
PowerShell tabs to this object by using scripts or by using
the menus in Windows PowerShell ISE.
See Also
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEAddOnToolCollection Object
Article • 09/17/2021
Methods
Adds a new add-on tool to the collection. It returns the newly added add-on tool.
Before you run
this command, you must install the add-on tool on the local computer
and load the assembly.
Name - String
Specifies the display name of the add-on tool that is added to Windows
PowerShell ISE.
ControlType -Type
Specifies the control that is added.
PowerShell
[reflection.assembly]::LoadFile("c:\test\ISESimpleSolution\ISESimpleSolution
.dll")
$psISE.CurrentPowerShellTab.VerticalAddOnTools.Add("Solutions",
[ISESimpleSolution.Solution], $true)
Remove( Item )
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Item - Microsoft.PowerShell.Host.ISE.ISEAddOnTool
Specifies the object to be removed
from Windows PowerShell ISE.
PowerShell
# Load a DLL with an add-on and then add it to the ISE
[reflection.assembly]::LoadFile("c:\test\ISESimpleSolution\ISESimpleSolution
.dll")
$psISE.CurrentPowerShellTab.VerticalAddOnTools.Add("Solutions",
[ISESimpleSolution.Solution], $true)
SetSelectedPowerShellTab( psTab )
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
psTab - Microsoft.PowerShell.Host.ISE.PowerShellTab
The PowerShell tab to select.
PowerShell
$newTab = $psISE.PowerShellTabs.Add()
Remove( psTab )
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
psTab - Microsoft.PowerShell.Host.ISE.PowerShellTab
The PowerShell tab to remove.
PowerShell
$newTab = $psISE.PowerShellTabs.Add()
sleep 5
$psISE.PowerShellTabs.Remove($newTab)
See Also
The PowerShellTab Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEAddOnTool Object
Article • 09/17/2021
Each add-on tool can be associated with either the vertical pane or the horizontal pane.
The
vertical pane is docked to the right edge of Windows PowerShell ISE. The horizontal
pane is docked
to the bottom edge.
Each PowerShell tab in Windows PowerShell ISE can have its own set of add-on tools
installed. See
$psISE.CurrentPowerShellTab.HorizontalAddOnTools and
$psISE.CurrentPowerShellTab.VerticalAddOnTools to access the
collection of tools
available to the currently selected tab or the same properties on any of the
PowerShellTab objects in the $psISE.PowerShellTabs
collection object.
Methods
There are no Windows PowerShell ISE-specific methods available for objects of this
class.
Properties
Control
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The Control property provides read access to many of the details of the Commands
add-on tool.
PowerShell
$psISE.CurrentVisibleVerticalTool.Control
Output
HostObject : Microsoft.PowerShell.Host.ISE.ObjectModelRoot
Content :
HasContent :
ContentTemplate :
ContentTemplateSelector :
ContentStringFormat :
BorderBrush :
BorderThickness :
Background :
Foreground :
FontFamily :
FontSize :
FontStretch :
FontStyle :
FontWeight :
HorizontalContentAlignment :
VerticalContentAlignment :
TabIndex :
IsTabStop :
Padding :
Template : System.Windows.Controls.ControlTemplate
Style :
OverridesDefaultStyle :
UseLayoutRounding :
Triggers : {}
TemplatedParent :
Resources : {System.Windows.Controls.TabItem}
DataContext :
BindingGroup :
Language :
Name :
Tag :
InputScope :
ActualWidth : 370.75
ActualHeight : 676.559097412109
LayoutTransform :
Width :
MinWidth :
MaxWidth :
Height :
MinHeight :
MaxHeight :
FlowDirection : LeftToRight
Margin :
HorizontalAlignment :
VerticalAlignment :
FocusVisualStyle :
Cursor :
ForceCursor :
IsInitialized : True
IsLoaded :
ToolTip :
ContextMenu :
Parent :
HasAnimatedProperties :
InputBindings :
CommandBindings :
AllowDrop :
DesiredSize : 227.66,676.559097412109
IsMeasureValid : True
IsArrangeValid : True
RenderSize : 370.75,676.559097412109
RenderTransform :
RenderTransformOrigin :
IsMouseDirectlyOver : False
IsMouseOver : False
IsStylusOver : False
IsKeyboardFocusWithin : False
IsMouseCaptured :
IsMouseCaptureWithin : False
IsStylusDirectlyOver : False
IsStylusCaptured :
IsStylusCaptureWithin : False
IsKeyboardFocused : False
IsInputMethodEnabled :
Opacity :
OpacityMask :
BitmapEffect :
Effect :
BitmapEffectInput :
CacheMode :
Uid :
Visibility : Visible
ClipToBounds : False
Clip :
SnapsToDevicePixels : False
IsFocused :
IsEnabled :
IsHitTestVisible :
IsVisible : True
Focusable :
PersistId : 1
IsManipulationEnabled :
AreAnyTouchesOver : False
AreAnyTouchesDirectlyOver :
AreAnyTouchesCapturedWithin : False
AreAnyTouchesCaptured :
TouchesCaptured : {}
TouchesCapturedWithin : {}
TouchesOver : {}
TouchesDirectlyOver : {}
DependencyObjectType : System.Windows.DependencyObjectType
IsSealed : False
Dispatcher : System.Windows.Threading.Dispatcher
IsVisible
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The Boolean property that indicates whether the add-on tool is currently visible in its
assigned
pane. If it is visible, you can set the IsVisible property to $false to hide the
tool, or set
the IsVisible property to $true to make an add-on tool visible on its
PowerShell tab. Note
that after an add-on tool is hidden, it is no longer accessible
through the
CurrentVisibleHorizontalTool or CurrentVisibleVerticalTool objects, and
therefore cannot be
made visible by using this property on that object.
PowerShell
$psISE.CurrentVisibleVerticalTool.IsVisible = $false
$psISE.CurrentPowerShellTab.VerticalAddOnTools[0].IsVisible = $true
Name
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only property that gets the name of the add-on tool.
PowerShell
$psISE.CurrentVisibleVerticalTool.Name
Output
Commands
See Also
The ISEAddOnToolCollection Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEEditor Object
Article • 09/17/2021
Methods
Clear()
Supported in Windows PowerShell ISE 2.0 and later.
PowerShell
$psISE.CurrentPowerShellTab.ConsolePane.Clear()
EnsureVisible(int lineNumber)
Supported in Windows PowerShell ISE 2.0 and later.
Scrolls the editor so that the line that corresponds to the specified lineNumber
parameter value
is visible. It throws an exception if the specified line number is outside
the range of 1,last line
number, which defines the valid line numbers.
lineNumber
The number of the line that is to be made visible.
PowerShell
# Scrolls the text in the Script pane so that the fifth line is in view.
$psISE.CurrentFile.Editor.EnsureVisible(5)
Focus()
Supported in Windows PowerShell ISE 2.0 and later.
GetLineLength(int lineNumber )
Supported in Windows PowerShell ISE 2.0 and later.
Gets the line length as an integer for the line that is specified by the line number.
lineNumber
The number of the line of which to get the length.
Returns
The line length for the line at the specified line number.
PowerShell
# Gets the length of the first line in the text of the Command pane.
$psISE.CurrentPowerShellTab.ConsolePane.GetLineLength(1)
GoToMatch()
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Moves the caret to the matching character if the CanGoToMatch property of the editor
object is
$true , which occurs when the caret is immediately before an opening
parenthesis, bracket, or
brace - ( , [ , { - or immediately after a closing parenthesis,
bracket, or brace - ) , ] , } . The caret
is placed before an opening character or after a
closing character. If the CanGoToMatch property
is $false , then this method does
nothing.
PowerShell
$psISE.CurrentPowerShellTab.ConsolePane.GoToMatch()
InsertText( text )
Supported in Windows PowerShell ISE 2.0 and later.
Replaces the selection with text or inserts text at the current caret position.
text - String
The text to insert.
See the Scripting Example later in this topic.
Selects the text from the startLine, startColumn, endLine, and endColumn parameters.
startLine - Integer
The line where the selection starts.
startColumn - Integer
The column within the start line where the selection starts.
endLine - Integer
The line where the selection ends.
endColumn - Integer
The column within the end line where the selection ends.
SelectCaretLine()
Supported in Windows PowerShell ISE 2.0 and later.
Selects the entire line of text that currently contains the caret.
PowerShell
$psISE.CurrentFile.Editor.SetCaretPosition(5,1)
$psISE.CurrentFile.Editor.SelectCaretLine()
Sets the caret position at the line number and the column number. It throws an
exception if either
the caret line number or the caret column number are out of their
respective valid ranges.
lineNumber - Integer
The caret line number.
columnNumber - Integer
The caret column number.
PowerShell
# Set the CaretPosition.
$psISE.CurrentFile.Editor.SetCaretPosition(5,1)
ToggleOutliningExpansion()
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
PowerShell
$psISE.CurrentFile.Editor.ToggleOutliningExpansion()
Properties
CanGoToMatch
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only Boolean property to indicate whether the caret is next to a parenthesis,
bracket, or
brace - () , [] , {} . If the caret is immediately before the opening character
or immediately
after the closing character of a pair, then this property value is $true .
Otherwise, it is
$false .
PowerShell
$psISE.CurrentFile.Editor.CanGoToMatch
CaretColumn
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the column number that corresponds to the position
of the caret.
PowerShell
$psISE.CurrentFile.Editor.CaretColumn
CaretLine
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the number of the line that contains the caret.
PowerShell
$psISE.CurrentFile.Editor.CaretLine
CaretLineText
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the complete line of text that contains the caret.
PowerShell
# Get all of the text on the line that contains the caret.
$psISE.CurrentFile.Editor.CaretLineText
LineCount
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the line count from the editor.
PowerShell
$psISE.CurrentFile.Editor.LineCount
SelectedText
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the selected text from the editor.
The read/write property that gets or sets the text in the editor.
Scripting Example
PowerShell
# select the entire line and shows how you can make it lowercase.
# You must run this in the Console pane. It will not run in the Script pane.
$myEditor = $psISE.CurrentFile.Editor
$myEditor.Clear()
$myEditor.InsertText("LINE1 `n")
$myEditor.InsertText("LINE2 `n")
$myEditor.InsertText("LINE3 `n")
$myEditor.InsertText("LINE4 `n")
$myEditor.InsertText("LINE5 `n")
# Use the GetLineLength method to get the length of the third line.
$endColumn = $myEditor.GetLineLength(3)
$myEditor.Select(1, 1, 3, $endColumn + 1)
$selection = $myEditor.SelectedText
$myEditor.Clear()
$myEditor.InsertText($selection.ToLower())
See Also
The ISEFile Object
The PowerShellTab Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEFileCollection Object
Article • 09/17/2021
Methods
Add( [FullPath] )
Supported in Windows PowerShell ISE 2.0 and later.
Creates and returns a new untitled file and adds it to the collection. The IsUntitled
property
of the newly created file is $true .
[FullPath] - Optional string The fully specified path of the file. An exception is generated
if you include the FullPath parameter and a relative path, or if you use a file name
instead of
the full path.
PowerShell
$newFile = $psISE.CurrentPowerShellTab.Files.Add()
# Adds a file specified by its full path to the collection of files in the
current PowerShell tab.
$psISE.CurrentPowerShellTab.Files.Add("$pshome\Examples\profile.ps1")
File - String The ISEFile file that you want to remove from the collection. If the file has
not
been saved, this method throws an exception. Use the Force switch parameter to
force the removal
of an unsaved file.
[Force] - optional Boolean If set to $true , grants permission to remove the file even if it
has not been saved after last use. The default is $false .
PowerShell
# Removes the first opened file from the file collection associated with the
current PowerShell tab.
# If the file has not yet been saved, then an exception is generated.
$firstfile = $psISE.CurrentPowerShellTab.Files[0]
$psISE.CurrentPowerShellTab.Files.Remove($firstfile)
# Removes the first opened file from the file collection associated with the
current PowerShell tab, even if it has not been saved.
$firstfile = $psISE.CurrentPowerShellTab.Files[0]
$psISE.CurrentPowerShellTab.Files.Remove($firstfile, $true)
SetSelectedFile( selectedFile )
Supported in Windows PowerShell ISE 2.0 and later.
SelectedFile - Microsoft.PowerShell.Host.ISE.ISEFile
The ISEFile file that you want to
select.
PowerShell
$firstfile = $psISE.CurrentPowerShellTab.Files[0]
$psISE.CurrentPowerShellTab.Files.SetSelectedFile($firstfile)
See Also
The ISEFile Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEFile Object
Article • 09/17/2021
Methods
Save( [saveEncoding] )
Supported in Windows PowerShell ISE 2.0 and later.
parameter to be used for the saved file. The default value is UTF8.
Exceptions
System.IO.IOException: The file could not be saved.
PowerShell
$psISE.CurrentFile.Save()
$psISE.CurrentFile.Save([System.Text.Encoding]::ASCII)
$myfile = $psISE.CurrentFile
$myfile.Encoding
SaveAs(filename, [saveEncoding])
Supported in Windows PowerShell ISE 2.0 and later.
Saves the file with the specified file name and encoding.
filename - String
The name to be used to save the file.
Exceptions
System.ArgumentNullException: The filename parameter is null.
System.ArgumentException: The filename parameter is empty.
System.IO.IOException: The file could not be saved.
PowerShell
$fullpath = "c:\temp\newname.txt"
$psISE.CurrentFile.SaveAs($fullPath)
# Save the file with a full path and name and explicitly as UTF8.
$psISE.CurrentFile.SaveAs($fullPath, [System.Text.Encoding]::UTF8)
Properties
DisplayName
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the string that contains the display name of this file.
The name is
shown on the File tab at the top of the editor. The presence of an asterisk
(*) at the end of
the name indicates that the file has changes that have not been saved.
PowerShell
$psISE.CurrentFile.DisplayName
Editor
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the editor object that is used for the
specified file.
PowerShell
# Gets the editor and the text.
$psISE.CurrentFile.Editor.Text
Encoding
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the original file encoding. This is a
System.Text.Encoding
object.
PowerShell
$psISE.CurrentFile.Encoding
FullPath
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the string that specifies the full path of the opened file.
PowerShell
$psISE.CurrentFile.FullPath
IsSaved
Supported in Windows PowerShell ISE 2.0 and later.
The read-only Boolean property that returns $true if the file has been saved after it was
last
modified.
PowerShell
# Determines whether the file has been saved since it was last modified.
$myfile = $psISE.CurrentFile
$myfile.IsSaved
IsUntitled
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that returns $true if the file has never been given a title.
PowerShell
$psISE.CurrentFile.IsUntitled
$psISE.CurrentFile.SaveAs("temp.txt")
$psISE.CurrentFile.IsUntitled
See Also
The ISEFileCollectionObject
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEMenuItemCollection Object
Article • 10/06/2021
Method
Add(string DisplayName,
System.Management.Automation.ScriptBlock Action,
System.Windows.Input.KeyGesture Shortcut )
Supported in Windows PowerShell ISE 2.0 and later.
DisplayName
The display name of the menu to be added.
Shortcut
The keyboard shortcut for the action.
Returns
The ISEMenuItem object that was just added.
PowerShell
# Note the use of "_" as opposed to the "&" for mapping to the fast access
key letter for the menu item.
$menuAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process',
{Get-Process}, 'Alt+P')
Clear()
Supported in Windows PowerShell ISE 2.0 and later.
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
See Also
The ISEMenuItem Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEMenuItem Object
Article • 10/06/2021
Properties
DisplayName
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the display name of the menu item.
PowerShell
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.DisplayName
Action
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the block of script. It invokes the action when you click
the menu
item.
PowerShell
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Action
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Action.Invoke()
Shortcut
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the Windows input keyboard shortcut for the menu
item.
PowerShell
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Shortcut
Submenus
Supported in Windows PowerShell ISE 2.0 and later.
PowerShell
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus
Scripting example
To better understand the use of the Add-ons menu and its scriptable properties, read
through the
following scripting example.
PowerShell
# This is a scripting example that shows the use of the Add-ons menu.
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
# Add an Add-ons menu item with an shortcut and fast access key.
# Note the use of "_" as opposed to the "&" for mapping to the fast access
key letter for the menu item.
$menuAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add('_Process',
{Get-Process}, 'Alt+P')
$parentAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('Parent',
$null, $null)
See Also
The ISEMenuItemCollection Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISEOptions Object
Article • 09/22/2022
The ISEOptions object represents various settings for Windows PowerShell ISE. It is an
instance
of the Microsoft.PowerShell.Host.ISE.ISEOptions class.
Methods
RestoreDefaultConsoleTokenColors()
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Restores the default values of the token colors in the Console pane.
PowerShell
# Changes the color of the commands in the Console pane to red and then
restores it to its default value.
$psISE.Options.ConsoleTokenColors["Command"] = 'red'
$psISE.Options.RestoreDefaultConsoleTokenColors()
RestoreDefaults()
Supported in Windows PowerShell ISE 2.0 and later.
Restores the default values of all options settings in the Console pane. It also resets the
behavior
of various warning messages that provide the standard check box to prevent
the message from being
shown again.
PowerShell
# Changes the background color in the Console pane and then restores it to
its default value.
$psISE.Options.ConsolePaneBackgroundColor = 'orange'
$psISE.Options.RestoreDefaults()
RestoreDefaultTokenColors()
Supported in Windows PowerShell ISE 2.0 and later.
Restores the default values of the token colors in the Script pane.
PowerShell
# Changes the color of the comments in the Script pane to red and then
restores it to its default value.
$psISE.Options.TokenColors["Comment"] = 'red'
$psISE.Options.RestoreDefaultTokenColors()
RestoreDefaultXmlTokenColors()
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Restores the default values of the token colors for XML elements that are displayed in
Windows
PowerShell ISE. Also see XmlTokenColors.
PowerShell
# Changes the color of the comments in XML data to red and then restores it
to its default value.
$psISE.Options.XmlTokenColors["Comment"] = 'red'
$psISE.Options.RestoreDefaultXmlTokenColors()
Properties
AutoSaveMinuteInterval
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies the number of minutes between automatic save operations of your files by
Windows
PowerShell ISE. The default value is 2 minutes. The value is an integer.
PowerShell
$psISE.Options.AutoSaveMinuteInterval = 3
CommandPaneBackgroundColor
This feature is present in Windows PowerShell ISE 2.0, but was removed or renamed in
later versions
of the ISE. For later versions, see ConsolePaneBackgroundColor.
Specifies the background color for the Command pane. It is an instance of the
System.Windows.Media.Color class.
PowerShell
$psISE.Options.CommandPaneBackgroundColor = 'orange'
CommandPaneUp
This feature is present in Windows PowerShell ISE 2.0, but was removed or renamed in
later versions
of the ISE.
Specifies whether the Command pane is located above the Output pane.
PowerShell
$psISE.Options.CommandPaneUp = $true
ConsolePaneBackgroundColor
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies the background color for the Console pane. It is an instance of the
System.Windows.Media.Color class.
PowerShell
$psISE.Options.ConsolePaneBackgroundColor = 'red'
ConsolePaneForegroundColor
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
PowerShell
# Changes the foreground color of the text in the Console pane to yellow.
$psISE.Options.ConsolePaneForegroundColor = 'yellow'
ConsolePaneTextBackgroundColor
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
PowerShell
$psISE.Options.ConsolePaneTextBackgroundColor = 'pink'
ConsoleTokenColors
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies the colors of the IntelliSense tokens in the Windows PowerShell ISE Console
pane. This
property is a dictionary object that contains name/value pairs of token types
and colors for the
Console pane. To change the colors of the IntelliSense tokens in the
Script pane, see TokenColors.
To reset the colors to the default values, see
RestoreDefaultConsoleTokenColors.
Token colors can be set for the following: Attribute,
Command, CommandArgument, CommandParameter,
Comment, GroupEnd, GroupStart,
Keyword, LineContinuation, LoopLabel, Member, NewLine, Number,
Operator, Position,
StatementSeparator, String, Type, Unknown, Variable.
PowerShell
$psISE.Options.ConsoleTokenColors["Command"] = 'green'
$psISE.Options.ConsoleTokenColors["Keyword"] = 'magenta'
DebugBackgroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the background color for the debug text that appears in the Console pane. It is
an
instance of the System.Windows.Media.Color class.
PowerShell
# Changes the background color for the debug text that appears in the
Console pane to blue.
$psISE.Options.DebugBackgroundColor = '#0000FF'
DebugForegroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the foreground color for the debug text that appears in the Console pane. It is
an
instance of the System.Windows.Media.Color class.
PowerShell
# Changes the foreground color for the debug text that appears in the
Console pane to yellow.
$psISE.Options.DebugForegroundColor = 'yellow'
DefaultOptions
Supported in Windows PowerShell ISE 2.0 and later.
A collection of properties that specify the default values to be used when the Reset
methods are used.
PowerShell
# Displays the name of the default options. This example is from ISE 4.0.
$psISE.Options.DefaultOptions
Output
SelectedScriptPaneState : Top
ShowDefaultSnippets : True
ShowToolBar : True
ShowOutlining : True
ShowLineNumbers : True
DefaultOptions :
Microsoft.PowerShell.Host.ISE.ISEOptions
FontSize : 9
Zoom : 100
ErrorForegroundColor : #FFFF0000
ErrorBackgroundColor : #00FFFFFF
WarningForegroundColor : #FFFF8C00
WarningBackgroundColor : #00FFFFFF
VerboseForegroundColor : #FF00FFFF
VerboseBackgroundColor : #00FFFFFF
DebugForegroundColor : #FF00FFFF
DebugBackgroundColor : #00FFFFFF
ConsolePaneBackgroundColor : #FF012456
ConsolePaneTextBackgroundColor : #FF012456
ConsolePaneForegroundColor : #FFF5F5F5
ScriptPaneBackgroundColor : #FFFFFFFF
ScriptPaneForegroundColor : #FF000000
ShowWarningForDuplicateFiles : True
ShowWarningBeforeSavingOnRun : True
UseLocalHelp : True
AutoSaveMinuteInterval : 2
MruCount : 10
ShowIntellisenseInConsolePane : True
ShowIntellisenseInScriptPane : True
UseEnterToSelectInConsolePaneIntellisense : True
UseEnterToSelectInScriptPaneIntellisense : True
IntellisenseTimeoutInSeconds : 3
ErrorBackgroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the background color for error text that appears in the Console pane. It is an
instance of
the System.Windows.Media.Color class.
PowerShell
# Changes the background color for the error text that appears in the
Console pane to black.
$psISE.Options.ErrorBackgroundColor = 'black'
ErrorForegroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the foreground color for error text that appears in the Console pane. It is an
instance of
the System.Windows.Media.Color class.
PowerShell
# Changes the foreground color for the error text that appears in the
console pane to green.
$psISE.Options.ErrorForegroundColor = 'green'
FontName
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the font name currently in use in both the Script pane and the Console pane.
PowerShell
FontSize
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the font size as an integer. It is used in the Script pane, the Command pane,
and the
Output pane. The valid range of values is 8 through 32.
PowerShell
$psISE.Options.FontSize = 20
IntellisenseTimeoutInSeconds
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies the number of seconds that IntelliSense uses to try to resolve the currently
typed text.
After this number of seconds, IntelliSense times out and enables you to
continue typing. The default
value is 3 seconds. The value is an integer.
PowerShell
$psISE.Options.IntellisenseTimeoutInSeconds = 5
MruCount
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies the number of recently opened files that Windows PowerShell ISE tracks and
displays at the
bottom of the File Open menu. The default value is 10. The value is an
integer.
PowerShell
# Changes the number of recently used files that appear at the bottom of the
File Open menu to 5.
$psISE.Options.MruCount = 5
OutputPaneBackgroundColor
This feature is present in Windows PowerShell ISE 2.0, but was removed or renamed in
later versions
of the ISE. For later versions, see ConsolePaneBackgroundColor.
The read/write property that gets or sets the background color for the Output pane
itself. It is an
instance of the System.Windows.Media.Color class.
PowerShell
$psISE.Options.OutputPaneForegroundColor = 'gold'
OutputPaneTextForegroundColor
This feature is present in Windows PowerShell ISE 2.0, but was removed or renamed in
later versions
of the ISE. For later versions, see ConsolePaneForegroundColor.
The read/write property that changes the foreground color of the text in the Output
pane in Windows
PowerShell ISE 2.0.
PowerShell
# Changes the foreground color of the text in the Output Pane to blue.
$psISE.Options.OutputPaneTextForegroundColor = 'blue'
OutputPaneTextBackgroundColor
This feature is present in Windows PowerShell ISE 2.0, but was removed or renamed in
later versions
of the ISE. For later versions, see ConsolePaneTextBackgroundColor.
The read/write property that changes the background color of the text in the Output
pane.
PowerShell
# Changes the background color of the Output pane text to pink.
$psISE.Options.OutputPaneTextBackgroundColor = 'pink'
ScriptPaneBackgroundColor
Supported in Windows PowerShell ISE 2.0 and later.
The read/write property that gets or sets the background color for files. It is an instance
of the
System.Windows.Media.Color class.
PowerShell
$psISE.Options.ScriptPaneBackgroundColor = 'yellow'
ScriptPaneForegroundColor
Supported in Windows PowerShell ISE 2.0 and later.
The read/write property that gets or sets the foreground color for non-script files in the
Script pane.
To set the foreground color for script files, use the TokenColors.
PowerShell
$psISE.Options.ScriptPaneBackgroundColor = 'green'
SelectedScriptPaneState
Supported in Windows PowerShell ISE 2.0 and later.
The read/write property that gets or sets the position of the Script pane on the display.
The string
can be either 'Maximized', 'Top', or 'Right'.
PowerShell
$psISE.Options.SelectedScriptPaneState = 'Top'
$psISE.Options.SelectedScriptPaneState = 'Right'
$psISE.Options.SelectedScriptPaneState = 'Maximized'
ShowDefaultSnippets
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether the CTRL + J list of snippets includes the starter set that is included in
Windows PowerShell. When set to $false , only user-defined snippets appear in the
CTRL + J list.
The default value is $true .
PowerShell
$psISE.Options.ShowDefaultSnippets = $false
ShowIntellisenseInConsolePane
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether IntelliSense offers syntax, parameter, and value suggestions in the
Console pane.
The default value is $true .
PowerShell
$psISE.Options.ShowIntellisenseInConsolePane = $false
ShowIntellisenseInScriptPane
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether IntelliSense offers syntax, parameter, and value suggestions in the
Script pane.
The default value is $true .
PowerShell
$psISE.Options.ShowIntellisenseInScriptPane = $false
ShowLineNumbers
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether the Script pane displays line numbers in the left margin. The default
value is $true .
PowerShell
$psISE.Options.ShowLineNumbers = $false
ShowOutlining
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether the Script pane displays expandable and collapsible brackets next to
sections of
code in the left margin. When they are displayed, you can click the minus -
icons next to a
block of text to collapse it or click the plus + icon to expand a block of
text. The default
value is $true .
PowerShell
$psISE.Options.ShowOutlining = $false
ShowToolBar
Supported in Windows PowerShell ISE 2.0 and later.
Specifies whether the ISE toolbar appears at the top of the Windows PowerShell ISE
window. The
default value is $true .
PowerShell
$psISE.Options.ShowToolBar = $true
ShowWarningBeforeSavingOnRun
Supported in Windows PowerShell ISE 2.0 and later.
PowerShell
# Enable the warning message when an attempt
$psISE.Options.ShowWarningBeforeSavingOnRun = $true
ShowWarningForDuplicateFiles
Supported in Windows PowerShell ISE 2.0 and later.
Specifies whether a warning message appears when the same file is opened in different
PowerShell
tabs. If set to $true , to open the same file in multiple tabs displays this
message: "A copy of
this file is open in another Windows PowerShell tab. Changes made
to this file will affect all open
copies." The default value is $true .
PowerShell
$psISE.Options.ShowWarningForDuplicateFiles = $true
TokenColors
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the colors of the IntelliSense tokens in the Windows PowerShell ISE Script
pane. This
property is a dictionary object that contains name/value pairs of token types
and colors for the
Script pane. To change the colors of the IntelliSense tokens in the
Console pane, see ConsoleTokenColors.
To reset the colors to the default values, see
RestoreDefaultTokenColors.
Token colors can be set for the following: Attribute,
Command, CommandArgument, CommandParameter,
Comment, GroupEnd, GroupStart,
Keyword, LineContinuation, LoopLabel, Member, NewLine, Number,
Operator, Position,
StatementSeparator, String, Type, Unknown, Variable.
PowerShell
$psISE.Options.TokenColors["Command"] = "green"
$psISE.Options.TokenColors["Keyword"] = "magenta"
UseEnterToSelectInConsolePaneIntellisense
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether you can use the Enter key to select an IntelliSense provided option in
the Console
pane. The default value is $true .
PowerShell
# Turn off using the ENTER key to select an IntelliSense provided option in
the Console pane.
$psISE.Options.UseEnterToSelectInConsolePaneIntellisense = $false
UseEnterToSelectInScriptPaneIntellisense
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether you can use the Enter key to select an IntelliSense-provided option in
the Script
pane. The default value is $true .
PowerShell
$psISE.Options.UseEnterToSelectInConsolePaneIntellisense = $true
UseLocalHelp
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies whether the locally installed Help or the online Help appears when you press
F1
with the cursor positioned in a keyword. If set to $true , then a pop-up window
shows content from
the locally installed Help. You can install the Help files by running
the Update-Help command. If
set to $false , then your browser opens to a page on
Microsoft Learn.
PowerShell
$psISE.Options.UseLocalHelp = $false
$psISE.Options.UseLocalHelp = $true
VerboseBackgroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the background color for verbose text that appears in the Console pane. It is a
System.Windows.Media.Color object.
PowerShell
$psISE.Options.VerboseBackgroundColor ='#0000FF'
VerboseForegroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the foreground color for verbose text that appears in the Console pane. It is a
System.Windows.Media.Color object.
PowerShell
$psISE.Options.VerboseForegroundColor = 'yellow'
WarningBackgroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the background color for warning text that appears in the Console pane. It is a
System.Windows.Media.Color object.
PowerShell
$psISE.Options.WarningBackgroundColor = '#0000FF'
WarningForegroundColor
Supported in Windows PowerShell ISE 2.0 and later.
Specifies the foreground color for warning text that appears in the Output pane. It is a
System.Windows.Media.Color object.
PowerShell
$psISE.Options.WarningForegroundColor = 'yellow'
XmlTokenColors
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies a dictionary object that contains name/value pairs of token types and colors
for XML
content that is displayed in Windows PowerShell ISE. Token colors can be set for
the following:
Attribute, Command, CommandArgument, CommandParameter,
Comment, GroupEnd, GroupStart, Keyword,
LineContinuation, LoopLabel, Member,
NewLine, Number, Operator, Position, StatementSeparator,
String, Type, Unknown,
Variable. Also see RestoreDefaultXmlTokenColors.
PowerShell
$psISE.Options.XmlTokenColors["ElementName"] = 'green'
$psISE.Options.XmlTokenColors["Comment"] = 'magenta'
Zoom
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Specifies the relative size of text in both the Console and Script panes. The default value
is 100.
Smaller values cause the text in Windows PowerShell ISE to appear smaller while
larger numbers cause
text to appear larger. The value is an integer that ranges from 20
to 400.
PowerShell
# Changes the text in the Windows PowerShell ISE to be double its normal
size.
$psISE.Options.Zoom = 200
See Also
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISESnippetCollection Object
Article • 09/17/2021
Methods
Load( FilePathName )
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
Loads a .snippets.ps1xml file that contains user-defined snippets. The easiest way to
create
snippets is to use the New-IseSnippet cmdlet, which automatically stores them in
your profile folder
so that they are loaded every time that you start Windows PowerShell
ISE.
FilePathName - String
The path and file name to a .snippets.ps1xml file that contains
snippet definitions.
PowerShell
See Also
The ISESnippetObject
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The ISESnippetObject
Article • 09/17/2021
Properties
Author
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only property that gets the name of the author of the snippet.
PowerShell
$psISE.CurrentPowerShellTab.Snippets.Item(0).Author
CodeFragment
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only property that gets the code fragment to be inserted into the editor.
PowerShell
# Get the code fragment associated with the first snippet item.
$psISE.CurrentPowerShellTab.Snippets.Item(0).CodeFragment
Shortcut
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only property that gets the Windows keyboard shortcut for the menu item.
PowerShell
# Get the shortcut for the first submenu item.
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Shortcut
See Also
The ISESnippetCollection Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The PowerShellTabCollection Object
Article • 09/17/2021
Methods
Add()
Supported in Windows PowerShell ISE 2.0 and later.
Adds a new PowerShell tab to the collection. It returns the newly added tab.
PowerShell
$newTab = $psISE.PowerShellTabs.Add()
Remove(Microsoft.PowerShell.Host.ISE.PowerShellTab psTab)
Supported in Windows PowerShell ISE 2.0 and later.
psTab
The PowerShell tab to remove.
PowerShell
$newTab = $psISE.PowerShellTabs.Add()
sleep 5
$psISE.PowerShellTabs.Remove($newTab)
SetSelectedPowerShellTab(Microsoft.PowerShell.Host.ISE.PowerShellTab
psTab)
Supported in Windows PowerShell ISE 2.0 and later.
Selects the PowerShell tab that is specified by the psTab parameter to make it the currently
active
PowerShell tab.
psTab
The PowerShell tab to select.
PowerShell
# Save the current tab in a variable and rename it
$oldTab = $psISE.CurrentPowerShellTab
$newTab = $psISE.PowerShellTabs.Add()
See Also
The PowerShellTab Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
The PowerShellTab Object
Article • 09/17/2021
Methods
Invoke( Script )
Supported in Windows PowerShell ISE 2.0 and later.
7 Note
This method only works on other PowerShell tabs, not the PowerShell tab from
which it is run. It
does not return any object or value. If the code modifies any
variable, then those changes persist
on the tab against which the command was
invoked.
PowerShell
# Return to the first PowerShell tab and type the following command
$psISE.PowerShellTabs[1].Invoke({dir})
7 Note
This method only works on other PowerShell tabs, not the PowerShell tab from
which it is run. The
script block is run and any value that is returned from the script
is returned to the run
environment from which you invoked the command. If the
command takes longer to run than the
millesecondsTimeout value specifies, then
the command fails with an exception: "The operation
has timed out."
PowerShell
# Create a new PowerShell tab and then switch back to the first
$psISE.PowerShellTabs.Add()
$psISE.PowerShellTabs.SetSelectedPowerShellTab($psISE.PowerShellTabs[0])
$psISE.PowerShellTabs[1].InvokeSynchronous('$x=1', $false)
# You can switch to the other tab and type '$x' to see that the value is
saved there.
# This example sets a value in the other tab (in a different scope)
$a = $psISE.PowerShellTabs[1].InvokeSynchronous('$z=3;$z')
$a
# This example runs a command that takes longer than the allowed timeout
value
# and measures how long it runs so that you can see the impact
Properties
AddOnsMenu
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the Add-ons menu for the PowerShell tab.
PowerShell
# Clear the Add-ons menu if one exists.
$psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Clear()
# Note the use of "_" as opposed to the "&" for mapping to the fast key
letter for the menu item.
$menuAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add('_Process',
{Get-Process}, 'Alt+P')
$parentAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add('Parent',
$null, $null)
$psISE.CurrentPowerShellTab.AddOnsMenu
CanInvoke
Supported in Windows PowerShell ISE 2.0 and later.
The read-only Boolean property that returns a $true value if a script can be invoked
with the Invoke( Script )
method.
PowerShell
$secondTab = $psISE.PowerShellTabs[1]
$secondTab.CanInvoke
$secondTab.Invoke({sleep 20})
$secondTab.CanInvoke
ConsolePane
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
In Windows
PowerShell ISE 2.0 this was named CommandPane.
The read-only property that gets the Console pane editor object.
PowerShell
$psISE.CurrentPowerShellTab.ConsolePane
DisplayName
Supported in Windows PowerShell ISE 2.0 and later.
The read-write property that gets or sets the text that is displayed on the PowerShell
tab. By
default, tabs are named "PowerShell #", where the # represents a number.
PowerShell
$newTab = $psISE.PowerShellTabs.Add()
ExpandedScript
Supported in Windows PowerShell ISE 2.0 and later.
The read-write Boolean property that determines whether the Script pane is expanded
or hidden.
PowerShell
$psISE.CurrentPowerShellTab.ExpandedScript =
!$psISE.CurrentPowerShellTab.ExpandedScript
Files
Supported in Windows PowerShell ISE 2.0 and later.
PowerShell
$newFile = $psISE.CurrentPowerShellTab.Files.Add()
$newFile.Editor.Text = "a`r`nb"
$newFile.Editor.LineCount
Output
This feature is present in Windows PowerShell ISE 2.0, but was removed or renamed in
later versions
of the ISE. In later versions of Windows PowerShell ISE, you can use the
ConsolePane object for
the same purposes.
The read-only property that gets the Output pane of the current editor.
PowerShell
$psISE.CurrentPowerShellTab.output.clear()
Prompt
Supported in Windows PowerShell ISE 2.0 and later.
The read-only property that gets the current prompt text. Note: the Prompt function
can be
overridden by the user'™s profile. If the result is other than a simple string, then
this property
returns nothing.
PowerShell
$psISE.CurrentPowerShellTab.Prompt
ShowCommands
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-write property that indicates if the Commands pane is currently displayed.
PowerShell
# Gets the current status of the Commands pane and stores it in the $a
variable
$a = $psISE.CurrentPowerShellTab.ShowCommands
StatusText
Supported in Windows PowerShell ISE 2.0 and later.
$psISE.CurrentPowerShellTab.StatusText
HorizontalAddOnToolsPaneOpened
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only property that indicates whether the horizontal Add-Ons tool pane is
currently open.
PowerShell
$psISE.CurrentPowerShellTab.HorizontalAddOnToolsPaneOpened
VerticalAddOnToolsPaneOpened
Supported in Windows PowerShell ISE 3.0 and later, and not present in earlier versions.
The read-only property that indicates whether the vertical Add-Ons tool pane is
currently open.
PowerShell
$psISE.CurrentPowerShellTab.ShowCommands = $true
$psISE.CurrentPowerShellTab.HorizontalAddOnToolsPaneOpened
See Also
The PowerShellTabCollection Object
Purpose of the Windows PowerShell ISE Scripting Object Model
The ISE Object Model Hierarchy
Other Useful Scripting Objects
Article • 09/17/2021
$psUnsupportedConsoleApplications
There are some limitations on how Windows PowerShell ISE interacts with console
applications. A
command or an automation script that requires user intervention might
not work the way it works
from the Windows PowerShell console. You might want to
block these commands or scripts from running
in the Windows PowerShell ISE
Command pane. The $psUnsupportedConsoleApplications object keeps
a list of such
commands. If you try to run the commands in this list, you get a message that they
are
not supported. The following script adds an entry to the list.
PowerShell
$psUnsupportedConsoleApplications
$psUnsupportedConsoleApplications.Add('Mycommand')
$psUnsupportedConsoleApplications
$psLocalHelp
This is a dictionary object that maintains a context-sensitive mapping between Help
topics and
their associated links in the local compiled HTML Help file. It is used to locate
the local Help
for a particular topic. You can add or delete topics from this list. The
following code example
shows some example key-value pairs that are contained in
$psLocalHelp .
PowerShell
$psLocalHelp | Format-List
Output
Key : Add-Computer
Value : WindowsPowerShellHelp.chm::/html/093f660c-b8d5-43cf-aa0c-
54e5e54e76f9.htm
Key : Add-Content
Value : WindowsPowerShellHelp.chm::/html/0c836a1b-f389-4e9a-9325-
0f415686d194.htm
PowerShell
$psLocalHelp.Add("get-myNoun", "c:\MyFolder\MyHelpChm.chm::/html/0198854a-
1298-57ae-aa0c-87b5e5a84712.htm")
$psOnlineHelp
This is a dictionary object that maintains a context-sensitive mapping between topic
titles of Help
topics and their associated external URLs. It is used to locate the Help for a
particular topic on
the web. You can add or delete topics from this list.
PowerShell
$psOnlineHelp | Format-List
Output
Key : Add-Computer
Value : https://go.microsoft.com/fwlink/p/?LinkID=135194
Key : Add-Content
Value : https://go.microsoft.com/fwlink/p/?LinkID=113278
PowerShell
$psOnlineHelp.Add("get-myNoun", "https://www.mydomain.com/MyNoun.html")
See Also
Purpose of the Windows PowerShell ISE Scripting Object Model
Windows Management Framework
Article • 10/25/2022
Windows PowerShell
Windows PowerShell Desired State Configuration (DSC)
Windows PowerShell Integrated Script Environment (ISE)
Windows Remote Management (WinRM)
Windows Management Instrumentation (WMI)
Windows PowerShell Web Services (Management OData IIS Extension)
Software Inventory Logging (SIL)
Server Manager CIM Provider
WMF 5.1
WMF 5.0
Windows 11 Ships
in-box
Ships in-box: The features of the specified version of WMF were shipped in the
indicated
version of Windows client or Windows Server.
Out of support: These products are no longer supported by Microsoft. You must
upgrade to a
supported version. For more information, see the Microsoft Lifecycle
Policy page.
7 Note
) Important
WMF 5.0 is superseded by WMF 5.1. Users with WMF 5.0 must upgrade to WMF 5.1
to receive support.
WMF 5.1 requires the .NET Framework 4.5.2 (or above).
Installation will succeed, but key
features will fail if .NET 4.5.2 (or above) is not
installed.
x86: Win8.1-KB3191564-x86.msu
WMF 5.1 Preview must be uninstalled before installing WMF 5.1 RTM.
WMF 5.1 may be installed directly over WMF 5.0 or WMF 4.0.
It is not required to install WMF 4.0 prior to installing WMF 5.1 on Windows 7 and
Windows
Server 2008 R2.
Installation instructions for Windows Server 2008 R2 and Windows 7 have changed,
and differ from
the instructions for the other packages. Installation instructions for
Windows Server 2012 R2,
Windows Server 2012, and Windows 8.1 are below.
2. Right-click on the ZIP file, and select Extract All.... The ZIP file contains two files: an
MSU and the Install-WMF5.1.ps1 script file. Once you have unpacked the ZIP file,
you can copy
the contents to any machine running Windows 7 or Windows Server
2008 R2.
3. After extracting the ZIP file contents, open PowerShell as administrator, then
navigate to the
folder containing the contents of the ZIP file.
4. Run the Install-WMF5.1.ps1 script in that folder, and follow the instructions. This
script will
check the prerequisites on the local machine, and install WMF 5.1 if the
prerequisites have been
met. The prerequisites are listed below.
installation on
Windows Server 2008 R2 and Windows 7:
AcceptEula: When this parameter is included, the EULA is automatically
accepted and will
not be displayed.
AllowRestart: This parameter can only be used if AcceptEula is specified. If
this parameter
is included, and a restart is required after installing WMF 5.1,
the restart will happen
without prompting immediately after the installation is
completed.
WinRM Dependency
Windows PowerShell Desired State Configuration (DSC) depends on WinRM. WinRM is
not enabled by
default on Windows Server 2008 R2 and Windows 7. Run Set-
WSManQuickConfig , in a Windows PowerShell
elevated session, to enable WinRM.
2. Change directories to the folder into which you have downloaded or copied the
WMF 5.1
installation package.
On computers that are running Windows Server 2012 R2 or Windows 8.1 x64,
run
Win8.1AndW2K12R2-KB3191564-x64.msu /quiet /norestart .
On computers that are running Windows Server 2012, run
W2K12-KB3191565-
x64.msu /quiet /norestart .
On computers that are running Windows 8.1 x86, run
Win8.1-KB3191564-
x86.msu /quiet /norestart .
7 Note
Installing WMF 5.1 requires a reboot. Using the /quiet option alone will
reboot the system
without warning. Use the /norestart option to avoid
rebooting. However, WMF 5.1 will not be
installed until you have rebooted.
Uninstallation Instructions
Article • 09/17/2021
PowerShell
PowerShell
PowerShell
New cmdlets
PowerShellGet improvements include enforcing signed modules, and installing JEA
modules
PackageManagement added support for Containers, CBS Setup, EXE-based setup,
CAB packages
Debugging improvements for DSC and PowerShell classes
Security enhancements including enforcement of catalog-signed modules coming
from the Pull Server
and when using PowerShellGet cmdlets
Responses to a number of user requests and issues
) Important
Before you install WMF 5.1 on Windows Server 2008 or Windows 7, confirm that
WMF 3.0 isn't
installed. For more information, see
WMF 5.1 Prerequisites for
Windows Server 2008 R2 SP1 and Windows 7 SP1.
PowerShell Editions
Starting with version 5.1, PowerShell is available in different editions that denote varying
feature sets and platform compatibility.
Desktop Edition: Built on .NET Framework and provides compatibility with scripts
and modules
targeting versions of PowerShell running on full footprint editions of
Windows such as Server Core
and Windows Desktop.
Core Edition: Built on .NET Core and provides compatibility with scripts and
modules targeting
versions of PowerShell running on reduced footprint editions of
Windows such as Nano Server and
Windows IoT.
typically read
at startup while searching for a command and is written on a background
thread sometime after a
module is imported.
To change the default location of the cache, set the $env:PSModuleAnalysisCachePath
environment
variable before starting PowerShell. Changes to this environment variable
will only affect children
processes. The value should name a full path (including
filename) that PowerShell has permission to
create and write files. To disable the file
cache, set this value to an invalid location, for
example:
PowerShell
$env:PSModuleAnalysisCachePath = 'nul'
This sets the path to an invalid device. If PowerShell can't write to the path, no error is
returned, but you can see error reporting by using a tracer:
PowerShell
When writing out the cache, PowerShell will check for modules that no longer exist to
avoid an
unnecessarily large cache. Sometimes these checks are not desirable, in which
case you can turn them
off by setting:
PowerShell
$env:PSDisableModuleAnalysisCacheCleanup = 1
Setting this environment variable will take effect immediately in the current process.
In WMF 5.1:
Improvements to Pester
In WMF 5.1, the version of Pester that ships with PowerShell has been updated from
3.3.5 to 3.4.0.
This update enables better behavior for Pester on Nano Server.
Bug fixes
The following notable bugs are fixed in WMF 5.1:
WMF 5.1 changes this behavior to honor $env:PSModulePath completely. This allows for
a
user-authored module that defines commands provided by PowerShell (e.g. Get-
ChildItem ) to be
auto-loaded and correctly overriding the built-in command.
Starting with WMF 5.1, you can now change the file encoding of redirection by setting
$PSDefaultParameterValues :
PowerShell
$PSDefaultParameterValues["Out-File:Encoding"] = "Ascii"
PowerShell
$obj.SendKeys([char]173)
The SendKeys method expects a string, but PowerShell did not convert the char to a
string,
deferring the conversion to IDispatch::Invoke, which uses VariantChangeType to
do the
conversion. In this example, this resulted in sending the keys '1', '7', and '3'
instead of the
expected Volume.Mute key.
PowerShell
function Get-COMDictionary
$d.Add('a', 2)
$d.Add('b', 2)
return $d
$x = Get-COMDictionary
In the above example, WMF 5.0 incorrectly wrote the Scripting.Dictionary to the
pipeline instead
of enumerating the key/value pairs.
PowerShell
class CThing
[object] foo($i)
[ordered]@{ Thing = $i }
WMF 5.1 fixes this by returning the help for the latest version of the topic.
Get-Help does not provide a way to specify which version you want help for. To work
around this,
navigate to the modules directory and view the help directly with a tool like
your favorite editor.
We have added new and updated existing cmdlets based on feedback from the
community.
Archive cmdlets
Two new cmdlets, Compress-Archive and Expand-Archive , let you compress and expand
ZIP files.
Catalog Cmdlets
Two new cmdlets have been added in the Microsoft.PowerShell.Security module.
New-FileCatalog
Test-FileCatalog
Clipboard cmdlets
Get-Clipboard and Set-Clipboard make it easier for you to transfer content to and from
a
Windows PowerShell session. The Clipboard cmdlets support images, audio files, file
lists, and text.
Get-Clipboard
Set-Clipboard
Your public key can be shared widely and is not sensitive data. Any content encrypted
with the
public key can only be decrypted using the private key. For more information,
see
Public-key cryptography .
Get-CmsMessage
Protect-CmsMessage
Unprotect-CmsMessage
Certificates require a unique key usage identifier (EKU), such as 'Code Signing' or
'Encrypted
Mail', to identify them as data encryption certificates in PowerShell. To view
document encryption
certificates in the certificate provider, you can use the
DocumentEncryptionCert dynamic
parameter of Get-ChildItem :
PowerShell
ConvertFrom-String
The new ConvertFrom-String cmdlet supports two modes:
Delimited parsing, by default, splits the input at white space, and assigns property
names to the
resulting groups.
The UpdateTemplate parameter saves the results of the learning algorithm into a
comment in the
template file. This makes the learning process (the slowest stage) a one-
time cost. Running
ConvertFrom-String with a template that contains the encoded
learning algorithm is now nearly
instantaneous.
PowerShell
Output
FileVersionRaw : 10.0.17763.1
ProductVersionRaw : 10.0.17763.1
ProductVersion : 10.0.17763.1
Format-Hex
Format-Hex lets you view text or binary data in hexadecimal format.
Output
New-Guid
There are many scenarios where youneed for unique identifier. The New-GUID cmdlet
provides a
simple way to create a new GUID.
PowerShell
New-Guid
Output
Guid
----
e19d6ea5-3cc2-4db9-8095-0cdaed5a703d
NoNewLine parameter
Out-File , Add-Content , and Set-Content now have a new NoNewline switch which
omits a new
line after the output. For example:
PowerShell
Get-Content .\Example.txt
Output
This is a single sentence.
PowerShell
Get-Content .\Example.txt
Output
This is
a single
sentence.
PowerShell
PowerShell
New-Item -ItemType SymbolicLink -Path C:\Temp -Name MySymLinkDir -Value
$pshome
Hard links
The same combinations of Path and Name allowed as described above.
PowerShell
Directory junctions
The same combinations of Path and Name allowed as described above.
PowerShell
Get-ChildItem
Get-ChildItem now displays an 'l' in the Mode property to indicate a symbolic link file or
directory.
PowerShell
Directory: C:\Temp
Remove-Item
Removing symbolic links works like removing any other item type.
PowerShell
Remove-Item C:\Temp\MySymLinkFile.txt
Remove-Item C:\Temp\MySymLinkDir
Use the Force parameter to remove the files in the target directory and the symbolic
link.
PowerShell
New-TemporaryFile
Sometimes in your scripts, you must create a temporary file. You can now do this with
the
New-TemporaryFile cmdlet:
PowerShell
$tempFile = New-TemporaryFile
$tempFile.FullName
Output
C:\Users\user1\AppData\Local\Temp\tmp375.tmp
VLAN configuration:
Create or remove VLAN
Enable or disable VLAN
Enumerate VLAN
Set friendly name to a VLAN
PowerShell
$uri =
"http://services.odata.org/V3/(S(fhleiief23wrm5a5nhf542q5))/OData/OData.svc/
"
In the following example, we are retrieving top product and capturing the output in the
$infoStream variable.
$additionalInfo['odata.count']
You can get the records from the server in batches using client-side paging support. This
is useful
when you must get a large amount of data from the server over the network.
PowerShell
$skipCount = 0
$batchSize = 3
$skipCount += $batchSize
The generated proxy cmdlets support the Select parameter that is used as a filter to
receive
only the record properties that the client needs. The filtering occurs on the
server, which reduces
the amount of data that is transferred over the network.
PowerShell
The Export-ODataEndpointProxy cmdlet, and the proxy cmdlets generated by it, now
support the
Headers parameter. The header can be used to channel additional
information expected by the
OData endpoint.
In the following example, a hash table containing a Subscription key is provided to the
Headers
parameter. This is a typical example for services that are expecting a
Subscription key for
authentication.
PowerShell
PowerShell 5.0 added the ability to define classes and other user-defined types using
formal syntax
and semantics like other object-oriented programming languages. The
goal is to enable developers and
IT professionals to embrace PowerShell for a wider
range of use cases, simplify development of
PowerShell artifacts (such as DSC
resources), and accelerate coverage of management surfaces.
Class keyword
The class keyword defines a new class. This is a true .NET Framework type. Class
members are
public, but only public within the module scope. You can't refer to the type
name as a string (for
example, New-Object doesn't work), and in this release, you can't
use a type literal (for example,
[MyClass] ) outside the script or module file in which the
class is defined.
PowerShell
class MyClass
...
PowerShell
enum Color2
Yellow = [Color]::Blue
An enumerator value must be a parse time constant. You cannot set it to the result of an
invoked
command.
PowerShell
enum MyEnum
Enum1
Enum2
Enum3 = 42
Enum4 = [int]::MaxValue
PowerShell
Import-DscResource
Import-DscResource is now a true dynamic keyword. PowerShell parses the specified
module's root
module, searching for classes that contain the DscResource attribute.
ImplementingAssembly
A new field, ImplementingAssembly, has been added to ModuleInfo. It is set to the
dynamic
assembly created for a script module if the script defines classes, or the loaded
assembly for
binary modules. It is not set when ModuleType is Manifest.
Further reading
about_Classes
about_Enum
about_Classes_and_DSC
Console Improvements in WMF 5.1
Article • 10/13/2021
VT100 support
Windows 10 added support for VT100 escape sequences.
PowerShell ignores certain
VT100 formatting escape sequences when calculating table widths.
PowerShell also added a new API that can be used in formatting code to determine if
VT100 is
supported. For example:
PowerShell
if ($host.UI.SupportsVirtualTerminal)
$esc = [char]0x1b
else
Note that VT100 escape sequences are only supported starting with the Windows 10
Anniversary update.
They are not supported on earlier systems.
With WMF 5.1, this hard to discover option is no longer necessary. You can start
PowerShell without
any options.
Note that PSReadline does not support redirected stdin, and the built-in command-line
editing
experience with redirected stdin is extremely limited, for example, arrow keys
don't work. A future
release of PSReadline should address this issue.
Improvements in PowerShell Script
Debugging
Article • 09/17/2021
PowerShell 5.0 includes several improvements that enhance the debugging experience.
Break All
The PowerShell console and PowerShell ISE now allow you to break into the debugger
for running
scripts. This works in both local and remote sessions.
In ISE, press Ctrl + B , or use the Debug -> Break All menu command.
PowerShell
In addition, you can now edit and save changes in a remote file that is automatically
opened in
PowerShell ISE when you hit a breakpoint. Now, you can debug a script file
that is running on a
remote computer, edit the file to fix an error, and then rerun the
modified script.
Runspace Debugging
New cmdlets have been added that let you list current runspaces in a process, and
attach the
PowerShell console or PowerShell ISE debugger to that runspace for script
debugging:
Get-Runspace
Debug-Runspace
Enable-RunspaceDebug
Disable-RunspaceDebug
Get-RunspaceDebug
Enter-PSHostProcess
Exit-PSHostProcess
Script Tracing and Logging
Article • 11/02/2021
Logging is enabled through the Turn on PowerShell Script Block Logging Group Policy
setting in
Administrative Templates -> Windows Components -> Windows
PowerShell.
Channel Operational
Level Verbose
Opcode Create
Task CommandStart
Keyword Runspace
%3
ScriptBlock ID: %4
The text embedded in the message is the extent of the script block compiled. The ID is a
GUID that
is retained for the life of the script block.
When you enable verbose logging, the feature writes begin and end markers:
Channel Operational
Level Verbose
Keyword Runspace
Runspace ID: %2
The ID is the GUID representing the script block (that can be correlated with event ID
0x1008), and
the Runspace ID represents the runspace in which this script block was run.
Percent signs in the invocation message represent structured ETW properties. While
they are replaced
with the actual values in the message text, a more robust way to
access them is to retrieve the
message with the Get-WinEvent cmdlet, and then use the
Properties array of the message.
Here's an example of how this functionality can help unwrap a malicious attempt to
encrypt and
obfuscate a script:
PowerShell
## Malware
function SuperDecrypt
param($script)
$bytes = [Convert]::FromBase64String($script)
## XOR "encryption"
$xorKey = 0x42
[System.Text.Encoding]::Unicode.GetString($bytes)
Invoke-Expression $decrypted
Output
function SuperDecrypt
param($script)
$bytes = [Convert]::FromBase64String($script)
## XOR "encryption"
$xorKey = 0x42
[System.Text.Encoding]::Unicode.GetString($bytes)
Invoke-Expression $decrypted
Write-Host 'Pwnd'
If the script block length exceeds the capacity of a single event, PowerShell breaks the
script into
multiple parts. Here is sample code to recombine a script from its log
messages:
PowerShell
Where-Object { $_.<...> }
As with all logging systems that have a limited retention buffer, one way to attack this
infrastructure is to flood the log with spurious events to hide earlier evidence. To protect
yourself from this attack, ensure that you have some form of event log collection set up
Windows
Event Forwarding. For more information, see
Use Azure Monitor to integrate
with SIEM tools .
Improvements in Desired State
Configuration (DSC) in WMF 5.1
Article • 09/17/2021
XML
<appSettings>
</appSettings>
PowerShell
Configuration PartialOne
Node('localhost')
File test
DestinationPath = "$env:TEMP\partialconfigexample.txt"
PartialOne
This made it impossible to pull one of your partial configuration from Azure
Automation service.
PowerShell
Configuration PartialOne
Node('localhost')
File test
DestinationPath = "$env:TEMP\partialconfigexample.txt"
PartialOne
configuration
from a pull server/service then the configuration file on the pull
server configuration repository
can have any file name. This naming flexibility
allows you to manage your nodes partially by Azure
Automation service, where
some configuration for your node is coming from Azure Automation DSC and
with
a partial configuration that you manage locally.
PowerShell
[DscLocalConfigurationManager()]
Configuration RegistrationMetaConfig
Settings
RefreshFrequencyMins = 30
RefreshMode = "PULL"
ConfigurationRepositoryWeb web
ServerURL = $endPoint
RegistrationKey = $registrationKey
ConfigurationNames = $configurationName
PartialConfiguration PartialConfigurationManagedByAzureAutomation
ConfigurationSource = "[ConfigurationRepositoryWeb]Web"
PartialConfiguration OnPremisesConfig
RefreshMode = "PUSH"
ExclusiveResources = @("Script")
RegistrationMetaConfig
You can now specify a value for PsDscRunAsCredential when using composite resources
inside
configurations. When specified, all resources run inside a composite resource as a
RunAs user. If a
composite resource calls another composite resource, all those
resources are also executed as RunAs
user. RunAs credentials are propagated to any
level of the composite resource hierarchy. If any
resource inside a composite resource
specifies its own value for PsDscRunAsCredential, a merge
error results during
configuration compilation.
PowerShell
Configuration InstallWindowsFeature
Node $AllNodes.NodeName
WindowsFeatureSet features
Name = @("Telnet-Client","SNMP-Service")
Ensure = "Present"
IncludeAllSubFeature = $true
PsDscRunAsCredential = Get-Credential
$configData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowDomainUser = $true
CertificateFile = 'C:\publicKeys\targetNode.cer'
Thumbprint = '7ee7f09d-4be0-41aa-a47f-96b9e3bdec25'
PowerShell
Configuration IIS_FrontEnd
Ensure = 'Present'
Name = 'Web-Server'
WindowsFeature FTP
Ensure = 'Present'
Name = 'Web-FTP-Server'
Configuration IIS_Worker
Ensure = 'Present'
Name = 'Web-Server'
WindowsFeature ASP
Ensure = 'Present'
Name = 'Web-ASP-Net45'
Configuration WebApplication
IIS_Frontend Web {}
IIS_Worker ASP {}
In previous releases, the result would be a failed compilation due to a conflict between
the
WindowsFeature FE_IIS and WindowsFeature Worker_IIS instances trying to ensure
the 'Web-Server' role
is installed. Notice that all of the properties that are being
configured are identical in these
two configurations. Since all of the properties in these
two resources are identical, this will
result in a successful compilation now.
If any of the properties are different between the two resources, they will not be
considered
identical and compilation will fail.
In WMF 5.1, DSC supports validating the digital signatures on catalog and configuration
(.MOF)
files. This feature prevents nodes from executing configurations or module files
which are not
signed by a trusted signer or which have been tampered with after they
have been signed by trusted
signer.
How to sign configuration and module
Configuration Files (.MOFs): The existing PowerShell cmdlet Set-
AuthenticodeSignature
is extended to support signing of MOF files.
Modules: Signing of modules is done by signing the corresponding module
catalog using the
following steps:
Pull
The LocalConfigurationManager of a node performs signing validation of modules and
configurations
based on its current settings. By default, signature validation is disabled.
Signature validation
can enabled by adding the 'SignatureValidation' block to the meta-
configuration definition of the
node as shown below:
PowerShell
[DSCLocalConfigurationManager()]
Configuration EnableSignatureValidation
Settings
RefreshMode = 'PULL'
ConfigurationRepositoryWeb pullserver{
ConfigurationNames = 'sql'
ServerURL =
'http://localhost:8080/PSDSCPullServer/PSDSCPullServer.svc'
AllowUnsecureConnection = $true
SignatureValidation validations{
TrustedStorePath = 'Cert:\LocalMachine\DSCStore'
EnableSignatureValidation
5. Install-Module to $env:ProgramFiles\WindowsPowerShell\Modules\
6. Process configuration
7 Note
Push
A configuration delivered by using push might be tampered with at its source before it
delivered to
the node. The Local Configuration Manager performs similar signature
validation steps for pushed or
published configuration(s). Below is a complete example
of signature validation for push.
PowerShell
[DSCLocalConfigurationManager()]
Configuration EnableSignatureValidation
Settings
RefreshMode = 'PUSH'
SignatureValidation validations{
TrustedStorePath = 'Cert:\LocalMachine\DSCStore'
SignedItemType = 'Configuration','Module'
EnableSignatureValidation
PowerShell
# Sample configuration
Configuration Test
File foo
DestinationPath = "$env:TEMP\signingTest.txt"
Contents = "ABC"
Test
PowerShell
The following improvements to the core PowerShell engine have been implemented in
WMF 5.1:
Performance
Performance has improved in some important areas:
Startup
Pipelining to cmdlets like ForEach-Object and Where-Object is approximately 50%
faster
Some example improvements (your results may vary depending on your hardware):
7 Note
Another visible change is how PowerShell caches the exported commands and other
information for
modules that are installed on a system. Previously, this cache was stored
in the directory
$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\CommandAnalysis . In
WMF 5.1, the cache is a single
file
$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\ModuleAnalysisCache . See Module
Analysis Cache
for more details.
Information Stream
Article • 09/17/2021
PowerShell 5.0 adds a new structured Information stream to transmit structured data
between a
script and its host. Write-Host has also been updated to emit its output to
the Information
stream where you can now capture or silence it. The new Write-
Information cmdlet used with
InformationVariable and InformationAction common
The following function uses cmdlets that take advantage of the new Information stream.
PowerShell
function OutputGusher {
[CmdletBinding()]
param()
Write-Host '============================='
Write-Host '============================='
$p
Write-Host
PowerShell
$r = OutputGusher
Output
=============================
I <3 Output
=============================
SCRIPT COMPLETE!!
The $r variable has captured the process information in the script variable $p .
PowerShell
$r.Id
4008
PowerShell
$r = OutputGusher -InformationVariable iv
$ivOutput
Output
=============================
I <3 Output
=============================
SCRIPT COMPLETE!!
Name Value
---- -----
When you send a message to the Information stream with a tag, that message is not
displayed in
the host application but can be retrieved using the tag name. For example:
PowerShell
Output
Just Enough Administration is a new feature in WMF 5.0 that enables role-based
administration
through PowerShell remoting. It extends the existing constrained
endpoint infrastructure by allowing
non-administrators to run specific commands,
scripts, and executables as an administrator. This
enables you to reduce the number of
full administrators in your environment and improve security.
To set up the user drive in your JEA session configuration file, use the following new
fields:
PowerShell
MountUserDrive = $true
UserDriveMaximumSize = 10485760 # 10 MB
To utilize the user drive and copy files to/from a JEA endpoint configured to expose the
User
drive, use the -ToSession and -FromSession parameters on Copy-Item .
PowerShell
# Note: you cannot specify the file name or subfolder on the remote machine.
# Copy the file back from the remote machine to your local machine
You can then write custom functions to process the data stored in the user drive and
make those
available to users in your Role Capability file.
To configure a JEA session to run under a gMSA account, use the following new key in
your PSSC file:
PowerShell
# Provide the name of your gMSA account here (don't include a trailing $)
# The local machine must be privileged to use this gMSA in Active Directory
GroupManagedServiceAccount = 'myGMSAforJEA'
# You cannot configure a JEA endpoint to use both a gMSA and virtual account
RunAsVirtualAccount = $false
7 Note
Group Managed Service Accounts do not afford the isolation or limited scope of
virtual accounts.
Every connecting user will share the same gMSA identity, which
may have permissions across your
entire enterprise. Be very careful when selecting
to use a gMSA, and always prefer virtual
accounts which are limited to the local
machine when possible.
The new RequiredGroups field in the PSSC file allows you to specify the logic to
determine if a
user can connect to JEA. It consists of specifying a hashtable (optionally
nested) that uses the
'And' and 'Or' keys to construct your rules. Here are some
examples of how to use this field:
PowerShell
# The 2 factor authentication group name is "2FA-logon" and the smart card
group name is "smartcard-logon"
Version Alias
Scenario: If you have version 1.0 and 2.0 of a package, P1, installed on your system, and
you
want to uninstall version 1.0, you would run Uninstall-Package -Name P1 -Version
1.0 and expect
version 1.0 to be uninstalled after running the cmdlet. However the
However, in some cases, when you have an old version of NuGet provider installed on
your computer,
the older version of NuGet sometimes gets loaded first into the
PowerShell session (that's the race
condition in PackageManagement). However
PowerShellGet requires the later version of the NuGet
provider to work, so
PowerShellGet asks PackageManagement to bootstrap the NuGet provider again.
This
results in multiple prompts for bootstrapping the NuGet provider.
Solution: In WMF5.1, PackageManagement loads the latest version of the NuGet
provider to avoid
multiple prompts for bootstrapping the NuGet provider.
You could also work around this issue by manually deleting the old version of the NuGet
provider
(NuGet-Anycpu.exe) if exists from
$env:ProgramFiles\PackageManagement\ProviderAssemblies
$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies
Scenario: In WMF 5.0, PackageManagement did not support computers that have only
Intranet (but
not Internet) access.
Solution: In WMF 5.1, you can follow these steps to allow Intranet computers to use
PackageManagement:
1. Download the NuGet provider using another computer that has an Internet
connection by using
Install-PackageProvider -Name NuGet .
$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies\nuget .
3. Copy the binaries to a folder or network share location that the Intranet computer
can access,
and then install the NuGet provider with
Install-PackageProvider -
Name NuGet -Source <Path to folder> .
PowerShell
PowerShell
) Important
When installing WMF 5.x on a Windows Server 2012 R2 Server that is already
running SIL, it is
necessary to run the Start-SilLogging cmdlet once after the WMF
install, as the installation
process will errantly stop the Software Inventory Logging
feature.
Software Inventory Logging helps reduce the operational costs of getting accurate
information about
the Microsoft software installed locally on a server, but especially
across many servers in an IT
environment (assuming the software is installed and
running across the IT environment). Provided one
is set up, you can forward this data to
an aggregation server, and collect the log data in one place
by using a uniform,
automatic process.
While you can also log software inventory data by querying each computer directly,
Software
Inventory Logging, by employing a forwarding (over the network) architecture
initiated by each
server, can overcome server discovery challenges that are typical for
many software inventory and
asset management scenarios. Software Inventory Logging
uses SSL to secure data that is forwarded
over HTTPS to an aggregation server. Storing
the data in one place makes the data easier to analyze,
manipulate, and share when
necessary.
None of this data is sent to Microsoft as part of the feature functionality. Software
Inventory
Logging data and functionality is meant for the sole use of the server
software's licensed owner and
administrators.
For more information and documentation about Software Inventory Logging cmdlets,
see
Manage Software Inventory Logging in Windows Server 2012 R2.
Product Compatibility Status
Article • 09/17/2021
Compatible
Systems that are running the following server applications can run Windows
Management Framework
5.1:
7 Note
Skype for Business Server 2015 compatibility with WMF 5.1 has been tested only
with Windows Server
2012 R2.
Not Tested
Systems that are running the following server applications have not tested against
Windows
Management Framework 5.1:
Incompatible
Systems that are running the following server applications should not run Windows
Management
Framework 5.1:
Once you have performed either of the above actions, the PowerShell shortcuts will
work. These
actions need to be performed only once.
PowerShell
Set-ExecutionPolicy RemoteSigned
Resolution: Run the Start-SilLogging cmdlet once after the WMF installation, as the
installation
process will errantly stop the Software Inventory Logging feature.
Resolution: Not ideal, but current workaround is to implement recursion in the script
rather
than rely on the cmdlet.
Resolution:
PowerShell
3. Run the command and ignore the error, as they are expected.
PowerShell
Publish-SilData
PowerShell
4. Find and remove the following text, one instance of each needs to be deleted
(they will be near
the end of the document).
XML
<sysprepOrder order="0x3200"></sysprepOrder>
<sysprepOrder order="0x3300"></sysprepOrder>
PowerShell
Takeown /f C:\Windows\System32\Sysprep\ActionFiles\Generalize.xml
PowerShell
9. Copy the file you edited and saved over to the Sysprep directory using the
following command:
PowerShell
xcopy C:\Generalize.xml
C:\Windows\System32\Sysprep\ActionFiles\Generalize.xml
10. Generalize.xml is now updated with the workaround. Please run Sysprep with
the generalize
option enabled.
Known Issues in WMF 5.1
Article • 09/17/2021
Pester
In this release, there are two issues you should be aware of when using Pester on Nano
Server:
Running tests against Pester itself can result in some failures because of
differences between
FULL CLR and CORE CLR. In particular, the Validate method is
not available on the
XmlDocument type. Six tests which attempt to validate the
schema of the NUnit output logs are
known to fail.
One code coverage test fails because the WindowsFeature DSC Resource does not
exist in Nano
Server. However, these failures are generally benign and can safely
be ignored.
Operation Validation
Update-Help fails for Microsoft.PowerShell.Operation.Validation module due to
non-working help
URI
PowerShell
$PreviousDSCStates = @("$env:windir\system32\configuration\*.mof",
"$env:windir\system32\configuration\*.mof.checksum",
"$env:windir\system32\configuration\PartialConfiguration\*.mof",
"$env:windir\system32\configuration\PartialConfiguration\*.mof.checksum
"
PowerShell
Resolution: Re-create the certificate with Data Encipherment or Key Encipherment Key
usage, and
Document Encryption Enhanced Key usage (1.3.6.1.4.1.311.80.1). For more
information, see Protect-CmsMessage.
Output
LCM failed to retrieve the property PendingJobStep from the object of class
dscInternalCache .
+ FullyQualifiedErrorId : MI RESULT 6
+ PSComputerName : localhost
PowerShell
PowerShell
mofcomp $env:windir\system32\wbem\DscCoreConfProv.mof
Resolution: None.
Resolution: None.
Resolution: None.
PowerShell
# Find all the processes hosting PowerShell
Get-PSHostProcessInfo
# Enter the process that is hosting DSC engine (WMI process with
DscPsPluginWkr_Appdomain)
Get-Runspace
Debug-Runspace -Id 2
Resolution: Use different names for even same resources in different partial
configurations.
PowerShell
$session = New-CimSession -ComputerName $node -Credential $credential
Resolution: None.
Resolution: None.
Resolution: Define all variables and functions in DSC Resource class itself. No $script
scope
variables/functions.
Resolution: None.
following
compilation error.
Output
At
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfigurati
on\PSDesiredStateConfiguration.psm1:2035 char:35
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ FullyQualifiedErrorId :
PSInvalidOperationException,ImportClassResourcesFromModule
PowerShell
Import-DscResource -ModuleName
@{ModuleName='MyModuleName';RequiredVersion='1.2'}
PowerShell
$env:windir\system32\config\systemprofile\AppData\Local\Microsoft\Windows\Po
werShell\CommandAnalysis
PowerShell
Configuration $configName
# User Data
Registry SetRegisteredOwner
Ensure = 'Present'
Force = $True
Key = $Node.RegisteredKey
ValueName = $Node.RegisteredOwnerValue
ValueType = 'String'
ValueData = $Node.RegisteredOwnerData
script DeleteCommandAnalysisCache
DependsOn = "[Registry]SetRegisteredOwner"
getscript = "@{}"
setscript = '$true'
Windows PowerShell is a scripting engine .DLL that's embedded into multiple hosts.
The most common
hosts you'll start are the interactive command-line powershell.exe
and the Interactive Scripting
Environment powershell_ise.exe .
To start Windows PowerShell on Windows Server 2012 R2, Windows 8.1, Windows Server
2012, and Windows
8, see Common Management Tasks and Navigation in Windows.
Beginning in PowerShell 6, the PowerShell binary was renamed pwsh.exe for Windows
and pwsh for
macOS and Linux. You can start PowerShell preview versions using pwsh-
preview . For more
information, see About pwsh.
To find cmdlet reference and installation documentation for PowerShell 7, use the
following links:
Document Link
To view content for other PowerShell versions, see How to use the PowerShell
documentation.
Use any of the following methods to start the installed version of Windows PowerShell
3.0, or
Windows PowerShell 4.0, where applicable.
You can also use the parameters of the powershell.exe program to customize the
session. For more
information, see PowerShell.exe Command-Line Help.
To enable Windows PowerShell ISE in Windows PowerShell 2.0 on Windows Server 2008
R2 or Windows
Server 2008, use the following procedure.
However, you might occasionally need to run Windows PowerShell (x86), such as when
you're using
a module that requires the 32-bit version or when you're connecting
remotely to a 32-bit computer.
To start a 32-bit version of Windows PowerShell, use any of the following procedures.
In Windows 8.1
On the Start screen, type Windows PowerShell (x86). Click the Windows
PowerShell x86
tile.
If you're running Remote Server Administration Tools for Windows 8.1, you can
also open
Windows PowerShell x86 from the Server ManagerTools menu. Select
Windows PowerShell (x86).
On the desktop, move the cursor to the upper right corner, click Search, type
PowerShell
x86 and then click Windows PowerShell (x86).
Via command line, enter:
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
Using the Windows PowerShell 2.0
Engine
Article • 10/07/2021
The Windows PowerShell 2.0 Engine is intended to be used only when an existing script
or host
program cannot run because it is incompatible with Windows PowerShell 5.1.
Examples of this include
older versions of Exchange or SQL Server modules. Such cases
are expected to be rare.
Many programs that require the Windows PowerShell 2.0 Engine start it automatically.
These
instructions are included for the rare situations in which you need to start the
engine manually.
Windows PowerShell 2.0 is missing a significant amount of the hardening and security
features added
in versions 3, 4, and 5. We highly, highly recommend that users not use
it if they can help it. For
more information, see A Comparison of Shell and Scripting
Language Security and
PowerShell ♥ the Blue Team .
Systems on which Windows Management Framework 3.0 or higher is installed have all
of the required
components. No further configuration is necessary. For information
about installing Windows
Management Framework, see Install and configure WMF.
How to start the Windows PowerShell 2.0
Engine
When you start Windows PowerShell the newest version starts by default. To start
Windows PowerShell
with the Windows PowerShell 2.0 Engine, use the Version
parameter of PowerShell.exe . You can run
the command at any command prompt,
including Windows PowerShell and Cmd.exe.
PowerShell.exe -Version 2
The following sample command creates the PS2 session configuration on the
Server01 computer. To
run this command, start Windows PowerShell with the Run
as administrator option.
PowerShell
2. To create a session on the Server01 computer that uses the PS2 session
configuration, use the
ConfigurationName parameter of cmdlets that create a
remote session, such as the
`New-PSSession cmdlet.
When a session that uses the session configuration starts, the Windows PowerShell
2.0 Engine is
automatically loaded into the session.
The following command starts a session on the Server01 computer that uses the
PS2 session
configuration. The command saves the session in the $s variable.
PowerShell
The following command starts a background job with the Windows PowerShell 2.0
Engine
PowerShell
DSC is a management platform in PowerShell that enables you to manage your IT and
development
infrastructure with configuration as code.
DSC 1.1 is the legacy version of DSC that originally shipped in Windows PowerShell
5.1.
DSC 3.0 is the new version of DSC. This version is a preview release that is still
being
developed. Users working with non-Windows environments can expect
cross-platform features in DSC
3.0. DSC 3.0 is the version that is supported by the
machine configuration feature of Azure
Automanage.
The documentation for DSC has been moved to a new location so that we can manage
the DSC
version-specific information separate from the versions of PowerShell.
The PowerShell Gallery is the central repository for PowerShell content. In it, you can
find
PowerShell scripts, modules containing PowerShell cmdlets and Desired State
Configuration (DSC)
resources. Some of these packages are authored by Microsoft, and
others are authored by the
PowerShell community.
The PowerShellGet module contains cmdlets for discovering, installing, updating, and
publishing
PowerShell packages from the PowerShell Gallery. These packages can
contain artifacts such as
Modules, DSC Resources, Role Capabilities, and Scripts. Make
sure you have the latest version of
PowerShellGet installed.
The documentation for PowerShellGet and the PowerShell Gallery has been moved to a
new location
so that we can manage the version-specific information separate from the
versions of PowerShell.
h WHAT'S NEW
2023 Updates
2022 Updates
2021 Updates
2020 Updates
Learning resources
d TRAINING
PowerShell 101
Deep Dives
q VIDEO
Community resources
e OVERVIEW
Community support
a DOWNLOAD
Digital art
i REFERENCE
The PowerShell Community is a vibrant and active group of users. This article can help
you get
connected with other member of the community.
The PowerShell community can file issues, bugs, or feature requests in our
GitHub
repository. If you have questions, you may
find help from other members of the
community in one of these public forums:
User Groups
PowerShell Tech Community
DSC Community
PowerShell.org
StackOverFlow
r/PowerShell subreddit
PowerShell Virtual User Group - join via:
Slack
Discord
PRs Merged 2015 2016 2017 2018 2019 2020 2021 2022 2023 Grand
Total
kiazhi 25 79 12 116
alexandair 57 7 26 2 1 93
doctordns 5 32 20 7 9 5 1 79
sethvs 1 43 20 1 10 75
ehmiiz 22 7 29
yecril71pl 21 3 3 27
Dan1el42 20 20
NReilingh 2 13 3 18
it-praktyk 16 1 17
skycommand 1 3 3 6 1 2 16
vors 15 1 16
kvprasoon 2 1 7 2 2 2 16
markekraus 11 5 16
PRs Merged 2015 2016 2017 2018 2019 2020 2021 2022 2023 Grand
Total
purdo17 13 13
k-takai 5 1 7 13
PlagueHO 10 1 11
bergmeister 1 3 3 1 1 1 1 11
exchange12rocks 7 3 1 11
Issues Opened 2015 2016 2017 2018 2019 2020 2021 2022 2023 Grand
Total
mklement0 19 60 56 61 28 8 10 242
iSazonov 1 4 10 8 4 3 30
ehmiiz 20 7 27
jszabo98 2 15 6 1 1 25
juvtib 15 7 22
doctordns 5 3 5 7 1 21
vexx32 3 11 3 17
peetrike 1 4 2 6 2 15
KirkMunro 7 7 1 15
alexandair 9 4 2 15
clamb123 14 14
trollyanov 11 1 12
rkeithhill 1 2 2 2 3 1 1 12
iRon7 2 2 2 6 12
JustinGrote 1 3 6 1 1 12
Issues Opened 2015 2016 2017 2018 2019 2020 2021 2022 2023 Grand
Total
CarloToso 10 10
UberKluger 1 7 2 10
vors 1 6 2 1 10
LaurentDardenne 3 2 5 10
kilasuit 3 2 1 4 10
What's new in PowerShell Docs for 2023
Article • 06/01/2023
This article lists notable changes made to docs each month and celebrates the
contributions from the
community.
Help us make the documentation better for you. Read the Contributor's Guide to learn
how
to get started.
2023-May
New content
Updated content
The following people contributed to PowerShell docs this month by submitting pull
requests or
filing issues. Thank you!
GitHub Id PRs merged Issues opened
rwp0 1
pronichkin 1
Ooggle 1
mavaddat 1
IanKemp 1
mcdonaldjc 1
Brizio 1
dotnvo 1
r0bfr 1
mklement0 3
aksarben 2
crisman 2
2023-April
New content
Updated content
thepowerstring 1 1
53883 1 1
The following people contributed to PowerShell docs this month by submitting pull
requests or
filing issues. Thank you!
GitHub Id PRs merged Issues opened
NLZ 1
Jonathan-Quilter 1
2023-March
New content
Updated content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
skycommand 2
martincostello 1
iRon7 1 4
chrullrich 1
FlintyLemming 1
GitHub Id PRs merged Issues opened
ehmiiz 1
vvavrychuk 1
bb-froggy 1
BenjamimCS 1
kirillkrylov 1
bergmeister 1
lizy14 1
CarloToso 5
MartinGC94 2
rgl 2
2023-February
New Content
Content updates
Major update to
about_PowerShell_Config
Update to
about_Logging_Non-Windows
for macOS instructions
Major update to Class-based DSC Resources and
other related articles for DSC v2
joshua-russell 4 1
1NF053C 1
doctordns 1
Hrxn 1
KyleMit 1
VertigoRay 1
ehmiiz 1
ArmaanMcleod 2
mklement0 2
2023-January
New Content
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
ehmiiz 5 5
szabolevo 5 7
anderjef 2
turbedi 1
desk7 1
cobrabr 1
ZYinMD 1
tompazourek 1
kenyon 1
cjvandyk 1
JTBrinkmann 1
mklement0 4
CarloToso 3
KyleMit 2
iRon7 2
What's new in PowerShell Docs for 2022
Article • 02/02/2023
This article lists notable changes made to docs each month and celebrates the
contributions from the
community.
Help us make the documentation better for you. Read the Contributor's Guide to learn
how
to get started.
2022-December
New Content
about_PSItem
Configuring a light colored theme
What's new in Crescendo 1.1
Export-CrescendoCommand
PowerShell 7.4 (preview) cmdlet reference - a direct copy of the 7.3 content in
preparation for
the preview release of PowerShell 7.4
GitHub stats
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
ehmiiz 8 7
changeworld 3
szabolevo 1
amkhrjee 1
GitHub Id PRs merged Issues opened
xtqqczze 1 3
ALiwoto 1 2
mklement0 3
2022-November
New Content
Content updates
GitHub stats
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
ehmiiz 9 8
chadmando 1
baardhermansen 1
GitHub Id PRs merged Issues opened
skycommand 1
mklement0 3
peetrike 2
2022-October
New Content
Content updates
Hacktoberfest 2022
cleanup efforts
Thank you to @ehmiiz, @TSanzo-BLE, and @chadmando for their Hacktoberfest
PRs! Their 11 PRs
touched 114 articles.
Published PowerShell SDK .NET API content for
PowerShell 7.2 and
7.3-preview
The first updates since PowerShell 7.1 released in November 2020
Removed the unsupported versions 6.0 and 7.1
Added a list of aliases not available on Linux and macOS to
PowerShell differences
on non-Windows platforms
GitHub stats
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
ehmiiz 5 5
TSanzo-BLE 4
yecril71pl 2
chadmando 2
GigaScratch 1 1
GitHub Id PRs merged Issues opened
rbleattler 1
spjeff 1
adamdriscoll 1
manuelcarriernunes 1
michelangelobottura 1
dmpe 1
KamilPacanek 1
SetTrend 2
2022-September
No new content this month.
Content updates
GitHub stats
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
DonaldDWebster 1
emerconghaile 1
floojah 1
imere 1
mcdonaldjc 1
rayden84 1
GitHub Id PRs merged Issues opened
sirsql 1
tig 1
b-long 2
2022-August
New content
Content updates
Other Projects
Get-WhatsNew
cmdlet released - This cmdlet displays release notes for all
versions of PowerShell so you can see
what's new for a particular version.
GitHub stats
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
sethvs 4
GitHub Id PRs merged Issues opened
BEEDELLROKEJULIANLOCKHART 1
Chemerevsky 1
ClaudioESSilva 1
davidhaymond 1
DavidMetcalfe 1
dharmatech 1
kozhemyak 1
mcawai 1
NaridaL 1
Nicicalu 1
sdarwin 1
seansaleh 1
2022-July
New content
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
Alvynskio 1
bergmeister 1
BusHero 1
lewis-yeung 1
sethvs 1
tommymaynard 1
2022-June
New content migrated from GitHub wiki
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
mcdonaldjc 2 1
radrow 1
yecril71pl 1
muhahaaa 1
windin7cc 1
fabiod89 1
NaridaL 1
2022-May
New content
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
tommymaynard 5
naveensrinivasan 2
rikurauhala 1
joshua6point0 1
rhorber 1
Raton-Laveur 1
StephenRoille 1
krlinus 2
2022-April
New content
Content updates
Other projects
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
Hrxn 1
kevinholtkamp 1
MikeyBronowski 1
tommymaynard 4
2022-March
New Content
Content updates
Other projects
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
AspenForester 1
codaamok 1
DianaKuzmenko 1
MikeyBronowski 1
poshdude 1
GitHub Id PRs merged Issues opened
robcmo 1
sertdfyguhi 1
stampycode 1
2022-February
New Content
about_Calling_Generic_Methods
Content updates
Catching up on issues
Updates for 7.3 preview content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
sethvs 2
guilhermgonzaga 1
2022-January
New Content
No new content. We're down to one writer for PowerShell. I was out of the office
for half of
December for vacation then half of January for COVID.
Content updates
Catching up on issues
Updates for 7.3 preview content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
sethvs 3
UberKluger 1
MiguelDomingues 1
reZach 1
Hertz-Hu 1
julian-hansen 1
Hrxn 1
peteraritchie 1
What's new in PowerShell Docs for 2021
Article • 02/02/2023
This article lists notable changes made to docs each month and celebrates the
contributions from the
community.
Help us make the documentation better for you. Read the Contributor's Guide to learn
how
to get started.
2021-December
New Content
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
dAu6jARL 1
shriharshmishra 1
GitHub Id PRs merged Issues opened
a-sync 1
bogdangrigg 1
2021-November
New Content
about_Built-in_Functions
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
matt9ucci 4
yecril71pl 3
tholabrk 1
lukejjh 1
Oechiih 1
bergmeister 1
Hrxn 1
GitHub Id PRs merged Issues opened
jebeckham 1
2021-October
New Content
PSScriptAnalyzer documentation
Overview
Rules documentation
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
doctordns 4
diecknet 1
Kagre 1
KexyBiscuit 1
JohnRoos 1
Zhu-Panda 1
philanderson888 1
BlackFalcons 1
GitHub Id PRs merged Issues opened
milaandahiya 1
mklement0 2
2021-September
New Content
SDK documentation
How to validate an argument using a script
ValidateScript Attribute Declaration
Learning content
PowerShell security features
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
RaghuRocks3 1
Zhu-Panda 1
Jaykul 1
juvtib 1
przmv 1
mklement0 2
2021-August
New content
about_ANSI_Terminals
about_PSCustomObject
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
GitHub Id PRs merged Issues opened
AvrumFeldman 1
benmccallum 1
bitdeft 2
BraINstinct0 1
diddledani 1
doctordns 1
gravitional 1
homotechsual 1
imba-tjd 1
juvtib 1
kozhemyak 1
omarys 1
ryandasilva2992 1
sethvs 1
sneakernuts 1
2021-July
New content
about_Functions_Argument_Completion
about_Tab_Expansion
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
rkeithhill 2
juvtib 2
SetTrend 1
Rob-S 1
xtqqczze 1
akashdabhi03 1
kurtmckee 1
clamb123 13
mklement0 2
jerryKahnPerl 2
2021-June
New content
about_Intrinsic_Members
about_Booleans
Content updates
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
rkeithhill 1
frenchiveruti 2
paulaustin-automutatio 2
ringerc 2
trollyanov 2
UberKluger 2
2021-May
New Content
Migrated two articles from the Windows Server content to the PowerShell docset
PowerShell scripting performance considerations
PowerShell module authoring considerations
Added PowerShell Language Specification 3.0
The specification document is available from the Microsoft Download
Center as
a Microsoft Word document .
Updated content for PowerShell 7.2-Preview6 release
Moved Samples under the Learn node in the Table of Contents
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
kvprasoon 2
jErprog 1
aamnah 1
BetaLyte 1
TheNCuber 1
trollyanov 6
Tarjei-stavanger 3
aungminko93750 3
SetTrend 2
cdichter 2
reuvygroovy 2
2021-April
New Content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
ealmonte32 1
hananyajacobson 1
MarcChasse 1
Melvin-Abraham 1
robertkruk 1
MikeMM70 2
2021-March
New content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
bl-ue 1
brianary 1
Lx 1
matt9ucci 1
kfasick 1
mklement0 10
juvtib 6
BoJackem23 2
2021-February
New content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
bbodenmiller 1
GitHub Id PRs merged Issues opened
brianary 1
exchange12rocks 1
IvenBach 1
jamiepinheiro 1
jdoubleu 1
LogicalToolkit 1
matt9ucci 1
mihir-ajmera 1
revolter 1
secretGeek 1
springcomp 1
Ayanmullick 2
2021-January
New content
The following people have contributed to PowerShell docs by submitting pull requests
or filing
issues. Thank you!
AndreyMatrosov 4
revolter 2
GitHub Id PRs merged Issues opened
cconrad 1
Hrxn 1
kilasuit 1
NN--- 1
snickler 1
vinian 1
zeekbrown 1
brianary 2
mklement0 2
plastikfan 2
What's new in PowerShell Docs for 2020
Article • 02/02/2023
This article lists notable changes made to docs each month and celebrates the
contributions from the
community.
Help us make the documentation better for you. Read the Contributor's Guide to learn
how
to get started.
2020-December
Updated contributor guide
documented the &preserve_view=true query parameter for hyperlinks
documented cross-reference syntax for hyperlinks
added information about localization
GitHub stats
44 PRs merged (11 from Community)
50 issues opened (43 from Community)
50 issues closed
doctordns 3 2
chadbaldwin 1
dawedawe 1
dumpvn 1
kvprasoon 1
lbearl 1
petershen0307 1
skycommand 1
GitHub Id PRs merged Issues opened
springcomp 1
Cwilson-dataselfcom 5
bobbybatatina 2
2020-November
PowerShell 7.1 GA Release
What's New in PowerShell 7.1
Converted 7.1 docs to release status
Added 7.2 (preview) docs
Retired v6 docs to archive repository
Blog posts
You've got Help!
Updating help for the PSReadLine module
Documentation maintenance
Updated 137 articles to remove MSDN and TechNet references
Updated 171 articles to indicate Windows-only compatibility
Updated 38 articles to address build warnings and suggestions
Added include to 24 DSC articles
Major rewrite of the PowerShell Jobs articles
about_Jobs
about_Remote_Jobs
about_Thread_Jobs
GitHub stats
50 PRs merged (8 from Community)
55 issues opened (45 from Community)
51 issues closed
AlanFlorance 1
GitHub Id PRs merged Issues opened
gilbertbw 1
ianwalkeruk 1
JeremyTBradshaw 1
matt9ucci 1
Rob-S 1
ShaydeNofziger 1
skycommand 1
juvtib 8
iRon7 2
l-ip 2
stephenrgentry 2
Vixb1122 2
2020-October
New articles
about_Character_Encoding
about_Output_Streams
Using Visual Studio Code to debug compiled cmdlets (thanks @fsackur)
Add Credential support to PowerShell functions (thanks @joshduffney)
Documentation maintenance
Updates for 7.1-rc content
Updated all article descriptions to improve SEO
GitHub stats
61 PRs merged (7 from Community)
49 issues opened (42 from Community)
61 issues closed
doctordns 1
escape208 1
nickdevore 1
fsackur 1
Duffney 1
skycommand 1
yecril71pl 1
mklement0 3
Abdullah0820 2
2020-September
Documentation maintenance
Updates for 7.1-preview content
Community presentation
How to contribute to Docs for RTPUG - https://www.youtube.com/watch?
v=0_DEB61YOMc
GitHub stats
41 PRs merged (9 from Community)
52 issues opened (47 from Community)
51 issues closed
doctordns 1
GitHub Id PRs merged Issues opened
fatherjack 1
goforgold 1
jonathanweinberg 1
kvprasoon 1
skycommand 1
springcomp 1
themichaelbender 1
toddryan 1
mklement0 13
setpeetrike 2
2020-August
New PowerShell documentation
About_Calculated_Properties
Writing Progress across multiple threads with Foreach Parallel
Documentation maintenance
Updates for 7.1-preview content
GitHub stats
69 PRs merged (26 from Community)
68 issues opened (49 from Community)
58 issues closed
sethvs 10 2
yecril71pl 10
GitHub Id PRs merged Issues opened
mklement0 1 7
springcomp 1 2
SquirrelAssassin 2
thorstenbutz 2
aetos382 1
crumdev 1
joshSi 1
kmoad 1
2020-July
New PowerShell documentation
Resurrected old ETS docs - 7 articles added
Added article about creating updateable help using PlatyPS
Documentation maintenance
Updates for 7.1-preview content
Updated page header - simplified menu choices and added a download button
Fixed several Update-Help issues
Help for PSDesiredStateConfiguration and ThreadJob modules now
downloads
Published updateable help for PowerShell 7.1 preview
Updateable help for PowerShell 5.1 now includes About topics
GitHub stats
99 PRs merged (29 from Community)
51 issues opened (44 from Community)
71 issues closed
yecril71pl 10 3
sethvs 10
springcomp 3 2
txtor 2 1
baardhermansen 1
skycommand 1
srjennings 1
xtqqczze 1
mklement0 3
Allexxann 2
sharpninja 2
XuHeng1021 2
2020-June
New PowerShell documentation
Published new PowerShell 101 content contributed by Mike F.
Robbins
Added two recent blog posts from Rob Holt to the Scripting and development
docs
Choosing the right PowerShell NuGet package for your .NET project
Resolving PowerShell module assembly dependency conflicts
Documentation maintenance
Archived older content to https://aka.ms/PSLegacyDocs
PowerShell Web Access SDK content
PowerShell Workflows SDK content
Updates for 7.1-preview content
GitHub stats
83 PRs merged (15 from Community)
68 issues opened (52 from Community)
74 issues closed
Top Community Contributors
The following people have contributed to PowerShell docs by submitting pull requests
or filling
issues. Thank you!
doctordns 3
gabrielmccoll 2
adrianhale 1
aisbergde 1
beatcracker 1
bergmeister 1
DarioArzaba 1
gforceg 1
jpomfret 1
Karl-WE 1
signalwarrant 1
skycommand 1
tkhadimullin 1
johnkberry 2
juvtib 2
mklement0 2
Sagatboy33 4
2020-May
New PowerShell documentation
Created a new Deep dives section containing content from
community
contributor Kevin Marquette
Everything you want to know about arrays
Everything you want to know about hashtables
Everything you want to know about PSCustomObject
Everything you want to know about string substitution
Everything you want to know about if/then/else
Everything you want to know about switch
Everything you want to know about exceptions
Everything you want to know about $null
Everything you want to know about ShouldProcess
How to create a Standard Library binary module
Published the PowerShell 7.0 .NET API
reference
Update-Help -Force for PowerShell 5.1 now downloads updated content for the
core PowerShell
modules
Documentation maintenance
Major reorganization of the Table of Contents
New content under Learning PowerShell
Windows PowerShell 5.1 content collected in one location
Archived older content to https://aka.ms/PSLegacyDocs
PowerShell Web Access
PowerShell Workflows Guide
Updates for 7.1-preview content
GitHub stats
81 PRs merged (21 from Community)
61 issues opened (53 from Community)
64 issues closed
nschonni 10
xtqqczze 2 1
kilasuit 1 1
davidseibel 1
doctordns 1
jhoffmann271 1
KevinMarquette 1
GitHub Id PRs merged Issues opened
klitztuch 1
markojorge 1
perjahn 1
schuelermine 1
jsilverm 7
mklement0 5
cam1170 2
JustinGrote 2
peetrike 2
2020-April
New documents
PowerShell documentation
Using Experimental Features
about_PSModulePath
Wiki articles
The case for and against Invoke-Expression
Variables can be assigned values as part of an expression (with limitations)
Documentation maintenance
Now publishing updates to Microsoft Learn on a daily schedule
Monday-Friday 3pm Redmond Time (UTC-8)
Restructured the Community content
Many editorial cleanups
Updated Contributor Guide
Clarified some formatting rules
New information about table formatting
GitHub stats
74 PRs merged (8 from Community)
79 issues opened (71 from Community)
102 issues closed
ScSurber 1 1
alexandair 1
bmkaiser 1
hyoshioka0128 1
jpomfret 1
raydixon 1
signalwarrant 1
mklement0 8
reinierk 3
scabon 2
Abdullah0820 2
awooga 2
Damag3d 2
Fiasco123 2
Jasonthurston 2
2020-March
New documents
The PowerShell Docs community pages
Community resources page
What's new in PowerShell Docs page (this page)
PowerShell Infographic
added to the Digital Art page
PowerShell-Doc contributor guide
New PowerShell content
Migrating from Windows PowerShell 5.1 to PowerShell 7
PowerShell 7 module compatibility list
Using PowerShell in Docker
New Wiki content
PowerShell prevents exceptions for non existent keys for types that
implement IDictionary TKey, TValue
PowerShell's treatment of namespaces is case insensitive but case
preserving
Documentation maintenance
Massive cleanup of broken links
Cleanup of old and duplicate issues
GitHub stats
100 PRs merged (14 from Community)
68 issues opened (56 from Community)
109 issues closed
k-takai - 7 PRs
mklement0 - 5 issues
juvtib - 4 issues
iSazonov - 3 issue
doctordns - 2 issues
mdorantesm - 2 issues
qt3m45su0najc7 - 2 issues
2020-February
New documents
about_Parameter_Sets
Release history of modules and cmdlets
PowerShell 7 documentation updates
Updates to address issues
Ran PlatyPS to verify parameter info for all cmdlets and versions
GitHub stats
52 PRs merged (9 from Community)
49 issues opened (42 from Community)
55 issues closed
Maamue - 2 PRs
doctordns - 2 PRs
mklement0 - 4 issues
he852100 - 3 issues
VectorBCO - 2 issues
metablaster - 2 issues
2020-January
New documents
about_Windows_PowerShell_Compatibility
PowerShell 7 documentation updates
Updates to address issues
GitHub stats
58 PRs merged (7 from Community)
57 issues opened (43 from Community)
70 issues closed
Makovec - 3 PRs
mklement0 - 9 issues
mvadu - 2 issues
razos - 2 issues
VLoub - 2 issues
doctordns - 2 issues
PowerShell Digital Art
Article • 05/05/2022
The legends are true! The powerful shell that ensures safe passage to the cloud. But how?
Please enjoy the digital artwork linked below. Demonstrate to your peers that you have
been
entrusted with the Scrolls of Monad!
PowerShell Infographic
PowerShell Infographic
Comic
PowerShell Hero Comic (High resolution)
PowerShell Hero Comic (Print resolution)
PowerShell Hero Comic (Web resolution)
Wallpaper
PowerShell Hero Comic Wallpaper (4k resolution)
PowerShell Hero Pink Wallpaper (4k resolution)
PowerShell Hero White Wallpaper (4k resolution)
Poster
PowerShell Hero Poster
PowerShell Hero
PowerShell Hero Image
Microsoft reserves the right in its sole discretion to terminate or modify permission to
display
the logo or artwork, and may request that third parties modify or delete any use
of the logo or
artwork that, in Microsoft's sole judgment, does not comply with these
guidelines or might
otherwise impair Microsoft's rights in the logo.
Using Visual Studio Code for PowerShell
Development
Article • 11/07/2022
Visual Studio Code (VS Code) is a cross-platform script editor by Microsoft. Together
with
the PowerShell extension , it provides a rich and interactive script editing
experience,
making it easier to write reliable PowerShell scripts. Visual Studio Code with
the PowerShell
extension is the recommended editor for writing PowerShell scripts.
7 Note
Getting started
Before you begin, make sure PowerShell exists on your system. For modern workloads
on Windows,
macOS, and Linux, see the following links:
) Important
The Windows PowerShell ISE is still available for Windows. However, it's no longer
in
active feature development. The ISE only works with PowerShell 5.1 and older. As
a component of
Windows, it continues to be officially supported for security and
high-priority servicing fixes.
we've no plans to remove the ISE from Windows.
For example, to create a new file, click File > New. To save it, click File > Save and then
provide a filename, such as HelloWorld.ps1 . To close the file, click the X next to the
filename.
To exit VS Code, File > Exit.
This problem can occur when PowerShell's execution policy is set by Windows Group
Policy. To
manually approve PowerShell Editor Services and the PowerShell extension for
VS Code, open a
PowerShell prompt and run the following command:
PowerShell
Import-Module $HOME\.vscode\extensions\ms-
vscode.powershell*\modules\PowerShellEditorServices\PowerShellEditorServices
.psd1
You're prompted with Do you want to run software from this untrusted publisher?
Type A to run
the file. Then, open VS Code and verify that the PowerShell extension is
functioning properly. If
you still have problems getting started, let us know in a GitHub
issue .
If you installed PowerShell to a non-typical location, it might not show up initially in the
Session
Menu. You can extend the session menu by adding your own custom paths as
described below.
The PowerShell session menu can also be accessed from the {} icon in the bottom right
corner of
status bar. Hovering on or selecting this icon displays a shortcut to the session
menu and a small
pin icon. If you select the pin icon, the version number is added to the
status bar. The version
number is a shortcut to the session menu requiring fewer clicks.
7 Note
Pinning the version number replicates the behavior of the extension in versions of
VS Code before
1.65. The 1.65 release of VS Code changed the APIs the PowerShell
extension uses and standardized
the status bar for language extensions.
JSON
"editor.renderWhitespace": "all",
"editor.renderControlCharacters": true,
"files.trimTrailingWhitespace": true,
"files.encoding": "utf8bom",
"files.autoGuessEncoding": true
If you don't want these settings to affect all files types, VS Code also allows per-
language
configurations. Create a language-specific setting by putting settings in a
[<language-name>]
field. For example:
JSON
"[powershell]": {
"files.encoding": "utf8bom",
"files.autoGuessEncoding": true
Tip
1. From the Command Palette search for and select Open User Settings. Or use the
keyboard shortcut on Windows or Linux Ctrl + , . On macOS, use
Cmd + , .
2. In the Settings editor, search for PowerShell Additional Exe Paths.
3. Click Add Item.
4. For the Key (under Item), provide your choice of name for this additional
PowerShell
installation.
5. For the Value (under Value), provide the absolute path to the executable itself.
You can add as many additional paths as you like. The added items show up in the
session menu with
the given key as the name.
JSON
"powershell.powerShellAdditionalExePaths": {
"Downloaded PowerShell":
"C:/Users/username/Downloads/PowerShell/pwsh.exe",
"Built PowerShell":
"C:/Users/username/src/PowerShell/src/powershell-win-
core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe"
},
7 Note
Prior to version 2022.5.0 of the extension, this setting was a list of objects with the
required
keys exePath and versionName . A breaking change was introduced to
support configuration via
GUI. If you had previously configured this setting, please
convert it the new format. The value
given for versionName is now the Key, and the
value given for exePath is now the
Value. You can do this more easily by resetting
the value and using the Settings interface.
JSON
"powershell.powerShellAdditionalExePaths": {
"Downloaded PowerShell":
"C:/Users/username/Downloads/PowerShell/pwsh.exe",
},
After you've configured this setting, restart VS Code or to reload the current VS Code
window from
the Command Palette, type Developer: Reload Window .
If you open the session menu, you now see your additional PowerShell installations.
Tip
If you build PowerShell from source, this is a great way to test out your local build
of
PowerShell.
No-workspace debugging
In VS Code version 1.9 (or higher), you can debug PowerShell scripts without opening
the folder that
contains the PowerShell script.
1. Open the PowerShell script file with File > Open File...
2. Set a breakpoint - select a line then press F9
You should see the Debug actions pane appear that allows you to break into the
debugger, step,
resume, and stop debugging.
Workspace debugging
Workspace debugging refers to debugging in the context of a folder that you've opened
from the
File menu using Open Folder.... The folder you open is typically your
PowerShell project
folder or the root of your Git repository. Workspace debugging
allows you to define multiple debug
configurations other than just debugging the
currently open file.
Launch Current File - Launch and debug the file in the currently active editor
window
Launch Script - Launch and debug the specified file or command
Interactive Session - Debug commands executed from the Integrated
Console
Attach - Attach the debugger to a running PowerShell Host Process
JSON
"version": "0.2.0",
"configurations": [
"type": "PowerShell",
"request": "launch",
"script": "${file}",
"args": [],
"cwd": "${file}"
},
"type": "PowerShell",
"request": "attach",
"processId": "${command.PickPSHostProcess}",
"runspaceId": 1
},
"type": "PowerShell",
"request": "launch",
"cwd": "${workspaceRoot}"
This file represents the common debug scenarios. When you open this file in the editor,
you see an
Add Configuration... button. You can click this button to add more
PowerShell debug
configurations. One useful configuration to add is PowerShell:
Launch Script. With this
configuration, you can specify a file containing optional
arguments that are used whenever you press
F5 no matter which file is active in the
editor.
After the debug configuration is established, you can select the configuration you want
to use
during a debug session. Select a configuration from the debug configuration
drop-down in the
Debug view's toolbar.
Useful resources
There are a few videos and blog posts that may be helpful to get you started using the
PowerShell
extension for VS Code:
Videos
Using Visual Studio Code as Your Default PowerShell Editor
Visual Studio Code: deep dive into debugging your PowerShell scripts
Blog posts
PowerShell Extension
Write and debug PowerShell scripts in Visual Studio Code
Debugging Visual Studio Code Guidance
Debugging PowerShell in Visual Studio Code
Get started with PowerShell development in Visual Studio Code
Visual Studio Code editing features for PowerShell development - Part 1
Visual Studio Code editing features for PowerShell development - Part 2
Debugging PowerShell script in Visual Studio Code - Part 1
Debugging PowerShell script in Visual Studio Code - Part 2
If you're interested in contributing, Pull Requests are greatly appreciated. Follow along
with the
developer documentation on GitHub to get started.
How to replicate the ISE experience in
Visual Studio Code
Article • 11/17/2022
While the PowerShell extension for VS Code doesn't seek complete feature parity with
the PowerShell
ISE, there are features in place to make the VS Code experience more
natural for users of the ISE.
This document tries to list settings you can configure in VS Code to make the user
experience a bit
more familiar compared to the ISE.
ISE Mode
7 Note
This feature is available in the PowerShell Preview extension since version 2019.12.0
and in the
PowerShell extension since version 2020.3.0.
The easiest way to replicate the ISE experience in Visual Studio Code is by turning on
"ISE Mode".
To do this, open the command palette ( F1 OR Ctrl + Shift + P
OR Cmd +
Shift + P on macOS) and type in "ISE Mode". Select
"PowerShell: Enable ISE Mode"
from the list.
This command automatically applies the settings described below The result looks like
this:
ISE Mode configuration settings
ISE Mode makes the following changes to VS Code settings.
Key bindings
7 Note
Simplified ISE-like UI
If you're looking to simplify the Visual Studio Code UI to look more closely to the
UI of the ISE,
apply these two settings:
JSON
"workbench.activityBar.visible": false,
"debug.openDebug": "neverOpen",
These settings hide the "Activity Bar" and the "Debug Side Bar" sections shown
inside the red box
below:
Tab completion
JSON
"editor.tabCompletion": "on",
"powershell.integratedConsole.focusConsoleOnExecute": false
JSON
"powershell.integratedConsole.showOnStartup": false
7 Note
JSON
"files.defaultLanguage": "powershell",
Color scheme
There are a number of ISE themes available for VS Code to make the editor look
much more like the
ISE.
In the Command Palette type theme to get Preferences: Color Theme and press
JSON
In the Command Palette, enter PowerShell Command Explorer and press Enter .
If you want to open a file in the Windows PowerShell ISE anyway, open the
Command Palette,
search for "open in ise", then select PowerShell: Open Current
File in PowerShell ISE.
Other resources
4sysops has a great article on configuring VS Code to be more like the ISE.
Mike F Robbins has a great post on setting up VS Code.
VS Code Tips
Command Palette
The Command Palette is handy way of executing commands in VS Code. Open the
command palette using
F1 OR Ctrl + Shift + P OR
Cmd + Shift + P on macOS.
If you only plan on using VS Code for PowerShell scripting, you can hide the
Debug Console
since it'sn't used by the PowerShell extension. To do so, right click
on Debug Console then
click on the check mark to hide it.
More settings
If you know of more ways to make VS Code feel more familiar for ISE users, contribute
to this doc.
If there's a compatibility configuration you're looking for, but you can't find
any way to enable
it, open an issue and ask away!
For those of you that are familiar with the ISE, you may recall that you could run psedit
file.ps1
from the integrated console to open files - local or remote - right in the ISE.
This feature is also available in the PowerShell extension for VSCode. This guide shows
you how to
do it.
Prerequisites
This guide assumes that you have:
This feature also works when connecting to a remote machine via WinRM, PowerShell
Direct, or SSH. If
you want to use SSH, but are using Windows, check out the Win32
version of SSH !
) Important
Usage examples
These examples show remote editing and debugging from a MacBook Pro to an Ubuntu
VM running in
Azure. The process is identical on Windows.
In short:
First, in the Integrated Console, run Enter-PSSession . You're connected to the remote
session when
[<hostname>] shows up to the left of your prompt.
Now, we can do the same steps as if we're editing a local script.
If you have any problems, you can open issues in the GitHub repo .
Understanding file encoding in VS Code
and PowerShell
Article • 12/16/2022
When using VS Code to create and edit PowerShell scripts, it's important that your files
are saved
using the correct character encoding format.
Similarly, when PowerShell runs a script it must convert the bytes in a file to characters
to
reconstruct the file into a PowerShell program. Since VS Code writes the file and
PowerShell reads
the file, they need to use the same encoding system. This process of
parsing a PowerShell script
goes: bytes -> characters -> tokens -> abstract syntax tree ->
execution.
Both VS Code and PowerShell are installed with a sensible default encoding
configuration. However,
the default encoding used by PowerShell has changed with the
release of PowerShell 6. To ensure you
have no problems using PowerShell or the
PowerShell extension in VS Code, you need to configure your
VS Code and PowerShell
settings properly.
You're more likely to have encoding problems when you're using characters not in the
7-bit ASCII character set . For example:
The encodings of VS Code and PowerShell haven't been changed from their
defaults. For PowerShell
5.1 and below, the default encoding is different from VS
Code's.
Another editor has opened and overwritten the file in a new encoding. This often
happens with the
ISE.
The file is checked into source control in an encoding that's different from what VS
Code or
PowerShell expects. This can happen when collaborators use editors with
different encoding
configurations.
Output
At C:\Users\<User>\<OneDrive>\Development\PowerShell\Scripts\Send-
EmailUsingSmtpRelay.ps1:6 char:1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.SendMailMessage
This problem occurs because VS Code encodes the character – in UTF-8 as the bytes
0xE2 0x80 0x93 . When these bytes are decoded as Windows-1252, they're interpreted
as the
characters â€" .
â€" instead of –
â€" instead of —
Ä2 instead of Ä
1. When scripts are edited in VS Code, the contents are sent by VS Code to the
extension. The
Language Server Protocol mandates that this content is
transferred in UTF-8. Therefore, it
isn't possible for the extension to get the wrong
encoding.
2. When scripts are executed directly in the Integrated Console, they're read from the
file by
PowerShell directly. If PowerShell's encoding differs from VS Code's,
something can go wrong
here.
3. When a script that's open in VS Code references another script that isn't open in
VS Code, the
extension falls back to loading that script's content from the file
system. The PowerShell
extension defaults to UTF-8 encoding, but uses byte-order
mark , or BOM, detection to select
the correct encoding.
The problem occurs when assuming the encoding of BOM-less formats (like UTF-8
with no BOM
and Windows-1252 ). The PowerShell extension defaults to UTF-8. The
extension can't
change VS Code's encoding settings. For more information, see
issue
#824 .
In .NET Standard, on the web, and in the Linux world, UTF-8 is now the dominant
encoding.
Many .NET Framework applications use UTF-16 . For historical reasons, this is
sometimes
called "Unicode", a term that now refers to a broad standard that
includes both UTF-8 and
UTF-16.
On Windows, many native applications that predate Unicode continue to use
Windows-1252 by default.
Unicode encodings also have the concept of a byte-order mark (BOM). BOMs occur at
the beginning of
text to tell a decoder which encoding the text is using. For multi-byte
encodings, the BOM also
indicates endianness of the encoding. BOMs are designed to
be bytes that rarely occur in
non-Unicode text, allowing a reasonable guess that text is
Unicode when a BOM is present.
BOMs are optional and their adoption isn't as popular in the Linux world because a
dependable
convention of UTF-8 is used everywhere. Most Linux applications presume
that text input is encoded
in UTF-8. While many Linux applications will recognize and
correctly handle a BOM, a number don't,
leading to artifacts in text manipulated with
those applications.
Therefore:
If you work primarily with Windows applications and Windows PowerShell, you
should prefer an
encoding like UTF-8 with BOM or UTF-16.
If you work across platforms, you should prefer UTF-8 with BOM.
If you work mainly in Linux-associated contexts, you should prefer UTF-8 without
BOM.
Windows-1252 and latin-1 are essentially legacy encodings that you should avoid
if possible.
However, some older Windows applications may depend on them.
It's also worth noting that script signing is encoding-dependent , meaning a
change of
encoding on a signed script will require resigning.
Configuring VS Code
VS Code's default encoding is UTF-8 without BOM.
JSON
"files.encoding": "utf8bom"
You should get a dropdown for this in the GUI view, or completions for it in the JSON
view.
You can also add the following to autodetect encoding when possible:
JSON
"files.autoGuessEncoding": true
If you don't want these settings to affect all files types, VS Code also allows per-
language
configurations. Create a language-specific setting by putting settings in a
[<language-name>]
field. For example:
JSON
"[powershell]": {
"files.encoding": "utf8bom",
"files.autoGuessEncoding": true
You may also want to consider installing the Gremlins tracker for Visual Studio Code.
This
extension reveals certain Unicode characters that easily corrupted because they're
invisible or look
like other normal characters.
Configuring PowerShell
PowerShell's default encoding varies depending on version:
In PowerShell 6+, the default encoding is UTF-8 without BOM on all platforms.
In Windows PowerShell, the default encoding is usually Windows-1252, an
extension of
latin-1 , also known as ISO 8859-1.
PowerShell
ForEach-Object {
$_.GetMethod('GetDefaultEncoding',
[System.Reflection.BindingFlags]'nonpublic,static').Invoke($null, @())
The following script can be used to determine what encoding your PowerShell session
infers for
a script without a BOM.
PowerShell
$badBytes = [byte[]]@(0xC3, 0x80)
$utf8Str = [System.Text.Encoding]::UTF8.GetString($badBytes)
try
[System.IO.File]::WriteAllBytes($path, $bytes)
$utf8Str
return 'UTF-8'
break
default
return 'Windows-1252'
break
finally
Remove-Item $path
It's possible to configure PowerShell to use a given encoding more generally using
profile settings.
See the following articles:
It's not possible to force PowerShell to use a specific input encoding. PowerShell 5.1 and
below,
running on Windows with the locale set to en-US, defaults to Windows-1252
encoding when there's no
BOM. Other locale settings may use a different encoding. To
ensure interoperability, it's best to
save scripts in a Unicode format with a BOM.
) Important
Any other tools you have that touch PowerShell scripts may be affected by your
encoding choices or
re-encode your scripts to another encoding.
Existing scripts
Scripts already on the file system may need to be re-encoded to your new chosen
encoding. In the
bottom bar of VS Code, you'll see the label UTF-8. Click it to open the
action bar and select Save
with encoding. You can now pick a new encoding for that
file. See VS Code's encoding
for full instructions.
If you need to re-encode multiple files, you can use the following script:
PowerShell
The ISE should honor a BOM, but it's also possible to use reflection to set the
encoding . Note
that this wouldn't be persisted between startups.
Configure the text encoding in your source control to match your VS Code
configuration.
Ensure all your files are checked into source control in the relevant encoding.
Be wary of changes to the encoding received through source control. A key sign of
this is a diff
indicating changes but where nothing seems to have changed
(because bytes have but characters have
not).
Collaborators' environments
On top of configuring source control, ensure that your collaborators on any files you
share don't
have settings that override your encoding by re-encoding PowerShell files.
Other programs
Any other program that reads or writes a PowerShell script may re-encode it.
Using the clipboard to copy and paste a script. This is common in scenarios like:
Copying a script into a VM
Copying a script out of an email or webpage
Copying a script into or out of a Microsoft Word or PowerPoint document
Other text editors, such as:
Notepad
vim
Any other PowerShell script editor
Text editing utilities, like:
Get-Content / Set-Content / Out-File
Some of these tools deal in bytes rather than text, but others offer encoding
configurations. In
those cases where you need to configure an encoding, you need to
make it the same as your editor
encoding to prevent problems.
about_Character_Encoding
@mklement0's summary of PowerShell encoding on StackOverflow
Previous issues opened on VS Code-PowerShell for encoding problems:
#1308
#1628
#1680
#1744
#1751
The classic Joel on Software write up about Unicode
Encoding in .NET Standard
Using Visual Studio Code to debug
compiled cmdlets
Article • 02/08/2023
This guide shows you how to interactively debug C# source code for a compiled
PowerShell module
using Visual Studio Code (VS Code) and the C# extension.
This guide assumes you have read and followed the instructions in the
Writing Portable
Modules guide.
1. In the Command Palette, run the Configure Default Build Task command.
2. In the Select a task to configure dialog, choose Create tasks.json file from
template.
JSON
"label": "build",
"command": "dotnet",
"type": "shell",
"args": [
"build",
"${workspaceFolder}/myModule",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary",
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
When debugging, your module DLL is imported into the PowerShell session in the VS
Code terminal. The
DLL becomes locked. The following message is displayed when you
run the build task without closing
the terminal session:
Output
When you invoke your cmdlet in the terminal session, the debugger stops at any
breakpoints set in
your source code.
4. The launch.json file is opened in the editor. With your cursor inside the
configurations
array, you see the configuration picker. If you don't see this list,
select
Add Configuration.
5. To create a default debug configuration, select Launch .NET Core Console App:
JSON
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "pwsh",
"args": [
"-NoExit",
"-NoProfile",
"-Command",
"Import-Module
${workspaceFolder}/myModule/bin/Debug/netstandard2.0/myModule.dll",
],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal"
The program field is used to launch pwsh so that the cmdlet being debugged can be run.
The
-NoExit argument prevents the PowerShell session from exiting as soon as the
module is imported.
The path in the Import-Module argument is the default build output
path when you've followed the
Writing Portable Modules guide. If you've created a
module manifest ( .psd1 file), you should
use the path to that instead. The / path
separator works on Windows, Linux, and macOS. You must
use the integrated terminal
to run the PowerShell commands you want to debug.
7 Note
If the debugger doesn't stop at any breakpoints, look in the Visual Studio Code
Debug Console for
a line that says:
If you see this, add "justMyCode": false to your launch config (at the same level as
"console": "integratedTerminal" .
JSON
"type": "clr",
"request": "launch",
"preLaunchTask": "build",
"program": "powershell",
"args": [
"-NoExit",
"-NoProfile",
"-Command",
"Import-Module
${workspaceFolder}/myModule/bin/Debug/netstandard2.0/myModule.dll",
],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal"
Place a breakpoint in the source code for the cmdlet you want to debug:
You can step through the source code, inspect variables, and inspect the call stack.
To end debugging, click Stop in the debug toolbar or press Shift + F5 . The
shell used
for debugging exits and releases the lock on the compiled DLL file.
PowerShell scripting performance
considerations
Article • 04/11/2023
PowerShell scripts that leverage .NET directly and avoid the pipeline tend to be faster
than
idiomatic PowerShell. Idiomatic PowerShell uses cmdlets and PowerShell functions,
often leveraging
the pipeline, and resorting to .NET only when necessary.
7 Note
Many of the techniques described here aren't idiomatic PowerShell and may reduce
the readability
of a PowerShell script. Script authors are advised to use idiomatic
PowerShell unless performance
dictates otherwise.
Suppressing output
There are many ways to avoid writing objects to the pipeline.
PowerShell
$null = $arrayList.Add($item)
[void]$arrayList.Add($item)
File redirection to $null is almost as fast as the previous alternatives. You won't notice a
performance difference for most scripts. However, file redirection does introduce some
overhead.
PowerShell
You can also pipe to Out-Null . In PowerShell 7.x, this is a bit slower than redirection but
probably not noticeable for most scripts.
PowerShell
$arrayList.Add($item) | Out-Null
However, calling Out-Null in a large loop can be significantly slower, even in PowerShell
7.x.
PowerShell
$d = Get-Date
Select-Object TotalSeconds
TotalSeconds
------------
1.0549325
$d = Get-Date
Select-Object TotalSeconds
TotalSeconds
------------
5.9572186
Windows PowerShell 5.1 doesn't have the same optimizations for Out-Null as
PowerShell 7.x, so you
should avoid using Out-Null in performance sensitive code.
Creating a script block and calling it (using dot sourcing or Invoke-Command ) then
assigning the
result to $null is a convenient technique for suppressing the output of a
large block of script.
PowerShell
$null = . {
$arrayList.Add($item)
$arrayList.Add(42)
This technique performs about the same as piping to Out-Null and should be avoided
in performance
sensitive script. The extra overhead in this example comes from the
creation of and invoking a
script block that was previously inline script.
Array addition
Generating a list of items is often done using an array with the addition operator:
PowerShell
$results = @()
$results += Do-Something
$results += Do-SomethingElse
$results
Array addition is inefficient because arrays have a fixed size. Each addition to the array
creates
a new array big enough to hold all elements of both the left and right operands.
The elements of
both operands are copied into the new array. For small collections, this
overhead may not matter.
Performance can suffer for large collections.
There are a couple of alternatives. If you don't actually require an array, instead consider
using
a typed generic list (List<T>):
PowerShell
$results = [System.Collections.Generic.List[object]]::new()
$results.AddRange((Do-Something))
$results.AddRange((Do-SomethingElse))
$results
The performance impact of using array addition grows exponentially with the size of the
collection
and the number additions. This code compares explicitly assigning values to
an array with using
array addition and using the Add() method on a List<T>. It defines
explicit assignment as
the baseline for performance.
PowerShell
$tests = @{
param($count)
$i
'.Add(..) to List<T>' = {
param($count)
$result = [Collections.Generic.List[int]]::new()
foreach($i in 1..$count) {
$result.Add($i)
param($count)
$result = @()
foreach($i in 1..$count) {
$result += $i
[pscustomobject]@{
CollectionSize = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds /
$groupResult[0].TotalMilliseconds
Output
When you're working with large collections, array addition is dramatically slower than
adding to
a List<T>.
When using a List<T>, you need to create the list with a specific type, like String or
Int.
When you add objects of a different type to the list, they are cast to the specified type.
If
they can't be cast to the specified type, the method raises an exception.
PowerShell
$intList = [System.Collections.Generic.List[int]]::new()
$intList.Add(1)
$intList.Add('2')
$intList.Add(3.0)
$intList.Add('Four')
$intList
Output
MethodException:
Line |
5 | $intList.Add('Four')
| ~~~~~~~~~~~~~~~~~~~~
| Cannot convert argument "item", with value: "Four", for "Add" to type
When you need the list to be a collection of different types of objects, create it with
Object
as the list type. You can enumerate the collection inspect the types of the objects
in it.
PowerShell
$objectList = [System.Collections.Generic.List[object]]::new()
$objectList.Add(1)
$objectList.Add('2')
$objectList.Add(3.0)
Output
1 is int
2 is string
3 is double
If you do require an array, you can call the ToArray() method on the list or you can let
PowerShell create the array for you:
PowerShell
$results = @(
Do-Something
Do-SomethingElse
In this example, PowerShell creates an ArrayList to hold the results written to the
pipeline
inside the array expression. Just before assigning to $results , PowerShell
converts the
ArrayList to an object[].
String addition
Strings are immutable. Each addition to the string actually creates a new string big
enough to hold
the contents of both the left and right operands, then copies the
elements of both operands into
the new string. For small strings, this overhead may not
matter. For large strings, this can affect
performance and memory consumption.
PowerShell
$string = ''
Measure-Command {
foreach( $i in 1..10000)
$string
} | Select-Object TotalMilliseconds
TotalMilliseconds
-----------------
641.8168
There are a couple of alternatives. You can use the -join operator to concatenate
strings.
PowerShell
Measure-Command {
$string = @(
) -join "`n"
$string
} | Select-Object TotalMilliseconds
TotalMilliseconds
-----------------
22.7069
In this example, using the -join operator is 30 times faster than string addition.
PowerShell
$sb = [System.Text.StringBuilder]::new()
Measure-Command {
foreach( $i in 1..10000)
[void]$sb.Append("Iteration $i`n")
$sb.ToString()
} | Select-Object TotalMilliseconds
TotalMilliseconds
-----------------
13.4671
In this example, using the StringBuilder is 50 times faster than string addition.
PowerShell
This can be an order of magnitude slower than using .NET APIs directly:
PowerShell
try
$stream = [System.IO.StreamReader]::new($path)
$line
finally
$stream.Dispose()
Given two collections, one with an ID and Name, the other with Name and Email:
PowerShell
[PSCustomObject]@{
Id = $_
Name = "Name$_"
[PSCustomObject]@{
Name = "Name$_"
Email = "[email protected]"
The usual way to reconcile these collections to return a list of objects with the ID, Name,
and Email properties might look like this:
PowerShell
$Employee = $_
[pscustomobject]@{
Id = $Employee.Id
Name = $Employee.Name
Email = $Account.Email
However, that implementation has to filter all 5000 items in the $Accounts collection
once for
every item in the $Employee collection. That can take minutes, even for this
single-value lookup.
Instead, you can make a hash table that uses the shared Name property as a key and
the
matching account as the value.
PowerShell
$LookupHash = @{}
$LookupHash[$Account.Name] = $Account
Looking up keys in a hash table is much faster than filtering a collection by property
values.
Instead of checking every item in the collection, PowerShell can check if the key
is defined and
use its value.
PowerShell
$Email = $LookupHash[$_.Name].Email
[pscustomobject]@{
Id = $_.Id
Name = $_.Name
Email = $Email
This is much faster. While the looping filter took minutes to complete, the hash lookup
takes less
than a second.
Avoid Write-Host
It's generally considered poor practice to write output directly to the console, but when
it makes
sense, many scripts use Write-Host .
If you must write many messages to the console, Write-Host can be an order of
magnitude slower
than [Console]::WriteLine() for specific hosts like pwsh.exe ,
powershell.exe , or
powershell_ise.exe . However, [Console]::WriteLine() isn't
guaranteed to work in all hosts. Also,
output written using [Console]::WriteLine()
doesn't get written to transcripts started by
Start-Transcript .
Loops that have fewer than 300 instructions are eligible for JIT-compilation. Loops larger
than that
are too costly to compile. When the loop has executed 16 times, the script is
JIT-compiled in the
background. When the JIT-compilation completes, execution is
transferred to the compiled code.
PowerShell
$RepeatCount = 10000
$Null = $ranGen.Next()
}).TotalMilliseconds
function Get-RandNum_Core {
param ($ranGen)
$ranGen.Next()
}).TotalMilliseconds
function Get-RandNum_All {
param ($ranGen)
$Null = $ranGen.Next()
Get-RandNum_All $ranGen
}).TotalMilliseconds
The Basic for-loop example is the base line for performance. The second example wraps
the random
number generator in a function that's called in a tight loop. The third
example moves the loop
inside the function. The function is only called once but the
code still generates 10000 random
numbers. Notice the difference in execution times for
each example.
Output
PowerShell
Initializing a new pipeline can be expensive, therefore you should avoid wrapping a
cmdlet
pipeline into another existing pipeline.
Consider the following example. The Input.csv file contains 2100 lines. The Export-Csv
command
is wrapped inside the ForEach-Object pipeline. The Export-Csv cmdlet is
invoked for every
iteration of the ForEach-Object loop.
PowerShell
[PSCustomObject]@{
Id = $Id
Name = $_.opened_by
}).TotalMilliseconds
Wrapped = 15,968.78 ms
For the next example, the Export-Csv command was moved outside of the ForEach-
Object pipeline.
In this case, Export-Csv is invoked only once, but still processes all
objects passed out of
ForEach-Object .
PowerShell
[PSCustomObject]@{
Id = $Id
Name = $_.opened_by
}
} | Export-Csv .\Output2.csv
}).TotalMilliseconds
Unwrapped = 42.92 ms
The unwrapped example is 372 times faster. Also, notice that the first implementation
requires the
Append parameter, which isn't required for the later implementation.
PowerShell module authoring
considerations
Article • 11/17/2022
This document includes some guidelines related to how a module is authored for best
performance.
Guidelines
In the module manifest, don't use wildcards in the AliasesToExport ,
CmdletsToExport , and
FunctionsToExport entries.
If the module doesn't export commands of a particular type, specify this explicitly
in the
manifest by specifying @() . A missing or $null entry is equivalent to
specifying the wildcard
* .
PowerShell
@{
FunctionsToExport = '*'
# CmdletsToExport = '*'
# AliasesToExport = '*'
Instead, use:
PowerShell
@{
Avoid CDXML
When deciding how to implement your module, there are three primary choices:
A binary module loads the fastest because it's compiled ahead of time and can use
NGen to JIT
compile once per machine.
A script module typically loads a bit more slowly than a binary module because
PowerShell must parse
the script before compiling and executing it.
A CDXML module is typically much slower than a script module because it must first
parse an XML file
which then generates quite a bit of PowerShell script that's then
parsed and compiled.
Preventing script injection attacks
Article • 02/10/2023
Once you are aware of the issue, there are several ways to protect against injection
attacks.
PowerShell
function Get-ProcessById
param ($ProcId)
The Get-ProcessById function looks up a local process by its Id value. It takes a $ProcId
parameter argument of any type. The $ProcId is then converted to a string and inserted
into
another script that's parsed and run using the Invoke-Expression cmdlet. This
function works fine
when a valid process Id integer is passed in.
PowerShell
Get-ProcessById $pid
However, the $ProcId parameter doesn't specify a type. It accepts any arbitrary string
value that
can include other commands.
PowerShell
In this example, the function correctly retrieved the process identified by $pid , but also
ran the
injected script Write-Host 'pwnd!' .
Output
pwnd!
PowerShell
function Get-ProcessById
Output
Get-ProcessById:
Line |
| ~~~~~~~~~~~~~~~~~~~~~~~~~
Here, the $ProcId input parameter is restricted to an integer type, so an error occurs
when a
string is passed in that can't be converted to an integer.
PowerShell
function Get-ProcessById
param ($ProcId)
Output
Get-Process:
Line |
| ~~~~~~~
"System.Int32". Error: "The input string '8064; Write-Host 'pwnd!' was not
in a correct
format."
As a best practice, you should avoid using Invoke-Expression , especially when handling
user input.
Invoke-Expression is dangerous because it parses and runs whatever string
content you provide,
making it vulnerable to injection attacks. It's better to rely on
PowerShell parameter binding.
PowerShell
function Get-ProcessById
param ($ProcId)
Output
Get-Process: Cannot bind parameter 'Id'. Cannot convert value "8064; Write-
Host " to type
However, this version of the function isn't yet completely safe from injection attacks. A
malicious
user can still use single quotes in their input to inject code.
PowerShell
This example uses single quotes in the user input to force the function to run three
separate
statements, one of which is arbitrary code injected by the user.
Output
pwnd!
PowerShell
function Get-ProcessById
param ($ProcId)
$ProcIdClean = [System.Management.Automation.Language.CodeGeneration]::
EscapeSingleQuotedStringContent("$ProcId")
Output
Get-Process: Cannot bind parameter 'Id'. Cannot convert value "8064'; Write-
Host 'pwnd!';'" to type
PowerShell
Install-Module InjectionHunter
Install-PSResource InjectionHunter
You can use this to automate security analysis during builds, continuous integration
processes,
deployments, and other scenarios.
PowerShell
Output
RuleName Severity ScriptName Line Message
gerous.ps1 Invoke-
Expression cmdlet. Untrusted input can cause
arbitrary
PowerShell expressions to be run.
Variables
may be used directly for dynamic parameter
arguments,
splatting can be used for dynamic
parameter
names, and the invocation operator can be
used for
dynamic command names. If content escaping
is truly
needed, PowerShell has several valid quote
characters, so [System.Management.Automation.Languag
Related links
Lee Holmes' blog post about Injection Hunter
Injection Hunter
Portable Modules
Article • 11/17/2022
Windows PowerShell is written for .NET Framework while PowerShell Core is written for
.NET Core. Portable modules are modules that work in both Windows PowerShell and
PowerShell
Core. While .NET Framework and .NET Core are highly compatible, there are
differences in the
available APIs between the two. There are also differences in the APIs
available in Windows
PowerShell and PowerShell Core. Modules intended to be used in
both environments need to be aware of
these differences.
Porting a PSSnapIn
PowerShell SnapIns aren't supported in PowerShell Core. However, it's trivial to convert a
PSSnapIn to a PowerShell module. Typically, the PSSnapIn registration code is in a single
source
file of a class that derives from PSSnapIn. Remove this source file from the build;
it's no
longer needed.
Use New-ModuleManifest to create a new module manifest that replaces the need for
the PSSnapIn
registration code. Some values from the PSSnapIn (such as Description)
can be reused within
the module manifest.
The RootModule property in the module manifest should be set to the name of the
assembly
( .dll ) implementing the cmdlets.
PowerShell
Output
Options:
-n, --name The name for the output being created. If no name is
specified, the name of the current directory is used.
----------------------------------------------------------------------------
-------------------
...
Directory: C:\Users\Steve
PS> cd myModule
Restore succeeded.
PowerShell
dotnet build
Output
PS C:\Users\Steve\myModule> dotnet build
Build succeeded.
0 Warning(s)
0 Error(s)
PowerShell
Import-Module .\bin\Debug\netstandard2.0\myModule.dll
Test-SampleCmdlet -?
Output
NAME
Test-SampleCmdlet
SYNTAX
ALIASES
None
REMARKS
None
FavoriteNumber FavoritePet
-------------- -----------
7 Cat
Supporting technologies
The following sections describe in detail some of the technologies used by this
template.
7 Note
Although an API may exist in .NET Standard, the API implementation in .NET Core
may throw a
PlatformNotSupportedException at runtime, so to verify compatibility
with Windows PowerShell
and PowerShell Core, the best practice is to run tests for
your module within both environments.
Also run tests on Linux and macOS if your
module is intended to be cross-platform.
Targeting .NET Standard helps ensure that, as the module evolves, incompatible APIs
don't
accidentally get introduced into the module. Incompatibilities are discovered at
compile time
instead of runtime.
However, it isn't required to target .NET Standard for a module to work with both
Windows PowerShell
and PowerShell Core, as long as you use compatible APIs. The
Intermediate Language (IL) is
compatible between the two runtimes. You can target .NET
Framework 4.6.1, which is compatible with
.NET Standard 2.0. If you don't use APIs
outside of .NET Standard 2.0, then your module works with
PowerShell Core 6 without
recompilation.
We recommend you compile your module using PowerShell Standard Library. The library
ensures the APIs
are available and implemented in both Windows PowerShell and
PowerShell Core 6. PowerShell Standard
is intended to always be forwards-compatible. A
module built using PowerShell Standard Library 5.1
will always be compatible with future
versions of PowerShell.
Module Manifest
After validating that your module works with both Windows PowerShell and PowerShell
Core, the module
manifest should explicitly indicate compatibility by using the
CompatiblePSEditions property.
A value of Desktop means that the module is
compatible with Windows PowerShell, while a value of
Core means that the module is
compatible with PowerShell Core. Including both Desktop and Core
means that the
module is compatible with both Windows PowerShell and PowerShell Core.
7 Note
Core doesn't automatically mean that the module is compatible with Windows,
Indicating OS Compatibility
First, validate that your module works on Linux and macOS. Next, indicate compatibility
with those
operating systems in the module manifest. This makes it easier for users to
find your module for
their operating system when published to the PowerShell
Gallery .
Within the module manifest, the PrivateData property has a PSData sub-property. The
optional
Tags property of PSData takes an array of values that show up in PowerShell
Gallery. The
PowerShell Gallery supports the following compatibility values:
Tag Description
Tag Description
Example:
PowerShell
@{
GUID = "4ae9fd46-338a-459c-8186-07f910774cb8"
HelpInfoUri = "https://go.microsoft.com/fwlink/?linkid=855962"
ModuleVersion = "1.2.4"
PowerShellVersion = "3.0"
ClrVersion = "4.0"
RootModule = "PackageManagement.psm1"
CmdletsToExport = @(
'Find-Package',
'Get-Package',
'Get-PackageProvider',
'Get-PackageSource',
'Install-Package',
'Import-PackageProvider'
'Find-PackageProvider'
'Install-PackageProvider'
'Register-PackageSource',
'Set-PackageSource',
'Unregister-PackageSource',
'Uninstall-Package'
'Save-Package'
FormatsToProcess = @('PackageManagement.format.ps1xml')
PrivateData = @{
PSData = @{
ProjectUri = 'https://oneget.org'
Prior to PowerShell 7, one would have to have custom code to load the appropriate
native dll so that
the managed library can find it correctly.
With PowerShell 7, native binaries to load are searched in sub-folders within the
managed library's
location following a subset of the .NET RID Catalog notation.
managed.dll folder
| |--- native.dll
| |--- native.dll
| |--- native.dll
| |--- native.dll
| |--- native.so
| |--- native.so
| |--- native.so
| |--- native.so
| |--- native.dylib
I recently had an idea for module that I wanted to implement as a binary module. I have
yet to
create one using the PowerShell Standard Library so this felt like a good
opportunity. I used
the Creating a cross-platform binary module guide to create this
module without any
roadblocks. We're going to walk that same process and I'll add a
little extra commentary along the
way.
7 Note
For example, we have a critical process that does a lot of work with JSON and
hashtables. We
optimized the PowerShell as much as we could but the process still takes
12 minutes to complete. The
module already contained a lot of C# style PowerShell. This
makes conversion to a binary module
clean and simple. By converting to a binary
module, we reduced the process time from over 12 minutes
to under four minutes.
Hybrid modules
You can mix binary cmdlets with PowerShell advanced functions. Everything you know
about script
modules applies the same way. The empty psm1 file is included so you can
add other PowerShell
functions later.
Almost all of the compiled cmdlets that I have created started out as PowerShell
functions first.
All of our binary modules are really hybrid modules.
Build scripts
I kept the build script simple here. I generally use a large Invoke-Build script as part of
my
CI/CD pipeline. It does more magic like running Pester tests, running
PSScriptAnalyzer, managing
versioning, and publishing to the PSGallery. Once I started
using a build script for my modules, I
was able to find lots of things to add to it.
MyModule
├───src
├───Output
│ └───MyModule
├───MyModule
│ ├───Data
│ ├───Private
│ └───Public
└───Tests
Getting Started
First I need to create the folder and create the git repo. I'm using $module as a
placeholder for
the module name. This should make it easier for you to reuse these
examples if needed.
PowerShell
$module = 'MyModule'
Set-Location $module
git init
PowerShell
First thing we want to do is check the version of the dotnet core SDK that we have
installed.
I'm using 2.1.4, but you should have 2.0.0 or newer before continuing.
PowerShell
2.1.4
PowerShell
Set-Location 'src'
PowerShell
This created the library project in a subfolder but I don't want that extra level of nesting.
I'm
going to move those files up a level.
PowerShell
Move-Item -Path .\$module\* -Destination .\
Set the .NET core SDK version for the project. I have the 2.1 SDK so I'm going to specify
2.1.0 .
Use 2.0.0 if you're using the 2.0 SDK.
PowerShell
Add the PowerShell Standard Library NuGet package to the project. Make sure you
use the
most recent version available for the level of compatibility that you need. I
would default to the
latest version but I don't think this module leverages any features
newer than PowerShell 3.0.
PowerShell
PowerShell
PS> Get-ChildItem
Directory: \MyModule\src
C#
using System;
using System.Management.Automation;
namespace MyModule
[Parameter(Position=0)]
this.WriteObject(this.InputObject);
base.EndProcessing();
PowerShell
PowerShell
Build succeeded.
0 Warning(s)
0 Error(s)
We can call Import-Module on the new dll to load our new cmdlet.
PowerShell
If the import fails on your system, try updating .NET to 4.7.1 or newer. The
Creating a
cross-platform binary module guide goes into more details on .NET support and
compatibility for older versions of .NET.
Module manifest
It's cool that we can import the dll and have a working module. I like to keep going with
it and
create a module manifest. We need the manifest if we want to publish to the
PSGallery later.
From the root of our project, we can run this command to create the module manifest
that we need.
PowerShell
$manifestSplat = @{
Path = ".\$module\$module.psd1"
NestedModules = @('bin\MyModule.dll')
RootModule = "$module.psm1"
FunctionsToExport = @('Resolve-MyCmdlet')
New-ModuleManifest @manifestSplat
I'm also going to create an empty root module for future PowerShell functions.
PowerShell
This allows me to mix both normal PowerShell functions and binary cmdlets in the same
project.
PowerShell
$module = 'MyModule'
Push-Location $PSScriptRoot
Import-Module "$PSScriptRoot\Output\$module\$module.psd1"
Invoke-Pester "$PSScriptRoot\Tests"
These commands build our DLL and place it into our output\$module\bin folder. It then
copies the
other module files into place.
Output
└───MyModule
├───MyModule.psd1
├───MyModule.psm1
└───bin
├───MyModule.deps.json
├───MyModule.dll
└───MyModule.pdb
At this point, we can import our module with the psd1 file.
PowerShell
Import-Module ".\Output\$module\$module.psd1"
From here, we can drop the .\Output\$module folder into our $env:PSModulePath
directory and it
autoloads our command whenever we need it.
All the steps that I outlined above are still valid, but this template cuts many of them
out. It's
still a fairly new template that's still getting some polish placed on it. Expect it to
keep getting
better from here.
This is how you use install and use the PSModule template.
PowerShell
dotnet build
Import-Module "bin\Debug\netstandard2.0\$module.dll"
Get-Module $module
This minimally-viable template takes care of adding the .NET SDK, PowerShell Standard
Library, and
creates an example class in the project. You can build it and run it right
away.
Important details
Before we end this article, here are a few other details worth mentioning.
Unloading DLLs
Once a binary module is loaded, you can't really unload it. The DLL file is locked until
you unload
it. This can be annoying when developing because every time you make a
change and want to build it,
the file is often locked. The only reliable way to resolve this
is to close the PowerShell session
that loaded the DLL.
You can set up a local PSGallery and publish to that as part of your build. Then do your
local
install from that PSGallery. This sounds like a lot of work, but this can be as simple
as starting a
docker container. I cover a way to do that in my post on
Using a NuGet
server for a PSRepository .
Final thoughts
I didn't touch on the C# syntax for creating a cmdlet, but there is plenty of
documentation on it
in the Windows PowerShell SDK. It's definitely something worth
experimenting with as a
stepping stone into more serious C#.
Choosing the right PowerShell NuGet
package for your .NET project
Article • 11/17/2022
Alongside the pwsh executable packages published with each PowerShell release, the
PowerShell team
also maintains several packages available on NuGet . These packages
allow targeting PowerShell
as an API platform in .NET.
As a .NET application that provides APIs and expects to load .NET libraries implementing
its own
(binary modules), it's essential that PowerShell be available in the form of a
NuGet package.
Currently there are several NuGet packages that provide some representation of the
PowerShell API
surface area. Which package to use with a particular project hasn't
always been made clear. This
article sheds some light on a few common scenarios for
PowerShell-targeting .NET projects and how to
choose the right NuGet package to
target for your PowerShell-oriented .NET project.
Hosting vs referencing
Some .NET projects seek to write code to be loaded into a pre-existing PowerShell
runtime (such as
pwsh , powershell.exe , the PowerShell Integrated Console or the ISE),
while others want to run
PowerShell in their own applications.
We use the term publish in this article to refer to running dotnet publish , which
places a
.NET library into a directory with all of its dependencies, ready for
deployment to a particular
runtime.
In order to prevent publishing project dependencies that are just being used as
compilation
reference targets, it is recommended to set the PrivateAssets attribute:
XML
If you forget to do this and use a reference assembly as your target, you may see issues
related to
using the reference assembly's default implementation instead of the actual
implementation. This may
take the form of a NullReferenceException , since reference
assemblies often mock the
implementation API by simply returning null .
PowerShell binary modules are .NET libraries loaded by PowerShell that must
implement PowerShell
APIs like the PSCmdlet or CmdletProvider types in order to
expose cmdlets or providers
respectively. Because they are loaded in, modules
seek to compile against references to PowerShell
without publishing it in their
build. It's also common for modules to want to support multiple
PowerShell
versions and platforms, ideally with a minimum of overhead of disk space,
complexity,
or repeated implementation. See about_Modules for more information
about modules.
7 Note
The PowerShell NuGet package is not a .NET library package at all, but instead
provides the
PowerShell dotnet global tool implementation. This should not be
used by any projects, since it
only provides an executable.
PowerShellStandard.Library
The PowerShell Standard library is a reference assembly that captures the intersection of
the APIs
of PowerShell versions 7, 6 and 5.1. This provides a compile-time-checked API
surface to compile
.NET code against, allowing .NET projects to target PowerShell
versions 7, 6 and 5.1 without risking
calling an API that won't be there.
PowerShell Standard is intended for writing PowerShell modules, or other code only
intended to be
run after loading it into a PowerShell process. Because it is a reference
assembly, PowerShell
Standard contains no implementation itself, so provides no
functionality for standalone
applications.
The PowerShell loading the module or library must be running a minimum of .NET
4.6.1; .NET 4.6 and
.NET 4.5.2 do not support .NET Standard. Note that a newer
Windows PowerShell version does not
mean a newer .NET Framework version;
Windows PowerShell 5.1 may run on .NET 4.5.2.
In order to work with a PowerShell running .NET Framework 4.7.1 or below, the
.NET 4.6.1
NETStandard.Library implementation is required to provide the
netstandard.dll and other shim
assemblies in older .NET Framework versions.
PowerShell 6+ provides its own shim assemblies for type forwarding from .NET
Framework 4.6.1 (and
above) to .NET Core. This means that as long as a module uses
only APIs that exist in .NET Core,
PowerShell 6+ can load and run it when it has been
built for .NET Framework 4.6.1 (the net461
runtime target).
This means that binary modules using PowerShell Standard to target multiple
PowerShell versions with
a single published DLL have two options:
1. Publishing an assembly built for the net461 target runtime. This involves:
2. Publishing an assembly build for the netstandard2.0 target runtime. This requires:
Publishing the project for the netstandard2.0 runtime
Taking the net461 dependencies of NETStandard.Library and copying them
into the project
assembly's publish location so that the assembly is type-
forwarded corrected in .NET Framework.
To build PowerShell modules or libraries targeting older .NET Framework versions, it may
be
preferable to target multiple .NET runtimes. This will publish an assembly for each
target runtime,
and the correct assembly will need to be loaded at module load time
(for example with a small psm1
as the root module).
To test APIs built against PowerShell Standard in .NET, you should add
Microsoft.Powershell.SDK as
a testing dependency with .NET Core (with the version set
For more information on PowerShell Standard and using it to write a binary module that
works in
multiple PowerShell versions, see this blog post . Also see the
PowerShell
Standard repository on GitHub.
Microsoft.PowerShell.SDK
Microsoft.PowerShell.SDK is a meta-package that pulls together all of the components
of the
PowerShell SDK into a single NuGet package. A self-contained .NET application
can use
Microsoft.PowerShell.SDK to run arbitrary PowerShell functionality without
depending on any external
PowerShell installations or libraries.
7 Note
The PowerShell SDK just refers to all the component packages that make up
PowerShell, and which
can be used for .NET development with PowerShell.
7 Note
The PowerShell SDK is only available for PowerShell versions 6 and up. To provide
equivalent
functionality with Windows PowerShell, use the Windows PowerShell
reference assemblies described
below.
System.Management.Automation
The System.Management.Automation package is the heart of the PowerShell SDK. It exists
on NuGet,
primarily, as an asset for Microsoft.Powershell.SDK to pull in. However, it can
also be used
directly as a package for smaller hosting scenarios and version-targeting
modules.
Specifically, the System.Management.Automation package may be a preferable provider of
PowerShell
functionality when:
You wish to target APIs that are only present within a specific PowerShell version
You won't be depending on types occurring outside the
System.Management.Automation assembly (for
example, types exported by cmdlets
in Microsoft.PowerShell.* modules).
Instead, the Windows PowerShell reference assemblies provide both reference targets
and a way to
rehost Windows PowerShell, acting the same as the PowerShell SDK does
for versions 6 and up.
PowerShell 5.1
PowerShell 4
PowerShell 3
Information on how to use the Windows PowerShell reference assemblies can be found
in the
Windows PowerShell SDK.
PSReadLine
PSReadLine , the PowerShell module that provides much of PowerShell's rich console
experience,
targets PowerShell Standard as a dependency rather than a specific
PowerShell version, and targets
the net461 .NET runtime in its csproj .
PowerShell 6+ supplies its own shim assemblies that allow a DLL targeting the net461
runtime to
"just work" when loaded in (by redirecting binding to .NET Framework's
mscorlib.dll to the
relevant .NET Core assembly).
This simplifies PSReadLine's module layout and delivery significantly, since PowerShell
Standard
ensures the only APIs used will be present in both PowerShell 5.1 and
PowerShell 6+, while also
allowing the module to ship with only a single assembly.
The .NET 4.6.1 target does mean that Windows PowerShell running on
.NET 4.5.2 and
.NET 4.6 is not supported though.
As with PSReadLine, PSES cannot support .NET 4.6 and below, but it performs a check
at runtime
before calling any of the APIs that could cause a crash on the lower .NET
Framework runtimes.
PSScriptAnalyzer
PSScriptAnalyzer , the linter for PowerShell, must target syntactic elements only
introduced in
certain versions of PowerShell. Because recognition of these syntactic
elements is accomplished by
implementing an AstVisitor2, it's not possible to use
PowerShellStandard and also implement
AST visitor methods for newer PowerShell
syntaxes.
Summary
In this article, we've listed and discussed the NuGet packages available to target when
implementing
a .NET project that uses PowerShell, and the reasons you might have for
using one over another.
When writing a binary PowerShell module in C#, it's natural to take dependencies on
other packages
or libraries to provide functionality. Taking dependencies on other
libraries is desirable for code
reuse. PowerShell always loads assemblies into the same
context. This presents issues when a
module's dependencies conflict with already-
loaded DLLs and may prevent using two otherwise
unrelated modules in the same
PowerShell session.
If you've had this problem, you've seen an error message like this:
This article looks at some ways dependency conflicts occur in PowerShell and ways to
mitigate
dependency conflict issues. Even if you're not a module author, there are some
tricks in here that
might help you with dependency conflicts occurring in modules that
you use.
Conflict issues are compounded by the fact that a project almost never deliberately or
directly
depends on two versions of the same dependency. Instead, the project has two
or more dependencies
that each require a different version of the same dependency.
For example, say your .NET application, DuckBuilder , brings in two dependencies, to
perform parts
of its functionality and looks like this:
Because Contoso.ZipTools and Fabrikam.FileHelpers both depend on different versions
of
Newtonsoft.Json, there may be a dependency conflict depending on how each
dependency is loaded.
example PowerShell.
7 Note
Because the module depends on a newer version of the assembly, it won't accept the
version that
PowerShell already has loaded. But because PowerShell has already loaded
a version of the assembly,
the module can't load its own version using the conventional
load mechanism.
Conflicting with another module's dependencies
Another common scenario in PowerShell is that a module is loaded that depends on one
version of an
assembly, and then another module is loaded later that depends on a
different version of that
assembly.
Imagine these modules load their dependencies by placing the dependency assemblies
in the same
directory as the root module assembly. This allows .NET to implicitly load
them by name. If we're
running PowerShell 7.0 (on top of .NET Core 3.1), we can load
and run FictionalTools , then load
and run FilesystemManager without issue. However,
in a new session, if we load and run
FilesystemManager , then load FictionalTools , we
get a FileLoadException from the
FictionalTools command because it requires a
newer version of Microsoft.Extensions.Logging than
the one loaded. FictionalTools
can't load the version needed because an assembly of the same name
has already been
loaded.
dependencies of
the loaded DLL. This method may not resolve dependencies the
way we want.
Assembly.LoadFile() , a basic loading API intended to load only the assembly
.NET Core (and .NET 5+) has replaced this complexity with a simpler model:
No Global Assembly Cache. Applications bring all their own dependencies. This
removes an external
factor for dependency resolution in applications, making
dependency resolution more reproducible.
PowerShell, as the plugin host,
complicates this slightly for modules. Its dependencies in
$PSHOME are shared with
all modules.
Only one Application Domain, and no ability to create new ones. The Application
Domain concept
is maintained in .NET to be the global state of the .NET process.
A new, extensible Assembly Load Context (ALC) model. Assembly resolution can be
namespaced by putting it
in a new ALC. .NET processes begin with a single default
ALC into which all assemblies are
loaded (except for those loaded with
Assembly.LoadFile(string) and Assembly.Load(byte[]) ). But
the process can
create and define its own custom ALCs with its own loading logic. When an
assembly
is loaded, the first ALC it's loaded into is responsible for resolving its
dependencies. This
creates opportunities to implement powerful .NET plugin
loading mechanisms.
In both implementations, assemblies are loaded lazily. This means that they're loaded
when a method
requiring their type is run for the first time.
For example, here are two versions of the same code that load a dependency at
different times.
The first always loads its dependency when Program.GetRange() is called, because the
dependency
reference is lexically present within the method:
C#
using Dependency.Library;
if (i >= 20)
DependencyApi.Use();
list.Add(i);
return list;
The second loads its dependency only if the limit parameter is 20 or more, because of
the internal
indirection through a method:
C#
using Dependency.Library;
if (i >= 20)
UseDependencyApi();
list.Add(i);
return list;
DependencyApi.Use();
This is a good practice since it minimizes the memory and filesystem I/O and uses the
resources more
efficiently. The unfortunate a side effect of this is that we won't know
that the assembly fails to
load until we reach the code path that tries to load the
assembly.
It can also create a timing condition for assembly load conflicts. If two parts of the same
program
try to load different versions of the same assembly, the version loaded
depends on which code path
is run first.
For PowerShell, this means that the following factors can affect an assembly load
conflict:
Your conflict is with a direct dependency of your module and you control the
version.
Your conflict is with an indirect dependency, but you can configure your direct
dependencies to
use a workable indirect dependency version.
You know the conflicting version and can rely on it not changing.
For example, PowerShell 6.2.6 and PowerShell 7.0.2 both currently use Newtonsoft.Json
version
12.0.3. To create a module targeting Windows PowerShell, PowerShell 6, and
PowerShell 7, you would
target Newtonsoft.Json 12.0.3 as a dependency and include it
in your built module. When the
module is loaded in PowerShell 6 or 7, PowerShell's own
Newtonsoft.Json assembly is already
loaded. Since it's the version required for your
module, resolution succeeds. In Windows PowerShell,
the assembly isn't already present
in PowerShell, so it's loaded from your module folder instead.
The conflict is with an indirect dependency, and none of your dependencies can be
configured to
use a common version.
The other dependency version is likely to change often, so settling on a common
version is only a
short-term fix.
Dependency conflicts occur because two versions of the same assembly are loaded into
the same .NET
process. A simple solution is to load them into different processes, as
long as you can still
use the functionality from both together.
To run a PowerShell command out of the current process, start a new PowerShell
process directly
with the command call:
PowerShell
pwsh -c 'Invoke-ConflictingCommand'
The main limitation here is that restructuring the result can be trickier or more
error prone than
other options.
PowerShell
In this case, you just need to be sure that any variables and state are passed in
correctly.
The job system can also be slightly cumbersome when running small commands.
PowerShell remoting
When it's available, PowerShell remoting can be a useful way to run commands out
of process. With
remoting, you can create a fresh PSSession in a new process, call
its commands over PowerShell
remoting, then use the results locally with the other
modules containing the conflicting
dependencies.
PowerShell
$s = New-PSSession
Invoke-ConflictingCommand
PowerShell
Be aware that modules may not be compatible with or may work differently with
Windows PowerShell.
When out-of-process invocation should not be used
As a module author, out-of-process command invocation is difficult to bake into a
module and may
have edge cases that cause issues. In particular, remoting and jobs
may not be available in all
environments where your module needs to work. However,
the general principle of moving the
implementation out of process and allowing the
PowerShell module to be a thinner client, may still
be applicable.
As a module user, there are cases where out-of-process invocation won't work:
When PowerShell remoting is unavailable because you don't have privileges to use
it or it
is not enabled.
When a particular .NET type is needed from output as input to a method or
another command.
Commands running over PowerShell remoting emit
deserialized objects rather than strongly-typed
.NET objects. This means that
method calls and strongly typed APIs don't work with the output of
commands
imported over remoting.
Within .NET, they offer the most robust solution to the problem of loading conflicting
versions of
an assembly. However, custom ALCs are not available in .NET Framework.
This means that this solution
only works in PowerShell 6 and above.
Currently, the best example of using an ALC for dependency isolation in PowerShell is in
PowerShell
Editor Services, the language server for the PowerShell extension for Visual
Studio Code. An
ALC is used to prevent PowerShell Editor Services' own dependencies
from clashing with those
in PowerShell modules.
+ src/
+ TestAlcModuleCommand.cs
+ AlcModule.csproj
C#
using Shared.Dependency;
namespace AlcModule
[Cmdlet(VerbsDiagnostic.Test, "AlcModule")]
Dependency.Use();
PowerShell
@{
Author = 'Me'
ModuleVersion = '0.0.1'
RootModule = 'AlcModule.dll'
CmdletsToExport = @('Test-AlcModule')
PowerShellVersion = '7.0'
XML
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
</Project>
When we build this module, the generated output has the following layout:
AlcModule/
+ AlcModule.psd1
+ AlcModule.dll
+ Shared.Dependency.dll
Module dependencies are only loaded into our custom ALC, and not into
PowerShell's ALC, so
there can be no conflict. Moreover, as we add more
dependencies to our project, we don't want to
continuously add more code to
keep loading working. Instead, we want reusable, generic dependency
resolution
logic.
Loading the module still works as normal in PowerShell. Cmdlets and other types
that the
PowerShell module system needs are defined within PowerShell's own
ALC.
To mediate these two requirements, we must break up our module into two assemblies:
Using this bridge concept, our new assembly situation looks like this:
To make sure the default ALC's dependency probing logic doesn't resolve the
dependencies to be
loaded into the custom ALC, we need to separate these two parts of
the module in different
directories. The new module layout has the following structure:
AlcModule/
AlcModule.Cmdlets.dll
AlcModule.psd1
Dependencies/
| + AlcModule.Engine.dll
| + Shared.Dependency.dll
To see how the implementation changes, we'll start with the implementation of
AlcModule.Engine.dll :
C#
using Shared.Dependency;
namespace AlcModule.Engine
Dependency.Use();
This is a simple container for the dependency, Shared.Dependency.dll , but you should
think of it
as the .NET API for your functionality that the cmdlets in the other assembly
wrap for PowerShell.
C#
using AlcModule.Engine;
namespace AlcModule.Cmdlets
[Cmdlet(VerbsDiagnostic.Test, "AlcModule")]
AlcEngine.Use();
WriteObject("done!");
}
dependencies we want
to hide.
our module's
Dependencies directory:
C#
namespace AlcModule.Cmdlets
_dependencyDirPath = dependencyDirPath;
_dependencyDirPath,
$"{assemblyName.Name}.dll");
if (File.Exists(assemblyPath))
return LoadFromAssemblyPath(assemblyPath);
return null;
Then we need to hook up our custom ALC to the default ALC's Resolving event, which is
the ALC
version of the AssemblyResolve event on Application Domains. This event is
fired to find
AlcModule.Engine.dll when EndProcessing() is called.
C#
namespace AlcModule.Cmdlets
Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"Dependencies"));
new AlcModuleAssemblyLoadContext(s_dependencyDirPath);
AssemblyLoadContext.Default.Resolving += ResolveAlcEngine;
AssemblyLoadContext.Default.Resolving -= ResolveAlcEngine;
//
if (!assemblyToResolve.Name.Equals("AlcModule.Engine"))
return null;
//
return s_dependencyAlc.LoadFromAssemblyName(assemblyToResolve);
With the new implementation, take a look at the sequence of calls that occurs when the
module is loaded and Test-AlcModule is run:
Some points of interest are:
The IModuleAssemblyInitializer is run first when the module loads and sets the
Resolving
event.
We don't load the dependencies until Test-AlcModule is run and its
EndProcessing() method
is called.
Assembling the implementation, our new source code layout looks like this:
+ AlcModule.psd1
+ src/
+ AlcModule.Cmdlets/
| + AlcModule.Cmdlets.csproj
| + TestAlcModuleCommand.cs
| + AlcModuleAssemblyLoadContext.cs
| + AlcModuleInitializer.cs
+ AlcModule.Engine/
| + AlcModule.Engine.csproj
| + AlcEngine.cs
XML
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AlcModule.Engine\AlcModule.Engine.csproj"
/>
</ItemGroup>
</Project>
XML
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
</Project>
Build AlcModule.Engine
Build AlcModule.Cmdlets
Copy everything from AlcModule.Engine into the Dependencies directory, and
remember what we
copied
Copy everything from AlcModule.Cmdlets that wasn't in AlcModule.Engine into the
base module
directory
Since the module layout here is so crucial to dependency separation, here's a build
script to use
from the source root:
PowerShell
param(
[ValidateSet('Debug', 'Release')]
[string]
$Configuration = 'Debug'
$mod = "AlcModule"
$netcore = "netcoreapp3.1"
$src = "$PSScriptRoot/src"
$engineSrc = "$src/$mod.Engine"
$cmdletsSrc = "$src/$mod.Cmdlets"
$outDir = "$PSScriptRoot/out/$mod"
$outDeps = "$outDir/Dependencies"
# Build AlcModule.Engine
Push-Location $engineSrc
Pop-Location
# Build AlcModule.Cmdlets
Push-Location $cmdletsSrc
Pop-Location
# Copy manifest
$deps = [System.Collections.Generic.Hashtable[string]]::new()
# Now copy each Cmdlets asset, not taking any found in Engine
For a more detailed example, go to this GitHub repository . This example demonstrates
how to
migrate a module to use an ALC, while keeping that module working in .NET
Framework. It also shows
how to use .NET Standard and PowerShell Standard to simplify
the core implementation.
This solution is also used by the Bicep PowerShell module , and the blog post
Resolving PowerShell Module Conflicts is another good read about this solution.
For a new module, this would add additional complexity to the design and
implementation
For an existing module, this would require significant refactoring
) Important
If you're interested in trying to use a custom application domain, the following links
might help:
These solutions have the common theme that they are changes to deployment
configurations for an
environment where you control the application and possibly the
entire machine. These solutions are
oriented toward scenarios like web servers and
other applications deployed to server environments,
where the environment is intended
to host the application and is free to be configured by the
deploying user. They also
tend to be very much .NET Framework oriented, meaning they don't work with
PowerShell 6 or higher.
If you know that your module is only used in Windows PowerShell 5.1 environments that
you have total
control over, some of these may be options. In general however,
modules shouldn't modify global
machine state like this. It can break configurations
that cause problems in powershell.exe ,
other modules, or other dependent applications
that cause your module to fail in unexpected ways.
The GAC only applies to .NET Framework, so this does not help in PowerShell 6 and
above.
Installing assemblies to the GAC is a modification of global machine state and may
cause
side-effects in other applications or to other modules. It may also be difficult
to do correctly,
even when your module has the required access privileges. Getting
it wrong could cause serious,
machine-wide issues in other .NET applications.
Further reading
There's plenty more to read on .NET assembly version dependency conflicts. Here are
some nice
jumping off points:
System requirements
To create and use a plugin predictor, you must be using the following versions of
software:
PowerShell 7.2 (or higher) - provides the APIs necessary for creating a command
predictor
PSReadLine 2.2.2 (or higher) - allows you to configure PSReadLine to use the
plugin
Overview of a predictor
A predictor is a PowerShell binary module. The module must implement the
System.Management.Automation.Subsystem.Prediction.ICommandPredictor interface. This
interface
declares the methods used to query for prediction results and provide
feedback.
PowerShell
XML
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.PowerShell.SDK"
Version="7.2.0" />
</ItemGroup>
</Project>
3. Delete the default Class1.cs file created by dotnet and copy the following code
to a
SamplePredictorClass.cs file in your project folder.
C#
using System;
using System.Collections.Generic;
using System.Threading;
using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Prediction;
namespace PowerShell.Sample
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
if (string.IsNullOrWhiteSpace(input))
return default;
});
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// </param>
/// <summary>
/// <summary>
/// The predictor can start processing early as needed with the
latest history.
/// </summary>
/// <summary>
/// </summary>
#endregion;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor,
predictor);
/// <summary>
/// </summary>
SubsystemManager.UnregisterSubsystem(SubsystemKind.CommandPredictor,
new Guid(Identifier));
The following example code returns the string "HELLO WORLD" for the prediction
result for all
user input. Since the sample predictor doesn't process any feedback,
the code doesn't implement
the feedback methods from the interface. Change the
prediction and feedback code to meet the
needs of your predictor.
7 Note
4. Run dotnet build to produce the assembly. You can find the compiled assembly in
the
bin/Debug/net6.0 location of your project folder.
PowerShell
Import-Module .\bin\Debug\net6.0\SamplePredictor.dll
With the assembly is loaded in the session, you see the text "HELLO WORLD" appear as
you type in the
terminal. You can press F2 to switch between the Inline view and the
List view.
PowerShell
Output
7 Note
The legacy PowerShell SDK documentation covers the details of creating help for
PowerShell
cmdlets packaged into modules. However, PowerShell does not provide any
tools for creating the
XML-based help. The SDK documentation explains the structure of
MAML help, but leaves you the
task of creating the complex, and deeply nested, MAML
content by hand.
What is PlatyPS?
PlatyPS is an open-source tool that started as a hackathon project to make the
creation and maintenance of MAML easier. PlatyPS documents the syntax of parameter
sets and the
individual parameters for each cmdlet in your module. PlatyPS creates
structured Markdown
files that contain the syntax information. It can't create
descriptions or provide examples.
PlatyPS creates placeholders for you to fill in descriptions and examples. After adding
the required
information, PlatyPS compiles the Markdown files into MAML files.
PowerShell's help system also
allows for plain-text conceptual help files (about topics).
PlatyPS has a cmdlet to create a
structured Markdown template for a new about file, but
these about_*.help.txt files must be
maintained manually.
You can include the MAML and Text help files with your module. You can also use
PlatyPS to compile
the help files into a CAB package that can be hosted for updateable
help.
PowerShell
Install-Module platyps -Force
Import-Module platyps
The following flowchart outlines the process for creating or updating PowerShell
reference content.
PowerShell
2. Use PlatyPS to generate Markdown files for your module page and all associated
cmdlets within the
module. Repeat this step for each module you need to
document.
PowerShell
$OutputFolder = <output path>
$parameters = @{
Module = <ModuleName>
OutputFolder = $OutputFolder
AlphabeticParamsOrder = $true
WithModulePage = $true
ExcludeDontShow = $true
Encoding = [System.Text.Encoding]::UTF8
New-MarkdownHelp @parameters
If the output folder does not exist, New-MarkdownHelp creates it. In this example,
New-MarkdownHelp creates a Markdown file for each cmdlet in the module. It also
creates the
module page in a file named <ModuleName>.md . This module page
contains a list of the cmdlets
contained in the module and placeholders for the
Synopsis description. The metadata in the
module page comes from the module
manifest and is used by PlatyPS to create the HelpInfo XML file
(as explained
below).
1. Import your new module into the session. Repeat this step for each module you
need to document.
PowerShell
2. Use PlatyPS to update Markdown files for your module landing page and all
associated cmdlets
within the module. Repeat this step for each module you need
to document.
PowerShell
$parameters = @{
AlphabeticParamsOrder = $true
UpdateInputOutput = $true
ExcludeDontShow = $true
Encoding = [System.Text.Encoding]::UTF8
Update-MarkdownHelpModule @parameters
specified folder.
It does not update the about_*.md files. The module file
( ModuleName.md ) receives any new
Synopsis text that has been added to the cmdlet
files. Updates to cmdlet files include the
following change:
For detailed information about writing PowerShell content, see the following articles:
7 Note
PlatyPS has a specific schema that is uses for cmdlet reference. That schema only
allows certain
Markdown blocks in specific sections of the document. If you put
content in the wrong location,
the PlatyPS build step fails. For more information,
see the schema documentation in the
PlatyPS repository. For a complete
example of well-formed cmdlet reference, see
Get-Item.
After providing the required content for each of your cmdlets, you need to make sure
that you update
the module landing page. Verify your module has the correct Module
Guid and Download Help Link
values in the YAML metadata of the <module-name>.md file.
PowerShell
Now that you have entered all the content, you can create the MAML help files that are
displayed by
Get-Help in the PowerShell console.
PowerShell
New-ExternalHelp converts all cmdlet Markdown files into one (or more) MAML files.
U Caution
PlatyPS does a poor job converting the about_*.md files to plain text. You must use
very simple
Markdown to get acceptable results. You may want to maintain the files
in plain-text
about_topic_name.help.txt format, rather than allowing PlatyPS to
convert them.
Once this step is complete, you will see *-help.xml and about_*.help.txt files in the
target
output folder.
PowerShell
The cmdlet reads the compiled MAML file and outputs the content in the same format
you would receive
from Get-Help . This allows you to inspect the results to verify that the
Markdown files compiled
correctly and produce the desired results. If you find an error,
re-edit the Markdown files and
recompile the MAML.
The HelpInfoURI is a URL that points to location where your help files are hosted on the
internet. This value is configured in the module manifest. Update-Help reads the module
manifest
to get this URL and download the updateable help content. This URL should
only point to the folder
location and not to individual files. Update-Help constructs the
filenames to download based on
other information from the module manifest and the
HelpInfo XML file.
) Important
The New-ExternalHelp cmdlet creates the HelpInfo XML file in the output folder. The
HelpInfo XML
file is built using YAML metadata contained in the module Markdown files
( ModuleName.md ).
The New-ExternalHelpCab cmdlet creates ZIP and CAB files containing the MAML and
about_*.help.txt files you compiled. CAB files are compatible with all versions of
PowerShell.
PowerShell 6 and higher can use ZIP files.
PowerShell
$helpCabParameters = @{
CabFilesFolder = $MamlOutputFolder
LandingPagePath = $LandingPage
OutputFolder = $CabOutputFolder
New-ExternalHelpCab @helpCabParameters
After creating the ZIP and CAB files, upload the ZIP, CAB, and HelpInfo XML files to your
HTTP file
server. Put the files in the location indicated by the HelpInfoURI.
Known issues
PlatyPS is very sensitive to the schema for the structure of the Markdown files it
creates
and compiles. It is very easy write valid Markdown that violates this schema. For
more information,
see the PowerShell style guide and Editing reference articles.
Windows PowerShell Language
Specification 3.0
Article • 09/22/2022
The Windows PowerShell Language Specification 3.0 was published in December 2012
and is based on
PowerShell 3.0. The specification document is available as a Microsoft
Word document from the
Microsoft Download Center at:
https://www.microsoft.com/download/details.aspx?id=36389
That Word document has been converted for presentation here on Microsoft Learn.
During conversion,
some editorial changes have been made to accommodate
formatting for the Docs platform. Some typos
and minor errors have been corrected.
) Important
The contents of this documentation may not reflect the current state of PowerShell
in its current
version. There is no plan to update this documentation to reflect the
current state. This
documentation is presented here for historical reference.
1. Introduction
PowerShell is a command-line shell and scripting language, designed especially for
system
administrators.
Most shells operate by executing a command or utility in a new process, and presenting
the results
to the user as text. These shells also have commands that are built into the
shell and run in the
shell process. Because there are few built-in commands, many
utilities have been created to
supplement them. PowerShell is very different. Instead of
processing text, the shell processes
objects. PowerShell also includes a large set of built-
in commands with each having a consistent
interface and these can work with user-
written commands.
An object is a data entity that has properties (i.e., characteristics) and methods (i.e.,
actions that can be performed on the object). All objects of the same type have the
same base set of
properties and methods, but each instance of an object can have
different property values.
A major advantage of using objects is that it is much easier to pipeline commands; that
is, to
write the output of one command to another command as input. (In a traditional
command-line
environment, the text output from one command needs to be
manipulated to meet the input format of
another.)
PowerShell includes a very rich scripting language that supports constructs for looping,
conditions,
flow-control, and variable assignment. This language has syntax features and
keywords similar to
those used in the C# programming language (§C.).
There are four kinds of commands in PowerShell: scripts, functions and methods,
cmdlets, and native
commands.
Each time the PowerShell runtime environment begins execution, it begins what is called
a session.
Commands then execute within the context of that session.
This specification defines the PowerShell language, the built-in cmdlets, and the use of
objects via
the pipeline.
Unlike most shells, which accept and return text, Windows PowerShell is built on top of
the .NET
Framework common language runtime (CLR) and the .NET Framework, and
accepts and returns .NET
Framework objects.
2. Lexical Structure
Article • 07/29/2021
2.1 Grammars
This specification shows the syntax of the PowerShell language using two grammars.
The lexical
grammar (§B.1) shows how Unicode characters are combined to form line
terminators, comments,
white space, and tokens. The syntactic grammar (§B.2) shows
how the tokens resulting from the
lexical grammar are combined to form PowerShell
scripts.
Any use of the characters 'a' through 'z' in the grammars is case insensitive. This means
that
letter case in variables, aliases, function names, keywords, statements, and
operators is ignored.
However, throughout this specification, such names are written in
lowercase, except for some
automatic and preference variables.
2.2.1 Scripts
Syntax:
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
Syntax
input:
input-elements~opt~ signature-block~opt~
input-elements:
input-element
input-elements input-element
input-element:
whitespace
comment
token
signature-block:
signature-begin:
signature:
signature-end:
Description:
The input source stream to a PowerShell translator is the input in a script, which contains
a
sequence of Unicode characters. The lexical processing of this stream involves the
reduction of
those characters into a sequence of tokens, which go on to become the
input of syntactic analysis.
A script is a group of PowerShell commands stored in a script-file. The script itself has no
name,
per se, and takes its name from its source file. The end of that file indicates the
end of the
script.
A script may optionally contain a digital signature. A host environment is not required to
process
any text that follows a signature or anything that looks like a signature. The
creation and use of
digital signatures are not covered by this specification.
Syntax
new-line-character:
new-lines:
new-line-character
new-lines new-line-character
Description:
The presence of new-line-characters in the input source stream divides it into lines that
can be
used for such things as error reporting and the detection of the end of a single-
line comment.
2.2.3 Comments
Syntax:
Syntax
comment:
single-line-comment
requires-comment
delimited-comment
single-line-comment:
# input-characters~opt~
input-characters:
input-character
input-characters input-character
input-character:
requires-comment:
dash:
- (U+002D)
dashdash:
dash dash
delimited-comment:
delimited-comment-text:
delimited-comment-section
delimited-comment-text delimited-comment-section
delimited-comment-section:
>
hashes~opt~ not-greater-than-or-hash
hashes:
hashes #
not-greater-than-or-hash:
Description:
A delimited-comment begins with the character pair <# and ends with the character pair
#> .
It can occur as part of a source line, as a whole source line, or it can span any
number of source
lines.
The lexical grammar implies that comments cannot occur inside tokens.
(See §A for information about creating script files that contain special-valued comments
that are
used to generate documentation from script files.)
A requires-comment specifies the criteria that have to be met for its containing script to
be
allowed to run. The primary criterion is the version of PowerShell being used to run
the script. The
minimum version requirement is specified as follows:
Where N is the (required) major version and n is the (optional) minor version.
Syntax
Syntax
whitespace:
Description:
Except for the fact that white space may act as a separator for tokens, it is ignored.
PowerShell
In this example, the backtick indicates the source line is continued. The following
expression is
equivalent to $number = 10 + 20 - 50 .
PowerShell
$number = 10 `
+ 20 `
- 50
-20
2.3 Tokens
Syntax:
Syntax
token:
keyword
variable
command
command-parameter
command-argument-token
integer-literal
real-literal
string-literal
type-literal
operator-or-punctuator
Description:
2.3.1 Keywords
Syntax:
Syntax
keyword: one of
Description:
The keywords class , define , from , using , and var are reserved for future use.
7 Note
Editor's Note: The class and using keywords were introduced in PowerShell 5.0.
See
about_Classes and
about_Using.
2.3.2 Variables
Syntax:
Syntax
variable:
$$
$?
$^
$ variable-scope~opt~ variable-characters
@ variable-scope~opt~ variable-characters
braced-variable
braced-variable:
${ variable-scope~opt~ braced-variable-characters }
variable-scope:
global:
local:
private:
script:
using:
workflow:
variable-namespace
variable-namespace:
variable-characters :
variable-characters:
variable-character
variable-characters variable-character
variable-character:
braced-variable-characters:
braced-variable-character
braced-variable-characters braced-variable-character
braced-variable-character:
escaped-character
escaped-character:
Description:
Variables are discussed in detail in (§5). The variable $? is discussed in §2.3.2.2. Scopes
are
discussed in §3.5.
The variables $$ and $^ are reserved for use in an interactive environment, which is
outside the
scope of this specification.
There are two ways of writing a variable name: A braced variable name, which begins
with $ ,
followed by a curly bracket-delimited set of one or more almost-arbitrary
characters; and an
ordinary variable name, which also begins with $ , followed by a set
of one or more characters
from a more restrictive set than a braced variable name
allows. Every ordinary variable name can be
expressed using a corresponding braced
variable name.
PowerShell
$totalCost
$Maximum_Count_26
$végösszeg # Hungarian
$итог # Russian
${Maximum_Count_26}
${E:\\File.txt}
There is no limit on the length of a variable name, all characters in a variable name are
significant, and letter case is not distinct.
PowerShell
PowerShell
Get-Power @values
Get-Power @hash
@args
This is achieved by using @ instead of $ as the first character of the variable being
passed.
This notation can only be used in an argument to a command.
Names are partitioned into various namespaces each of which is stored on a virtual drive
(§3.1). For example, variables are stored on Variable: , environment variables are stored
on
Env: , functions are stored on Function: , and aliases are stored on Alias: . All of
these names
can be accessed as variables using the variable-namespace production
within variable-scope. For
example,
PowerShell
function F { "Hello from F" }
Set-Alias A F
$Count = 10
Any use of a variable name with an explicit Variable: namespace is equivalent to the
use of that
same variable name without that qualification. For example, $v and
$Variable:v are
interchangeable.
As well as being defined in the language, variables can also be defined by the cmdlet
New-Variable.
Automatic variables store state information about the PowerShell environment. Their
values can be
read in user-written script but not written.
7 Note
The table originally found in this document was removed to reduce duplication. For
a complete list
of automatic variables, see
about_Automatic_Variables.
Preference variables store user preferences for the session. They are created and
initialized by the
PowerShell runtime environment. Their values can be read and written
in user-written script.
7 Note
The table originally found in this document was removed to reduce duplication. For
a complete list
of preference variables, see
about_Preference_Variables.
2.3.3 Commands
Syntax:
Syntax
generic-token:
generic-token-parts
generic-token-parts:
generic-token-part
generic-token-parts generic-token-part
generic-token-part:
expandable-string-literal
verbatim-here-string-literal
variable
generic-token-char
generic-token-char:
{ } ( ) ; , | & $
double-quote-character
single-quote-character
whitespace
new-line-character
escaped-character
generic-token-with-subexpr-start:
generic-token-parts $(
2.3.4 Parameters
Syntax:
Syntax
command-parameter:
first-parameter-char:
parameter-chars:
parameter-char
parameter-chars parameter-char
parameter-char:
{ } ( ) ; , \| & . [
colon
whitespace
new-line-character
colon:
verbatim-command-argument-chars:
verbatim-command-argument-part
verbatim-command-argument-chars verbatim-command-argument-part
verbatim-command-argument-part:
verbatim-command-string
& non-ampersand-character
new-line-character
non-ampersand-character:
verbatim-command-string:
double-quote-character non-double-quote-chars
double-quote-character
non-double-quote-chars:
non-double-quote-char
non-double-quote-chars non-double-quote-char
non-double-quote-char:
double-quote-character
Description:
PowerShell
Set-MyProcess -Strict
Parameter with argument (§8.10.2) -- This has the form command-parameter where
first-parameter-char and parameter-chars together make up the parameter name,
which
corresponds to the name of a parameter (without its leading -) in the
command being invoked. There
must be no trailing colon. The argument
immediately following designates an associated value. For
example, given a
command Get-Power , which has parameters $base and $exponent , the following
invocations are equivalent:
PowerShell
PowerShell
Get-Power 5 3
Syntax
literal:
integer-literal
real-literal
string-literal
There are two kinds of numeric literals: integer (§2.3.5.1.1) and real (§2.3.5.1.2). Both
can
have multiplier suffixes (§2.3.5.1.3).
Syntax:
Syntax
integer-literal:
decimal-integer-literal
hexadecimal-integer-literal
decimal-integer-literal:
decimal-digits:
decimal-digit
decimal-digit decimal-digits
decimal-digit: one of
0 1 2 3 4 5 6 7 8 9
numeric-type-suffix:
long-type-suffix
decimal-type-suffix
hexadecimal-integer-literal:
0x hexadecimal-digits long-type-suffix~opt~
numeric-multiplier~opt~
hexadecimal-digits:
hexadecimal-digit
hexadecimal-digit decimal-digits
hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9 a b c d e f
long-type-suffix:
numeric-multiplier: one of
kb mb gb tb pb
Description:
The type of an integer literal is determined by its value, the presence or absence of
long-
type-suffix, and the presence of a numeric-multiplier (§2.3.5.1.3).
If its value can be represented by type int (§4.2.3), that is its type;
Otherwise, if its value can be represented by type long (§4.2.3), that is its type.
Otherwise, if its value can be represented by type decimal (§2.3.5.1.2), that is its
type.
Otherwise, it is represented by type double (§2.3.5.1.2).
If its value can be represented by type long (§4.2.3), that is its type;
Otherwise, that literal is ill formed.
Some examples of integer literals are 123 (int), 123L (long), and 200000000000 (long).
Syntax:
Syntax
real-literal:
exponent-part:
e sign~opt~ decimal-digits
sign: one of
dash
decimal-type-suffix:
numeric-multiplier: one of
kb mb gb tb pb
dash:
- (U+002D)
Description:
There are two kinds of real literal: double and decimal. These are indicated by the
absence or
presence, respectively, of decimal-type-suffix. (There is no such thing as a
float real
literal.)
A double real literal has type double (§4.2.4.1). A decimal real literal has type decimal
(§4.2.4.2). Trailing zeros in the fraction part of a decimal real literal are significant.
If the value of exponent-part's decimal-digits in a double real literal is less than the
minimum supported, the value of that double real literal is 0. If the value of exponent-
part's
decimal-digits in a decimal real literal is less than the minimum supported, that
literal is ill
formed. If the value of exponent-part's decimal-digits in a double or decimal
real literal is
greater than the maximum supported, that literal is ill formed.
Some examples of double real literals are 1., 1.23, .45e35, 32.e+12, and 123.456E-231.
Some examples of decimal real literals are 1d (which has scale 0), 1.20d (which has scale
2),
1.23450e1d (i.e., 12.3450, which has scale 4), 1.2345e3d (i.e., 1234.5, which has scale
1),
1.2345e-1d (i.e., 0.12345, which has scale 5), and 1.2345e-3d (i.e., 0.0012345, which
has scale 7).
7 Note
Because a double real literal need not have a fraction or exponent part, the
grouping parentheses
in (123).M are needed to ensure that the property or method
M is being selected for the integer
object whose value is 123. Without those
parentheses, the real literal would be ill-formed.
7 Note
Although PowerShell does not provide literals for infinities and NaNs, double real
literal-like
equivalents can be obtained from the static read-only properties
PositiveInfinity,
NegativeInfinity, and NaN of the types float and double (§4.2.4.1).
The grammar permits what starts out as a double real literal to have an l or L type
suffix. Such
a token is really an integer literal whose value is represented by type long.
7 Note
This feature has been retained for backwards compatibility with earlier versions of
PowerShell.
However, programmers are discouraged from using integer literals of
this form as they can easily
obscure the literal's actual value. For example, 1.2L has
value 1, 1.2345e1L has value 12, and
1.2345e-5L has value 0, none of which is
immediately obvious.
Syntax:
Syntax
kb mb gb tb pb
Description:
For convenience, integer and real literals can contain a numeric-multiplier, which
indicates one
of a set of commonly used powers of 10. numeric-multiplier can be written
in any combination of
upper- or lowercase letters.
Syntax
string-literal:
expandable-string-literal
expandable-here-string-literal
verbatim-string-literal
verbatim-here-string-literal
expandable-string-literal:
double-quote-character:
" (U+0022)
expandable-string-characters:
expandable-string-part
expandable-string-characters
expandable-string-part
expandable-string-part:
double-quote-character
braced-variable
double-quote-character
$ escaped-character
escaped-character
double-quote-character double-quote-character
dollars:
dollars $
expandable-here-string-literal:
expandable-here-string-characters:
expandable-here-string-part
expandable-here-string-characters expandable-here-string-part
expandable-here-string-part:
new-line-character
braced-variable
new-line-character
expandable-string-with-subexpr-start:
double-quote-character expandable-string-chars~opt~ $(
expandable-string-with-subexpr-end:
double-quote-char
expandable-here-string-with-subexpr-start:
expandable-here-string-with-subexpr-end:
new-line-character double-quote-character @
verbatim-string-literal:
single-quote-character:
' (U+0027)
verbatim-string-characters:
verbatim-string-part
verbatim-string-characters verbatim-string-part
verbatim-string-part:
single-quote-character single-quote-character
verbatim-here-string-literal:
verbatim-here-string-characters~opt~ new-line-character
single-quote-character *@*
verbatim-*here-string-characters:
verbatim-here-string-part
verbatim-here-string-characters verbatim-here-string-part
verbatim-here-string-part:
Description:
PowerShell
@'
'@
@'
line 1
'@
@'
line 1
line 2
'@
PowerShell
@"
"@
@"
line 1
"@
@"
line 1
line 2
"@
Output
column1<horizontal-tab>column2<new-line>
7 Note
If the variable name is part of some larger expression, only the variable name is
replaced. For
example, if $a is an array containing the elements 100 and 200,
">$a.Length<" results in
>100 200.Length< while ">$($a.Length)<" results in >2< .
See sub-expression expansion below.
PowerShell
$count = 10
Output
PowerShell
$a = "red","blue"
The result is
Output
The examples,
PowerShell
$count = 10
Output
10 + 5 is 15
10 + 5 is $(10 + 5)
10 + 5 is $($count + 5)
PowerShell
$i = 5; $j = 10; $k = 15
"`$i, `$j, and `$k have the values $( $i; $j; $k )"
Output
These four lines could have been written more succinctly as follows:
PowerShell
"`$i, `$j, and `$k have the values $(($i = 5); ($j = 10); ($k = 15))"
PowerShell
"First 10 squares: $(for ($i = 1; $i -le 10; ++$i) { "$i $($i*$i) " })"
Output
As shown, a sub-expression can contain string literals having both variable substitution
and
sub-expression expansion. Note also that the inner expandable-string-literal's
delimiters need
not be escaped; the fact that they are inside a sub-expression means
they cannot be terminators
for the outer expandable-string-literal.
PowerShell
$a = 10
"`$s1 = >$s1<"
"`$s2 = >$s2<"
$s2 = $s1
"`$s2 = >$s2<"
Output
$lit = @'
That's it!
2 * 3 = $(2*3)
'@
Output
That's it!
2 * 3 = $(2*3)
PowerShell
$lit = @"
That's it!
2 * 3 = $(2*3)
"@
PowerShell
That's it!
2 * 3 = 6
PowerShell
$lit = @"
abc
xyz
"@
the second line of the body has two leading spaces, and the first and second lines of the
body have
line terminators; however, the terminator for the second line of the body is
not part of that
body. The resulting literal is equivalent to:
"abc<implementation-defined
character sequence>xyz" .
7 Note
To aid readability of source, long string literals can be broken across multiple
source lines
without line terminators being inserted. This is done by writing each
part as a separate literal
and concatenating the parts with the + operator (§7.7.2).
This operator allows its operands to
designate any of the four kinds of string literal.
7 Note
Although there is no such thing as a character literal per se, the same effect can be
achieved by
accessing the first character in a 1-character string, as follows:
[char]"A" or "A"[0] .
Syntax
type-name:
type-identifier
type-name . type-identifier
type-identifier:
type-characters
type-characters:
type-character
type-characters type-character
type-character:
array-type-name:
type-name [
generic-type-name:
type-name [
Syntax
operator-or-punctuator: one of
{ } [ ] ( ) @( @{ $( ;
&& || & | , ++ .. :: .
! * / % + - --
assignment-operator
merging-redirection-operator
file-redirection-operator
comparison-operator
format-operator
assignment-operator: one of
= -= += *= /= %=
file-redirection-operator: one of
> >> 2> 2>> 3> 3>> 4> 4>>
merging-redirection-operator: one of
comparison-operator: *one of
-shr -split
format-operator:
-f
Description:
7 Note
Editor's Note: The pipeline chain operators && and || were introduced in
PowerShell 7. See
about_Pipeline_Chain_Operators.
The name following dash in an operator is reserved for that purpose only in an operator
context.
An operator that begins with dash must not have any white space between that dash
and the token
that follows it.
Syntax
escaped-character:
Description:
Escaped Meaning
Character
`a Alert (U+0007)
`b Backspace (U+0008)
`f Form-feed (U+000C)
`n New-line (U+000A)
`` Backtick (U+0060)
`0 NUL (U+0000)
`x If x is a character other than those characters shown above, the backtick character
is ignored and x is taken literally.
The implication of the final entry in the table above is that spaces that would otherwise
separate
tokens can be made part of a token instead. For example, a file name
containing a space can be
written as Test` Data.txt (as well as 'Test Data.txt' or
"Test Data.txt" ).
3. Basic concepts
Article • 07/29/2021
The data that a provider exposes appears on a drive, and the data is accessed via a path
just
like with a disk drive. Built-in cmdlets for each provider manage the data on the
provider drive.
PowerShell includes the following set of built-in providers to access the different types
of data
stores:
FileSystem A:, B:, C:, ... Disk drives, directories, and files §3.1.3
Windows PowerShell:
3.1.1 Aliases
An alias is an alternate name for a command. A command can have multiple aliases, and
the original
name and all of its aliases can be used interchangeably. An alias can be
reassigned. An alias is an
item (§3.3).
An alias can be assigned to another alias; however, the new alias is not an alias of the
original
command.
The provider Alias is a flat namespace that contains only objects that represent the
aliases. The
variables have no child items.
When an alias is created for a command using New-Alias , parameters to that command
cannot be
included in that alias. However, direct assignment to a variable in the Alias:
namespace does permit
parameters to be included.
7 Note
It is a simple matter, however, to create a function that does nothing more than
contain the
invocation of that command with all desired parameters, and to assign
an alias to that function.
The file system provider is a hierarchical namespace that contains objects that represent
the
underlying file system.
Files are stored on drives with names like A:, B:, C:, and so on (§3.1). Directories and files
are accessed using path notation (§3.4).
3.1.4 Functions
The PowerShell function provider allows functions (§8.10) and filters (§8.10.1) to be
retrieved, added, changed, cleared, and deleted.
The provider Function is a flat namespace that contains only the function and filter
objects.
Neither functions nor filters have child items.
The type of an object that represents a function is described in §4.5.10. The type of an
object
that represents a filter is described in §4.5.11.
3.1.5 Variables
Variables can be defined and manipulated directly in the PowerShell language.
The provider Variable is a flat namespace that contains only objects that represent the
variables.
The variables have no child items.
A PowerShell host may have multiple drives, in which case, each drive has its own
current location.
When a drive name is specified without a directory, the current location for that drive is
implied.
The current working location can be saved on a stack, and then set to a new location.
Later, that
saved location can be restored from that stack and made the current working
location. There are two
kinds of location stacks: the default working location stack, and
zero or more user-defined named
working location stacks. When a session begins, the
default working location stack is also the
current working location stack. However, any
named working location stack can be made the current
working location stack.
The object types that represents a working location and a stack of working locations are
described
in §4.5.5.
3.3 Items
An item is an alias (§3.1.1), a variable (§3.1.5), a function (§3.1.4), an environment
variable
(§3.1.2), or a file or directory in a file system (§3.1.3).
The type of an object that represents a directory is described in §4.5.17. The type of an
object
that represents a file is described in §4.5.18.
Path names are divided into one of two types: fully qualified and relative. A fully
qualified path
name consists of all elements that make up a path. The following syntax
shows the elements in a
fully qualified path name:
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
Syntax
path:
provider:
module~opt~ provider ::
module:
module-name \
drive:
drive-name :
containers:
container \
containers container \
provider refers to the PowerShell provider through which the data store is accessed.
drive refers to the PowerShell drive that is supported by a particular PowerShell provider.
A container can contain other containers, which can contain other containers, and so on,
with the
final container holding an item. Containers must be specified in the hierarchical
order in which
they exist in the data store.
E:\Accounting\InvoiceSystem\Production\MasterAccount\MasterFile.dat
\ Drive root of the current working location \Program Files C:\Program Files
The object type that represents a resolved path is described in §4.5.5. Paths are often
manipulated as strings.
3.5 Scopes
3.5.1 Introduction
A name can denote a variable, a function, an alias, an environment variable, or a drive.
The same
name may denote different items at different places in a script. For each
different item that a name
denotes, that name is visible only within the region of script
text called its scope. Different
items denoted by the same name either have different
scopes, or are in different name spaces.
Scopes may nest, in which case, an outer scope is referred to as a parent scope, and any
nested
scopes are child scopes of that parent. The scope of a name is the scope in which
it is defined
and all child scopes, unless it is made private. Within a child scope, a name
defined there hides
any items defined with the same name in parent scopes.
Unless dot source notation (§3.5.5) is used, each of the following creates a new scope:
A script file
A script block
A function or filter
PowerShell
# start of script
$x = 2; $y = 3
Get-Power $x $y
else { return 1 }
# end of script
The scope of the variables $x and $y created in the script is the body of that script,
including
the function defined inside it. Function Get-Power defines two parameters with
those same names.
As each function has its own scope, these variables are different
from those defined in the parent
scope, and they hide those from the parent scope. The
function scope is nested inside the script
scope.
Note that the function calls itself recursively. Each time it does so, it creates yet another
nested
scope, each with its own variables $x and $y .
Here is a more complex example, which also shows nested scopes and reuse of names:
PowerShell
# start of script scope
# $x is 2
# $x is 2
# $x is $true
# $x is $true
$x = 12.345 # scriptblock-scope $x created
# $x is 12.345
# $x is $true
F2 # create nested scope with call to function F2
# $x is $true
} # end of function scope, local $x goes away
# $x is $true
$x = "red" # function-scope $x created
# $x is "red"
} # end of function scope, local $x goes away
# $x is 2
if ($x -gt 0) {
# $x is 2
$x = "green"
# $x is "green"
# $x is still "green"
Global: This is the top-most level scope. All automatic and preference variables are
defined in
this scope. The global scope is the parent scope of all other scopes, and
all other scopes are
child scopes of the global scope.
Local: This is the current scope at any execution point within a script, script block,
or
function. Any scope can be the local scope.
Script: This scope exists for each script file that is executed. The script scope is the
parent
scope of all scopes created from within it. A script block does not have its
own script scope;
instead, its script scope is that of its nearest ancestor script file.
Although there is no such
thing as module scope, script scope provides the
equivalent.
Names can be declared private, in which case, they are not visible outside of their parent
scope,
not even to child scopes. The concept of private is not a separate scope; it's an
alias for local
scope with the addition of hiding the name if used as a writable location.
Scopes can be referred to by a number, which describes the relative position of one
scope to
another. Scope 0 denotes the local scope, scope 1 denotes a 1-generation
ancestor scope, scope 2
denotes a 2-generation ancestor scope, and so on. (Scope
numbers are used by cmdlets that manipulate
variables.)
Syntax
variable-scope:
global:
local:
private:
script:
using:
workflow:
variable-namespace
The scope is optional. The following table shows the meaning of each in all possible
contexts. It
also shows the scope when no scope is specified explicitly:
script Nearest ancestor script Nearest ancestor script Nearest ancestor script
file's scope or Global if file's scope or Global if file's scope or Global if
there is no nearest there is no nearest there is no nearest
ancestor script file ancestor script file ancestor script file
Variable scope information can also be specified when using the family of cmdlets listed
in
(§3.1.5). In particular, refer to the parameter Scope , and the parameters Option
Private and
Option AllScope for more information.
The scope using is used to access variables defined in another scope while running
scripts via
cmdlets like Start-Job , Invoke-Command , or within an inlinescript-statement.
For example:
PowerShell
$a = 42
workflow foo
$b = "Hello"
inlinescript { $using:b }
PowerShell
Script1.ps1
& "Script1.ps1"
& { ... }
FunctionA
However, when dot source notation is used, no new scope is created before the
command is executed,
so additions/changes it would have made to its own local scope
are made to the current scope
instead. For example,
PowerShell
. Script2.ps1
. "Script2.ps1"
. { ... }
. FunctionA
3.5.6 Modules
Just like a top-level script file is at the root of a hierarchical nested scope tree, so too is
each
module (§3.14). However, by default, only those names exported by a module are
available by name
from within the importing context. The Global parameter of the
cmdlet
Import-Module allows exported names to have
increased visibility.
3.7.1 Introduction
As stated in §1, an external procedure made available by the execution environment
(and written in
some language other than PowerShell) is called a method.
The name of a method along with the number and types of its parameters are
collectively called that
method's signature. (Note that the signature does not include the
method's return type.) The
execution environment may allow a type to have multiple
methods with the same name provided each has
a different signature. When multiple
versions of some method are defined, that method is said to be
overloaded. For
example, the type Math (§4.3.8) contains a set of methods called Abs , which
computes
the absolute value of a specified number, where the specified number can have one of a
number of types. The methods in that set have the following signatures:
PowerShell
Abs(decimal)
Abs(float)
Abs(double)
Abs(int)
Abs(long)
Abs(SByte)
Abs(Int16)
In this case, all of the methods have the same number of arguments; their signatures
differ by
argument type only.
Another example involves the type Array (§4.3.2), which contains a set of methods called
Copy
that copies a range of elements from one array to another, starting at the
beginning of each array
(by default) or at some designated element. The methods in
that set have the following signatures:
PowerShell
In this case, the signatures differ by argument type and, in some cases, by argument
number as well.
In most calls to overloaded methods, the number and type of the arguments passed
exactly match one
of the overloads, and the method selected is obvious. However, if
that is not the case, there needs
to be a way to resolve which overloaded version to call,
if any. For example,
PowerShell
Other examples include the type string (i.e.; System.String), which has numerous
overloaded
methods.
Although PowerShell has rules for resolving method calls that do not match an
overloaded signature
exactly, PowerShell does not itself provide a way to define
overloaded methods.
7 Note
Editor's Note: PowerShell 5.0 added the ability to define script-based classes. These
classes can
contain overloaded methods.
Given the set of applicable candidate methods (§3.7.3), the best method in that set is
selected.
If the set contains only one method, then that method is the best method.
Otherwise, the best method
is the one method that is better than all other methods with
respect to the given argument list
using the rules shown in §3.7.4. If there is not exactly
one method that is better than all
other methods, then the method invocation is
ambiguous and an error is reported.
The best method must be accessible in the context in which it is called. For example, a
PowerShell
script cannot call a method that is private or protected.
The best method for a call to a static method must be a static method, and the best
method for a
call to an instance method must be an instance method.
If the argument type is ref (§4.3.6), the corresponding parameter must also be ref, and
the
argument type for conversion purposes is the type of the property Value from the
ref argument.
If the argument type is ref , the corresponding parameter could be out instead of ref .
If the method accepts a variable number of arguments, the method may be applicable
in either normal
form or expanded form. If the number of arguments in A is identical to
the number of parameters
that the method accepts and the last parameter is an array,
then the form depends on the rank of one
of two possible conversions:
The rank of the conversion from the type of the last argument in A to the array
type for the last
parameter.
The rank of the conversion from the type of the last argument in A to the element
type of the
array type for the last parameter.
If the first conversion (to the array type) is better than the second conversion (to the
element
type of the array), then the method is applicable in normal form, otherwise it is
applicable in
expanded form.
If there are more arguments than parameters, the method may be applicable in
expanded form only. To
be applicable in expanded form, the last parameter must have
array type. The method is replaced with
an equivalent method that has the last
parameter replaced with sufficient parameters to account for
each unmatched argument
in A. Each additional parameter type is the element type of the array type
for the last
parameter in the original method. The above rules for an applicable method are applied
to this new method and argument list A.
when converted to Q~X~ , or vice versa. If the parameter conversion types are
compared, then if the conversion from P~X~ to Q~X~ is better than that from Q~X~
to P~X~ ,
the M~P~ accumulates N-X+1; otherwise, M~Q~ accumulates N-X+1. This
tie breaking rule is
intended to prefer the most specific method (i.e., the method
with parameters having the
smallest data types) if no information is lost in
conversions, or to prefer the most general
method (i.e., the method with the
parameters with the largest data types) if conversions result
in loss of information.
If both methods use their expanded form, the method with more parameters is the
better method.
If one method uses the expanded form and the other uses normal form, the
method using normal form
is the better method.
T~1~[] to T~2~[] where no assignable conversion between T~1~ and T~2~ exists
implementation-defined
manner
T~1~ to T~2~ where T~1~ implements IConvertible
T~1~ to T~2~ where T~1~ or T~2~ implements the method T~2~ op_Implicit(T1)
T~1~ to T~2~ where T~1~ or T~2~ implements the method T~2~ op_Explicit(T1)
T~1~ to T~2~ where T~2~ is any enum and T~1~ is either string or a collection
of objects
that can be converted to string
T to PSObject where T is any type
T to ref
T to xml
scriptblock to delegate
double , or decimal
SByte to T where T is Int16 , UInt16 , int , UInt32 , long , UInt64 , single ,
double , or decimal
UInt16 to T where T is int , UInt32 , long , or UInt64 , single , double , or
decimal
single to double
T~1~ to T~2~ where T~2~ is a base class or interface of T~1~ . This conversion is
considered an assignable conversion.
string to char[]
T to T -- This conversion is considered an assignable conversion.
For each conversion of the form T~1~ to T~2~[] where T~1~ is not an array and no
other
conversion applies, if there is a conversion from T~1~ to T~2~ , the rank of the
conversion is
worse than the conversion from T~1~ to T~2~ , but better than any
conversion ranked less than the
conversion from T~1~ to T~2~
Type names are matched as follows: Compare a given type name with the list of built-in
type
accelerators, such as int, long, double. If a match is found, that is the type.
Otherwise, presume
the type name is fully qualified and see if such a type exists on the
host system. If a match is
found, that is the type. Otherwise, add the namespace prefix
System. . If a match is found, that is
the type. Otherwise, the type name is in error. This
An expression that invokes a command involves the expression that designates the
command, and zero
or more expressions that designate the arguments whose values
are to be passed to that command. The
order in which these expressions are evaluated
relative to each other is unspecified.
An error falls into one of two categories. Either it terminates the operation (a
terminating
error) or it doesn't (a non-terminating error). With a terminating error, the
error is recorded
and the operation stops. With a non-terminating error, the error is
recorded and the operation
continues.
Non-terminating errors are written to the error stream. Although that information can
be redirected
to a file, the error objects are first converted to strings and important
information in those
objects would not be captured making diagnosis difficult if not
impossible. Instead, the error text
can be redirected (§7.12) and the error object saved in
a variable, as in
$Error1 = command 2>&1 .
The automatic variable $Error contains a collection of error records that represent
recent errors,
and the most recent error is in $Error[0] . This collection is maintained in
a buffer such that old
records are discarded as new ones are added. The automatic
variable $MaximumErrorCount controls
the number of records that can be stored.
$Error contains all of the errors from all commands mixed in together in one collection.
To
collect the errors from a specific command, use the common parameter ErrorVariable,
which allows a user-defined variable to be specified to hold the collection.
3.13 Pipelines
A pipeline is a series of one or more commands each separated by the pipe operator |
(U+007C).
Each command receives input from its predecessor and writes output to its
successor. Unless the
output at the end of the pipeline is discarded or redirected to a
file, it is sent to the host
environment, which may choose to write it to standard output.
Commands in a pipeline may also
receive input from arguments. For example, consider
the following use of commands Get-ChildItem ,
Sort-Object , and Process-File , which
create a list of file names in a given file system
directory, sort a set of text records, and
perform some processing on a text record, respectively:
PowerShell
Get-ChildItem
In the first case, Get-ChildItem creates a collection of names of the files in the
current/default
directory. That collection is sent to the host environment, which, by
default, writes each
element's value to standard output.
In the second case, Get-ChildItem creates a collection of names of the files in the
directory
specified, using the argument e:*.txt . That collection is written to the
command Sort-Object ,
which, by default, sorts them in ascending order, sensitive to
case (by virtue of the
CaseSensitive argument). The resulting collection is then written to
command Process-File ,
which performs some (unknown) processing. The output from
that command is then redirected to the
file results.txt .
If a command writes a single object, its successor receives that object and then
terminates after
writing its own object(s) to its successor. If, however, a command writes
multiple objects, they are
delivered one at a time to the successor command, which
executes once per object. This behavior is
called streaming. In stream processing, objects
are written along the pipeline as soon as they
become available, not when the entire
collection has been produced.
When processing a collection, a command can be written such that it can do special
processing before
the initial element and after the final element.
3.14 Modules
A module is a self-contained reusable unit that allows PowerShell code to be partitioned,
organized, and abstracted. A module can contain commands (such as cmdlets and
functions) and items
(such as variables and aliases) that can be used as a single unit.
Once a module has been created, it must be imported into a session before the
commands and items
within it can be used. Once imported, commands and items
behave as if they were defined locally. A
module is imported explicitly with the Import-
Module command. A module may also be imported
automatically as determined in an
implementation defined manner.
The type of an object that represents a module is described in §4.5.12.
Element Description
[set] Matches any one character from set, which cannot be empty.
If set begins with ], that right square bracket is considered part of set and the next
right square bracket terminates the set; otherwise, the first right square bracket
terminates the set.
If set begins or ends with -, that hyphen-minus is considered part of set; otherwise, it
indicates a range of consecutive Unicode code points with the characters either side
of the hyphen-minus being the inclusive range delimiters. For example, A-Z indicates
the 26 uppercase English letters, and 0-9 indicates the 10 decimal digits.
7 Note
Element Description
Element Description
[set]
The [set] form matches any one character from set. The [^set] form matches no
[^set] characters from set. set cannot be empty.
If set begins with ] or ^], that right square bracket is considered part of set and the
next right square bracket terminates the set; otherwise, the first right square bracket
terminates the set.
If set begins with - or ^-, or ends with -, that hyphen-minus is considered part of set;
otherwise, it indicates a range of consecutive Unicode code points with the characters
either side of the hyphen-minus being the inclusive range delimiters. For example, A-
Z indicates the 26 uppercase English letters, and 0-9 indicates the 10 decimal digits.
7 Note
Element Description
\p{name} Matches any character in the named character class specified by name. Supported
names are Unicode groups and block ranges such as Ll, Nd, Z, IsGreek, and
IsBoxDrawing.
\P{name} Matches text not included in the groups and block ranges specified in name.
Element Description
\s Matches any white space character. Equivalent to the Unicode character categories
[\f\n\r\t\v\x85\p{Z}] .
\d Matches any decimal digit. Equivalent to \p{Nd} for Unicode and [0-9] for non-
Unicode behavior.
\D Matches any non-digit. Equivalent to \P{Nd} for Unicode and [\^0-9] for non-
Unicode behavior.
Element Description
* Specifies zero or more matches; for example, \w* or (abc)*. Equivalent to {0,} .
? Specifies zero or one matches; for example, \w? or (abc)? . Equivalent to {0,1} .
In PowerShell, each value has a type, and types fall into one of two main categories:
value types
and reference types. Consider the type int , which is typical of value types.
A value of type
int is completely self-contained; all the bits needed to represent that
value are stored in that
value, and every bit pattern in that value represents a valid value
for its type. Now, consider the
array type int[] , which is typical of reference types. A so-
called value of an array type can hold
either a reference to an object that actually
contains the array elements, or the null reference
whose value is $null . The important
distinction between the two type categories is best
demonstrated by the differences in
their semantics during assignment. For example,
PowerShell
As we can see, the assignment of a reference type value involves a shallow copy; that is,
a copy
of the reference to the object rather than its actual value. In contrast, a deep
copy requires
making a copy of the object as well.
A numeric type is one that allows representation of integer or fractional values, and that
supports arithmetic operations on those values. The set of numerical types includes the
integer
(§4.2.3) and real number (§4.2.4) types, but does not include bool
(§4.2.1) or char
(§4.2.2). An implementation may provide other numeric types
(such as signed byte,
unsigned integer, and integers of other sizes).
A collection is a group of one or more related items, which need not have the same
type.
Examples of collection types are arrays, stacks, queues, lists, and hash tables. A
program can
enumerate (or iterate) over the elements in a collection, getting access to
each element one at
a time. Common ways to do this are with the foreach statement
(§8.4.4) and the
ForEach-Object cmdlet. The type of an object that
represents an
enumerator is described in §4.5.16.
In this chapter, there are tables that list the accessible members for a given type. For
methods,
the Type is written with the following form: returnType/argumentTypeList. If
the argument
type list is too long to fit in that column, it is shown in the Purpose
column instead.
Other integer types are SByte , Int16 , UInt16 , UInt32 , and UInt64 , all in the namespace
System.
You can also use shorthand names for some types. For more information, see
about_Type_Accelerators.
4.2.1 Boolean
The Boolean type is bool . There are only two values of this type, False and True,
represented by the automatic variables $false and $true , respectively (§2.3.2.2).
4.2.2 Character
A character value has type char, which is capable of storing any UTF-16-encoded 16-bit
Unicode code
point.
MaxValue Static property char The largest possible value of type char
(read-only)
MinValue Static property char The smallest possible value of type char
(read-only)
4.2.3 Integer
There are two signed integer types, both of use two's-complement
representation for
negative values:
MaxValue Static property (read-only) int The largest possible value of type int
MinValue Static property (read-only) int The smallest possible value of type int
MaxValue Static property (read-only) long The largest possible value of type long
MinValue Static property (read-only) long The smallest possible value of type long
MaxValue Static property (read-only) byte The largest possible value of type byte
MinValue Static property (read-only) byte The smallest possible value of type byte
A third type name, single , is a synonym for type float ; float is used throughout this
specification.
Although the size and representation of the types float and double are defined by this
specification, an implementation may use extended precision for intermediate results.
MaxValue Static property (read-only) float The largest possible value of type float
MinValue Static property (read-only) float The smallest possible value of type float
NegativeInfinity Static property (read-only) float The constant value negative infinity
PositiveInfinity Static property (read-only) float The constant value positive infinity
MaxValue Static property (read- double The largest possible value of type double
only)
MinValue Static property (read- double The smallest possible value of type
only) double
NegativeInfinity Static property (read- double The constant value negative infinity
only)
PositiveInfinity Static property (read- double The constant value positive infinity
only)
4.2.4.2 decimal
Type decimal uses a 128-bit representation. At a minimum it must support a scale s such
that 0
<= s <= at least 28, and a value range -79228162514264337593543950335 to
79228162514264337593543950335. The actual representation of decimal is
implementation defined.
MaxValue Static property (read-only) decimal The largest possible value of type decimal
MinValue Static property (read-only) decimal The smallest possible value of type decimal
7 Note
Decimal real numbers have a characteristic called scale, which represents the
number of digits
to the right of the decimal point. For example, the value 2.340 has
a scale of 3 where trailing
zeros are significant. When two decimal real numbers are
added or subtracted, the scale of the
result is the larger of the two scales. For
example, 1.0 + 2.000 is 3.000, while 5.0 - 2.00 is
3.00. When two decimal real
numbers are multiplied, the scale of the result is the sum of the two
scales. For
example, 1.0 * 2.000 is 2.0000. When two decimal real numbers are divided, the
scale
of the result is the scale of the first less the scale of the second. For example,
4.00000/2.000
is 2.00. However, a scale cannot be less than that needed to preserve
the correct result. For
example, 3.000/2.000, 3.00/2.000, 3.0/2.000, and 3/2 are all
1.5.
When considered as an array of four int values it contains the following elements:
Index 0 (bits 0‑31) contains the low-order 32 bits of the decimal's coefficient.
Index 1 (bits 32‑63) contains the middle 32 bits of the decimal's coefficient.
Index 2 (bits 64‑95) contains the high-order 32 bits of the decimal's coefficient.
Index 3 (bits 96‑127) contains the sign bit and scale, as follows:
bits 0--15 are zero
bits 16‑23 contains the scale as a value 0--28
bits 24‑30 are zero
bit 31 is the sign (0 for positive, 1 for negative)
Continue Enumeration The PowerShell runtime will continue processing and notify the
constant user that an action has occurred.
Inquire Enumeration The PowerShell runtime will stop processing and ask the user
constant how it should proceed.
Stop Enumeration The PowerShell runtime will stop processing when an action
constant occurs.
High Enumeration The action performed has a high risk of losing data, such as
constant reformatting a hard disk.
Low Enumeration The action performed has a low risk of losing data.
constant
Medium Enumeration The action performed has a medium risk of losing data.
constant
None Enumeration Do not confirm any actions (suppress all requests for confirmation).
constant
Archive Enumeration The file's archive status. Applications use this attribute to
constant mark files for backup or removal.
Encrypted Enumeration The file or directory is encrypted. For a file, this means that
constant all data in the file is encrypted. For a directory, this means
that encryption is the default for newly created files and
directories.
Hidden Enumeration The file is hidden, and thus is not included in an ordinary
constant directory listing.
Normal Enumeration The file is normal and has no other attributes set. This
constant attribute is valid only if used alone.
NotContentIndexed Enumeration The file will not be indexed by the operating system's
constant content indexing service.
Member Member Purpose
Kind
Offline Enumeration The file is offline. The data of the file is not immediately
constant available.
ReparsePoint Enumeration The file contains a reparse point, which is a block of user-
constant defined data associated with a file or a directory.
SparseFile Enumeration The file is a sparse file. Sparse files are typically large files
constant whose data are mostly zeros.
System Enumeration The file is a system file. The file is part of the operating
constant system or is used exclusively by the operating system.
Temporary Enumeration The file is temporary. File systems attempt to keep all of the
constant data in memory for quicker access rather than flushing the
data back to mass storage. A temporary file should be
deleted by the application as soon as it is no longer needed.
This implementation-defined type has the following accessible members, which can be
combined:
Length Instance int (read- Gets the number of characters in the string
Property only)
ToLower Instance string Creates a new string that contains the lowercase
Method equivalent
ToUpper Instance string Creates a new string that contains the uppercase
Method equivalent
4.3.2 Arrays
All array types are derived from the type Array . This type has the following accessible
members:
Copy Static void/see Copies a range of elements from one array to another. There
Method Purpose are four versions, where source is the source array, destination
column is the destination array, count is the number of elements to
copy, and sourceIndex and destinationIndex are the starting
locations in their respective arrays:
4.3.3 Hashtables
Type Hashtable has the following accessible members:
Value Instance property The type of the value being Gets/sets the value being
(read-write) referenced. referenced.
PowerShell
function Doubler {
PowerShell
As shown, both the argument and its corresponding parameter must be declared ref .
File Instance string Gets the name of the file in which the script
property block is defined.
(read-
only)
Invoke Instance Collection of Invokes the script block with the specified
method object/object[] arguments and returns the results.
InvokeReturnAsIs Instance object/object[] Invokes the script block with the specified
method arguments and returns any objects generated.
Abs Static numeric/numeric Absolute value (the return type is the same as the
method type of the argument passed in)
Acos Static double / double Angle whose cosine is the specified number
method
Asin Static double / double Angle whose sine is the specified number
method
Atan Static double / double Angle whose tangent is the specified number
method
Atan2 Static double / double Angle whose tangent is the quotient of two
method y, double x specified numbers x and y
Ceiling Static decimal / decimal smallest integer greater than or equal to the
method specified number
double / double
Floor Static decimal / decimal Largest integer less than or equal to the specified
method number
double / double
Member Member Type Purpose
Kind
Log Static double / double Logarithm of number using base e or base base
method number
double / double
number, double
base
Max Static numeric/numeric Larger of two specified numbers (the return type is
method the same as the type of the arguments passed in)
Min Static numeric/numeric, Smaller of two specified numbers (the return type
method numeric is the same as the type of the arguments passed
in)
Pow Static double / double A specified number x raised to the specified power
method x, double y y
A generic dictionary type that is specialized to hold int keys with associated string
values might
be written as Dictionary[int,string] .
A stack of stack of strings might be written as Stack[Stack[string]] .
Although PowerShell does not define any built-in generic types, it can use such types if
they are
provided by the host environment. See the syntax in §7.1.10.
Dictionary[int,string]
suggested above is
System.Collections.Generic.Dictionary[int,string] .
CurrentLocation Instance property (read- string The current working location (§3.1.4) of
write) the drive
Description Instance string The description assigned to the variable via the
property New-Variable or Set-Variable cmdlets.
(read-
write)
Member Member Type Purpose
Kind
Module Instance Implementation The module from which this variable was
property defined exported
(read- (§4.5.12)
only)
ModuleName Instance string The module in which this variable was defined
property
(read-
only)
Name Instance string The name assigned to the variable when it was
property created in the PowerShell language or via the
(read- New-Variable and Set-Variable cmdlets.
only)
Options Instance string The options assigned to the variable via the New-
property Variable and Set-Variable cmdlets.
(read-
write)
Value Instance object The value assigned to the variable when it was
property assigned in the PowerShell language or via the
(read- New-Variable and Set-Variable cmdlets.
write)
Module Instance Implementation The module from which this alias was
property defined exported
(read-only) (§4.5.12)
Options Instance string The options assigned to the alias via the
property New-Alias New-Alias or Set-Alias
(read-write) cmdlets.
Name Instance property (read-write) string The name of the environment variable
Value Instance property (read-write) string The value of the environment variable
HelpFile Instance string The path to the Help file for the cmdlet.
property
(read-
write)
ModuleName Instance string The name of the module that defines the
property cmdlet.
(read-
only)
Module Instance Implementation The module from which this function was
property defined exported
(read- (§4.5.12)
only)
Options Instance Implementation The scope options for the function (§3.5.4).
property defined
(read-
write)
Member Member Type Purpose
Kind
System.Collections.ObjectModel.ReadOnlyCollection``1[[System.Management.Automa
tion.PSTypeName,System.Management.Automation]] .
[System.Management.Automation.ParameterMetadata,System.Management.Automation]] .
tion.CommandParameterSetInfo,System.Management.Automation]] .
Visibility has type System.Management.Automation.SessionStateEntryVisibility .
PowerShell also has a property called Visibility.
4.5.11 Filter description type
This type encapsulates the state of a filter. It has the same set of accessible members as
the
function description type (§4.5.10).
ParameterSetName Instance property string Name of the current parameter set (see
(read-only) ParameterSetName)
Current Instance object Gets the current element in the collection. If the enumerator
property is not currently positioned at an element of the collection,
(read- the behavior is implementation defined.
only)
MoveNext Instance None/bool Advances the enumerator to the next element of the
method collection. Returns $true if the enumerator was successfully
advanced to the next element; $false if the enumerator has
passed the end of the collection.
CreationTime Instance Implementation Gets and sets the creation time of the
property (read- defined (§4.5.19) directory object.
write)
LastWriteTime Instance Implementation Gets and sets the time when the
property (read- defined (§4.5.19) directory was last written to.
write)
BaseName Instance string Gets the name of the file excluding the
property extension.
(read- only)
CreationTime Instance Implementation Gets and sets the creation time of the file
property defined object.
(read-write) (§4.5.19)
Extension Instance string Gets the extension part of the file name.
property
(read- only)
LastWriteTime Instance Implementation Gets and sets the time when the file was last
property defined written to.
(read-write) (§4.5.19)
Member Member Type Purpose
Kind
Day Instance property int Gets the day component of the month represented
(read-only) by this instance.
Hour Instance property int Gets the hour component of the date represented by
(read-only) this instance.
Minute Instance property int Gets the minute component of the date represented
(read-only) by this instance.
Month Instance property int Gets the month component of the date represented
(read-only) by this instance.
Second Instance property int Gets the seconds component of the date represented
(read-only) by this instance.
Year Instance property int Gets the year component of the date represented by
(read-only) this instance.
Average Instance property double Gets the average of the values of the properties
(read-only) that are measured.
Count Instance property int Gets the number of objects with the specified
(read-only) properties.
Maximum Instance property double Gets the maximum value of the specified
(read-only) properties.
Minimum Instance property double Gets the minimum value of the specified
(read-only) properties.
Sum Instance property double Gets the sum of the values of the specified
(read-only) properties.
Characters Instance property (read- int Gets the number of characters in the target
only) object.
Lines Instance property (read- int Gets the number of lines in the target object.
only)
Words Instance property (read- int Gets the number of words in the target object.
only)
Invoke Instance object/variable Takes a variable number of arguments, and indirectly calls
method number and the method referred to by the parent method designator,
type passing in the arguments.
When an object is created, it contains all the instance properties of that object's type,
and the
instance methods of that type can be called on that object. An object may be
customized via the
addition of instance members at runtime. The result is called a
custom object. Any members added
to an instance exist only for the life of that instance;
other instances of the same core type are
unaffected.
The base member set of a type can be augmented by the addition of the following kinds
of members:
adapted members, via the Extended Type System (ETS), most details of which are
unspecified.
extended members, via the cmdlet Add-Member.
In PowerShell, extended members can also be added via types.ps1xml files. Adapted
and extended
members are collectively called synthetic members.
The ETS adds the following members to all PowerShell objects: psbase, psadapted,
psextended, and pstypenames. See the Force and View parameters in the cmdlet
Get-
Member for more information on these members.
An instance member may hide an extended and/or adapted member of the same name,
and an extended
member may hide an adapted member. In such cases, the member
sets psadapted and psextended
can be used to access those hidden members.
There are three ways create a custom object having a new member M:
PowerShell
PowerShell
PowerShell
$x = New-Object PSObject
A variable represents a storage location for a value, and that value has a type. Traditional
procedural programming languages are statically typed; that is, the runtime type of a
variable is
that with which it was declared at compile time. Object-oriented languages
add the idea of
inheritance, which allows the runtime type of a variable to be that with
which it was declared at
compile time or some type derived from that type. Being a
dynamically typed language, PowerShell's
variables do not have types, per se. In fact,
variables are not defined; they simply come into being
when they are first assigned a
value. And while a variable may be constrained (§5.3) to holding
a value of a given type,
type information in an assignment cannot always be verified statically.
At different times, a variable may be associated with values of different types either
through
assignment (§7.11) or the use of the ++ and ‑‑ operators (§7.1.5, §7.2.6). When
the
value associated with a variable is changed, that value's type may change. For
example,
PowerShell
Any use of a variable that has not been created results in the value $null. To see if a
variable has
been defined, use the Test-Path cmdlet.
PowerShell
$radius = 2.45
$month = $date.Month
$value = $values[2]
$h1.FirstName = "Smith"
$Alias:A = "Help"
$Env:MyPath = "e:\Temp"
${E:output.txt} = 123
$Variable:v = 10
variables
$Alias:A , $Env:MyPath , ${E:output.txt} , and $function:F are variables on the
corresponding
provider drives.
$Variable:v is actually an ordinary variable written with its fully qualified provider
drive.
Memory for creating and deleting objects containing static variables is managed by the
host
environment and the garbage collection system.
A PowerShell host environment might provide a way to create new types that contain
instance
variables or to add new instance variables to existing types.
Memory for creating and deleting objects containing static variables is managed by the
host
environment and the garbage collection system.
Memory for creating and deleting arrays is managed by the host environment and the
garbage
collection system.
Memory for creating and deleting Hashtables is managed by the host environment and
the garbage
collection system.
Hashtables are discussed in §10.
5.2.5 Parameters
A parameter is created when its parent command is invoked, and it is initialized with the
value of
the argument provided in the invocation or by the host environment. A
parameter ceases to exist when
its parent command terminates.
The lifetime of an ordinary variable is that part of program execution during which
storage is
guaranteed to be reserved for it. This lifetime begins at entry into the scope
with which it is
associated, and ends no sooner than the end of the execution of that
scope. If the parent scope is
entered recursively or iteratively, a new instance of the local
variable is created each time.
An ordinary variable can be named explicitly with a Variable: namespace prefix (§5.2.7).
Any variable belonging to the namespace Env:, Alias:, or to the file system namespace
(§2.3.2, §3.1) is constrained implicitly to the type string . Any variable belonging to the
namespace Function: (§2.3.2, §3.1) is constrained implicitly to the type scriptblock .
6. Conversions
Article • 02/03/2023
A type conversion is performed when a value of one type is used in a context that
requires a
different type. If such a conversion happens automatically it is known as
implicit conversion. (A
common example of this is with some operators that need to
convert one or more of the values
designated by their operands.) Implicit conversion is
permitted provided the sense of the source
value is preserved, such as no loss of
precision of a number when it is converted.
Explicit conversion of a value to the type it already has causes no change to that value
or its
representation.
The rules for handing conversion when the value of an expression is being bound to a
parameter are
covered in §6.17.
The bool value False is converted to zero; the bool value True is converted to 1.
A char type value whose value can be represented in the destination type has that
value;
otherwise, the conversion is in error.
A numeric type value whose value after rounding of any fractional part can be
represented in the
destination type has that rounded value; otherwise, the
conversion is in error.
A value of null type is converted to zero.
A string that represents a number is converted as described in §6.16. If after
truncation of
the fractional part the result can be represented in the destination
type the string is well
formed and it has the destination type; otherwise, the
conversion is in error. If the string does
not represent a number, the conversion is
in error.
For other reference type values, if the reference type supports such a conversion,
that conversion
is used; otherwise, the conversion is in error.
6.5 Conversion to float and double
The rules for converting any value to type float or double are as
follows:
The bool value False is converted to zero; the bool value True is converted to 1.
A char value is represented exactly.
A numeric type value is represented exactly, if possible; however, for int, long, and
decimal
conversions to float, and for long and decimal conversions to double,
some of the least
significant bits of the integer value may be lost.
A value of null type is converted to zero.
A string that represents a number is converted as described in §6.16; otherwise, the
conversion is in error.
For other reference type values, if the reference type supports such a conversion,
that conversion
is used; otherwise, the conversion is in error.
The bool value False is converted to zero; the bool value True is converted to 1.
A char type value is represented exactly.
A numeric type value is represented exactly; however, if that value is too large or
too small to
fit in the destination type, the conversion is in error.
A value of null type is converted to zero.
A string that represents a number is converted as described in §6.16; otherwise, the
conversion is in error.
For other reference type values, if the reference type supports such a conversion,
that conversion
is used; otherwise, the conversion is in error.
The scale of the result of a successful conversion is such that the fractional part has
no
trailing zeros.
The string used to represent the value of an element that is an array has the form
System.type[] ,
System.type[,] , and so on. For other reference types, the method
For other enumerable types, a new 1-element array is created whose value is the
corresponding
element after conversion to the target element type, if such a conversion
exists. Otherwise, the
conversion is in error.
A value of type string that contains one of the named values (with regard for case)
for an
enumeration type is converted to that named value.
A value of type string that contains a comma-separated list of named values (with
regard for case)
for an enumeration type is converted to the bitwise-OR of all
those named values.
A number of pieces of machinery come in to play here; these include the possible use of
single
argument constructors or default constructors if the value is a hashtable, implicit
and explicit
conversion operators, and Parse methods for the target type; the use of
Convert.ConvertTo; and the
ETS conversion mechanism.
If the left operand designates a value of type bool, the conversion is in error.
Otherwise, all operands designating the value $null are converted to zero of type
int and the
process continues with the numeric conversions listed below.
Otherwise, if the left operand designates a value of type char and the right
operand designates a
value of type bool, the conversion is in error.
Otherwise, if the left operand designates a value of type string but does not
represent a number
(§6.16), the conversion is in error.
Otherwise, if the right operand designates a value of type string but does not
represent a number
(§6.16), the conversion is in error.
Otherwise, all operands designating values of type string are converted to
numbers (§6.16),
and the process continues with the numeric conversions listed
below.
Otherwise, the conversion is in error.
Numeric conversions:
If one operand designates a value of type decimal, the value designated by the
other operand is
converted to that type, if necessary. The result has type decimal.
Otherwise, if one operand designates a value of type double, the value designated
by the other
operand is converted to that type, if necessary. The result has type
double.
Otherwise, if one operand designates a value of type float, the values designated
by both operands
are converted to type double, if necessary. The result has type
double.
Otherwise, if one operand designates a value of type long, the value designated by
the other
operand value is converted to that type, if necessary. The result has the
type first in the
sequence long and double that can represent its value.
Otherwise, the values designated by both operands are converted to type int, if
necessary. The
result has the first in the sequence int, long, double that can
represent its value without
truncation.
6.16 Conversion from string to numeric type
Depending on its contents, a string can be converted explicitly or
implicitly to a numeric
value. Specifically,
When the value of an expression is being bound to a parameter, there are extra
conversion
considerations, as described below:
If the parameter type is switch (§4.2.5, §8.10.5) and the parameter has no
argument, the value of the parameter in the called command is set to $true . If the
parameter
type is other than switch, a parameter having no argument is in error.
If the parameter type is switch and the argument value is $null , the parameter
value is set to
$false .
If the parameter type is object or is the same as the type of the argument, the
argument's value
is passed without conversion.
If the parameter type is not object or scriptblock, an argument having type
scriptblock is
evaluated and its result is passed as the argument's value. (This is
known as delayed script
block binding.) If the parameter type is object or
scriptblock, an argument having type
scriptblock is passed as is.
If the parameter type is a collection of type T2, and the argument is a scalar of type
T1, that
scalar is converted to a collection of type T2 containing one element. If
necessary, the scalar
value is converted to type T2 using the conversion rules of
this section.
If the parameter type is a scalar type other than object and the argument is a
collection, the
argument is in error.
If the expected parameter type is a collection of type T2, and the argument is a
collection of
type T1, the argument is converted to a collection of type T2 having
the same length as the
argument collection. If necessary, the argument collection
element values are converted to type T2
using the conversion rules of this section.
If the steps above and the conversions specified earlier in this chapter do not
suffice, the rules
in §6.18 are applied. If those fail, the parameter binding fails.
TypeConverter: This CLR type provides a unified way of converting types of values
to other
types, as well as for accessing standard values and sub-properties. The
most common type of
converter is one that converts to and from a text
representation. The type converter for a class
is bound to the class with a
System.ComponentModel.TypeConverterAttribute . Unless this attribute
is overridden,
all classes that inherit from this class use the same type converter as the base
class.
Refer to the PowerShell SDK and the Microsoft .NET framework documentation for
more
information.
Parse Method: If the source type is string and the destination type has a method
called
Parse , that method is called to perform the conversion.
Implicit Cast Operator: If the source type has an implicit cast operator that
converts to the
destination type, that operator is called to perform the conversion.
Explicit Cast Operator: If the source type has an explicit cast operator that converts
to the
destination type, that operator is called to perform the conversion. If the
destination type has
an explicit cast operator that converts from the source type,
that operator is called to perform
the conversion.
IConvertable: System.Convert.ChangeType is called to perform the conversion.
If the value is a hash literal (§2.3.5.6), the result is an object with an implementation
defined type that behaves like a hashtable and the order of the keys matches the
order specified
in the hash literal.
Otherwise, the behavior is implementation defined.
Only hash literals (§2.3.5.6) can be converted to ordered. The result is an instance of
System.Collections.Specialized.OrderedDictionary .
The conversion is always allowed but does not change the type of the value.
7. Expressions
Article • 09/03/2021
Syntax:
Syntax
expression:
logical-expression
Description:
The literal 123 is an expression that designates the int value 123.
The expression 1,2,3,4 designates the 4-element array object having the values
shown.
The expression 10.4 * $a specifies a computation.
The expression $a++ produces a side effect.
The expression $a[$i--] = $b[++$j] performs a combination of these things.
Except as specified for some operators, the order of evaluation of terms in an expression
and the
order in which side effects take place are both unspecified. Examples of
unspecified behavior
include the following: $i++ + $i , $i + --$i , and $w[$j++] =
$v[$j] .
A top-level expression is one that is not part of some larger expression. If a top-level
expression contains a side-effect operator the value of that expression is not written to
the
pipeline; otherwise, it is. See §7.1.1 for a detailed discussion of this.
PowerShell
$x = 10,20,30
$x = New-Object 'int[]' 3
In the first two uses of the $(...) operator, the expression designating the collection is
the
variable $x , which is enumerated resulting in three int values, plus the int 99.
However, in
the third case, the expression is a direct call to a cmdlet, so the result is not
enumerated, and
$a is an array of two elements, int[3] and int .
If an operation is not defined by PowerShell, the type of the value designated by the left
operand
is inspected to see if it has a corresponding op_<operation> method.
Syntax
primary-expression:
value
member-access
element-access
invocation-expression
post-increment-expression
post-decrement-expression
value:
parenthesized-expression
sub-expression
array-expression
script-block-expression
hash-literal-expression
literal
type-literal
variable
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
Syntax
parenthesized-expression:
Description:
A parenthesized expression is a primary-expression whose type and value are the same
as those of
the expression without the parentheses. If the expression designates a
variable then the
parenthesized expression designates that same variable. For example,
$x.m and ($x).m are
equivalent.
PowerShell
4 + 6 * 2 # 16
Ordinarily, grouping parentheses at the top-most level are redundant. However, that is
not always
the case. Consider the following example:
PowerShell
In the second case, the parentheses change the semantics, resulting in an array whose
two elements
are an array of 2 ints and the scalar int 6.
PowerShell
In the first and third cases, the value of the result is written to the pipeline. However,
although
the expression in the second case is evaluated, the result is not written to the
pipeline due to the
presence of the side-effect operator = at the top level. (Removal of
the $a = part allows the
value to be written, as * is not a side-effect operator.)
To stop a value of any expression not containing top-level side effects from being
written to the
pipeline, discard it explicitly, as follows:
PowerShell
[void](23.5/2.4)
[void]$a
$null = $a
$a > $null
To write to the pipeline the value of any expression containing top-level side effects,
enclose that
expression in parentheses, as follows:
PowerShell
In the following example, we have variable substitution (§2.3.5.2) taking place in a string
literal:
PowerShell
><
In the first case, the parentheses represent a sub-expression's delimiters not grouping
parentheses, and as the top-level expression contains a side-effect operator, the
expression's value
is not written to the pipeline. Of course, the > and < characters are
still written.) If
grouping parenthesis are added -- as shown in the second case -- writing
is enabled.
PowerShell
$a = $b = 0 # value not written to pipeline
PowerShell
$a # pipeline gets 0
Consider the following example that has two side effects, neither of which is at the top
level:
PowerShell
The result is written to the pipeline, as the top-level expression has no side effects.
Syntax
primary-expression . member-name
primary-expression :: member-name
Description:
The operator . is used to select an instance member from an object, or a key from a
Hashtable .
The left operand must designate an object, and the right operand must
designate an accessible
instance member.
Either the right operand designates an accessible instance member within the type of
the object
designated by the left operand or, if the left operand designates an array, the
right operand
designates accessible instance members within each element of the array.
The operator :: is used to select a static member from a given type. The left operand
must
designate a type, and the right-hand operand must designate an accessible static
member within that
type.
If the right-hand operand designates a writable location within the type of the object
designated by
the left operand, then the whole expression designates a writable
location.
Examples:
PowerShell
$a = 10, 20, 30
$property = "Length"
$property = "MinValue"
Syntax
argument-list:
( argument-expression-list~opt~ new-lines~opt~ )
Description:
Examples:
PowerShell
$b = "abc#$%XYZabc"
Syntax
Description:
There must not be any white space between primary-expression and the left square
bracket ( [ ).
Description:
When primary-expression designates an array of three or more dimensions, the rules for
2-dimensional arrays apply and the dimension positions are specified as a comma-
separated list of
values.
Examples:
PowerShell
$a = "red","green"
Examples:
PowerShell
When expression is a single key name, the result is the associated value and has that
type, unless
no such key exists, in which case, the result is $null . If $null is used as the
key the behavior
is implementation defined. If expression is an array of key names, see
§7.1.4.5.
Examples:
PowerShell
When expression is a single key name, if $null is used as the only value to subscript a
Hashtable, a NullArrayIndex exception is raised.
Description:
Examples:
PowerShell
$x = [xml]@"
<Name>
<FirstName>Mary</FirstName>
<LastName>King</LastName>
</Name>
"@
In the case of a Hashtable, the array slice contains the associated values to the keys
provided,
unless no such key exists, in which case, the corresponding element is $null .
If $null is used
as any key name the behavior is implementation defined.
Examples:
PowerShell
$a = [int[]](30,40,50,60,70,80,90)
Syntax
post-increment-expression:
primary-expression ++
post-decrement-expression:
primary-expression dashdash
dashdash:
--
Description:
The result produced by the postfix ++ operator is the value designated by the operand.
After that
result is obtained, the value designated by the operand is incremented by 1 of
the appropriate type.
The type of the result of expression E++ is the same as for the
result of the expression E + 1
(§7.7).
The result produced by the postfix -- operator is the value designated by the operand.
After that
result is obtained, the value designated by the operand is decremented by 1
of the appropriate type.
The type of the result of expression E-- is the same as for the
result of the expression E - 1
(§7.7).
Examples:
PowerShell
$i = 0 # $i = 0
$i++ # $i is incremented by 1
$a = 1,2,3
$b = 9,8,7
$i = 0
$j = 1
# decremented, $i incremented
Syntax
sub-expression:
Description:
Examples:
PowerShell
$j = 20
Syntax
array-expression:
Description:
Examples:
PowerShell
$j = 20
Syntax
script-block-expression:
script-block:
script-block-body:
named-block-list
statement-list
Description:
A script block is an unnamed block of statements that can be used as a single unit.
Script blocks
can be used to invoke a block of code as if it was a single command, or
they can be assigned to
variables that can be executed.
The named-block-list or statement-list is executed and the type and value(s) of the result
are
the type and value(s) of the results of those statement sets.
If param-block is omitted, any arguments passed to the script block are available via
$args
(§8.10.1).
During parameter binding, a script block can be passed either as a script block object or
as the
result after the script block has been evaluated. See §6.17 for further information.
Syntax
hash-literal-expression:
hash-literal-body:
hash-entry
hash-entry:
key-expression:
simple-name
unary-expression
statement-terminators:
statement-terminator
statement-terminators statement-terminator
statement-terminator:
new-line-character
Description:
The key may have any type except the null type. The associated values may have any
type, including
the null type, and each of those values may be any expression that
designates the desired value,
including $null .
Examples:
PowerShell
$h3 = @{ }
which creates two Hashtables, $h1 and $h2 , each containing three key/value pairs, and
a third,
$h3 , that is empty. Hashtable $h4 has keys of various types.
Syntax
type-literal:
[ type-spec ]
type-spec:
type-name
dimension:
dimension ,
generic-type-arguments:
type-spec new-lines~opt~
array-type-name:
type-name [
generic-type-name:
type-name [
Description:
Examples:
Examples of type literals are [int] , [object[] , and [int[,,]] . A generic stack type
(§4.4)
that is specialized to hold strings might be written as [Stack[string]] , and a
generic dictionary
type that is specialized to hold int keys with associated string values
might be written as
[Dictionary[int,string]] .
The type of a type-literal is System.Type . The complete name for the type Stack[string]
suggested above is System.Collections.Generic.Stack[int] . The complete name for the
type
Dictionary[int,string] suggested above is
System.Collections.Generic.Dictionary[int,string] .
Syntax
unary-expression:
primary-expression
expression-with-unary-operator
expression-with-unary-operator:
, new-lines~opt~ unary-expression
! new-lines~opt~ unary-expression
+ new-lines~opt~ unary-expression
pre-increment-expression
pre-decrement-expression
cast-expression
dash:*
- (U+002D)
pre-increment-expression:
++ new-lines~opt~ unary-expression
pre-decrement-expression:
cast-expression:
type-literal unary-expression
dashdash:
dash dash
This operator creates an unconstrained 1-dimensional array having one element, whose
type and value
are that of unary-expression.
Examples:
PowerShell
$a[0],
The operator -not converts the value designated by unary-expression to type bool (§6.2),
if
necessary, and produces a result of that type. If unary-expression's value is True, the
result is
False, and vice versa. The operator ! is an alternate spelling for -not.
Examples:
PowerShell
-not 0 # True
!"xyz" # False
Examples:
PowerShell
Examples:
PowerShell
Examples:
The unary-expression must designate a writable location having a value of numeric type
(§4) or the
value $null . If the value designated by its unary-expression is $null , unary-
expression's
value is converted to type int and value zero before the operator is
evaluated.
7 Note
The type of the value designated by unary-expression may change when the result
is stored. See
§7.11 for a discussion of type change via assignment.
For the prefix ++ operator, the value of unary-expression is incremented by 1 of the
appropriate
type. The result is the new value after incrementing has taken place. The
expression ++E is
equivalent to E += 1 (§7.11.2).
Examples:
PowerShell
$i = 0 # $i = 0
$++i # $i is incremented by 1
$a = 1,2,3
$b = 9,8,7
$i = 0;
$j = 1
The unary -join operator produces a string that is the concatenation of the value of
one or more
objects designated by unary-expression. (A separator can be inserted by
using the binary version
of this operator (§7.8.4.4).)
PowerShell
The unary -split operator splits one or more strings designated by unary-expression,
returning
their subparts in a constrained 1-dimensional array of string. It treats any
contiguous group of
white space characters as the delimiter between successive
subparts. (An explicit delimiter string
can be specified by using the binary version of this
operator (§7.8.4.5).) This operator has two
variants (§7.8).
The delimiter text is not included in the resulting strings. Leading and trailing white
space in the
input string is ignored. An input string that is empty or contains white
space only results in an
array of 1 string, which is empty.
Examples:
PowerShell
-split ("yes no", "up down") # 4 strings: "yes", "no", "up", "down"
This operator converts explicitly (§6) the value designated by unary-expression to the
type
designated by type-literal. If type-literal is other than void, the type of the result is
the
named type, and the value is the value after conversion. If type-literal is void, no
object is
written to the pipeline and there is no result.
When an expression of any type is cast to that same type, the resulting type and value is
the
unary-expression's type and value.
This operator is right associative.
Examples:
PowerShell
Syntax
array-literal-expression:
unary-expression
Description:
The binary comma operator creates a 1-dimensional array whose elements are the
values designated by
its operands, in lexical order. The array has unconstrained type.
Examples:
PowerShell
2,4,6,"red",$null,$true # Length 6
The addition of grouping parentheses to certain binary comma expressions does not
document the
default precedence; instead, it changes the result.
Syntax
range-expression:
array-literal-expression
array-literal-expression
Description:
Conceptually, this operator is a shortcut for the corresponding binary comma operator
sequence. For
example, the range 5..8 can also be generated using 5,6,7,8 . However,
if an ascending or
descending sequence is needed without having an array, an
implementation may avoid generating an
actual array. For example, in foreach ($i in
1..5) { ... } , no array need be created.
Examples:
PowerShell
16..16 # sequence of 1
$x = 1.5
Syntax
format-expression:
range-expression
format-operator:
dash f
dash:
- (U+002D)
Description:
A format specification string may contain zero or more format specifications each
having the
following form:
{N [ ,M ][ : FormatString ]}
Examples:
PowerShell
`$i` = 10; $j = 12
">{0,3:000}<" -f 5 # >005<
$format = ">{0:x8}<"
Syntax
multiplicative-expression:
format-expression
7.6.1 Multiplication
Description:
The result of the multiplication operator * is the product of the values designated by
the two
operands after the usual arithmetic conversions (§6.15) have been applied.
Examples:
PowerShell
Examples:
PowerShell
When the left operand designates an array the binary * operator creates a new
unconstrained
1‑dimensional array that contains the value designated by the left
operand replicated the number of
times designated by the value of the right operand as
converted to integer type (§6.4). A
replication count of zero results in an array of length
1. If the left operand designates a
multidimensional array, it is flattened (§9.12) before
being used.
Examples:
PowerShell
7.6.4 Division
Description:
The result of the division operator / is the quotient when the value designated by the
left
operand is divided by the value designated by the right operand after the usual
arithmetic
conversions (§6.15) have been applied.
Examples:
PowerShell
7.6.5 Remainder
Description:
The result of the remainder operator % is the remainder when the value designated by
the left
operand is divided by the value designated by the right operand after the usual
arithmetic
conversions (§6.15) have been applied.
Examples:
PowerShell
10 % 3 # int result 1
Syntax
additive-expression:
multiplicative-expression
7.7.1 Addition
Description:
The result of the addition operator + is the sum of the values designated by the two
operands
after the usual arithmetic conversions (§6.15) have been applied.
Examples:
PowerShell
When the left operand designates a string the binary + operator creates a new string
that contains
the value designated by the left operand followed immediately by the
value(s) designated by the
right operand as converted to type string (§6.8).
Examples:
PowerShell
When the left operand designates an array the binary + operator creates a new
unconstrained
1‑dimensional array that contains the elements designated by the left
operand followed immediately
by the value(s) designated by the right operand.
Multidimensional arrays present in either operand
are flattened (§9.12) before being
used.
Examples:
PowerShell
When both operands designate Hashtables the binary + operator creates a new
Hashtable that
contains the elements designated by the left operand followed
immediately by the elements designated
by the right operand.
Examples:
PowerShell
7.7.5 Subtraction
Description:
The result of the subtraction operator - is the difference when the value designated by
the right
operand is subtracted from the value designated by the left operand after the
usual arithmetic
conversions (§6.15) have been applied.
Examples:
PowerShell
Syntax
comparison-operator: one of
dash:
- (U+002D)
Description:
The type of the value designated by the left operand determines how the value
designated by the
right operand is converted (§6), if necessary, before the comparison is
done.
Some comparison-operators (written here as -op) have two variants, one that is case
sensitive
(-cop), and one that is not (-iop). The -op version is equivalent to -iop. Case
sensitivity
is meaningful only with comparisons of values of type string. In non-string
comparison contexts, the
two variants behave the same.
There are two equality operators: equality ( -eq ) and inequality ( -ne ); and four relational
operators: less-than ( -lt ), less-than-or-equal-to ( -le ), greater-than ( -gt ), and
greater-
than-or-equal-to ( -ge ). Each of these has two variants (§7.8).
For two strings to compare equal, they must have the same length and contents, and
letter case, if
appropriate.
If the value designated by the left operand is not a collection, the result has type bool .
Otherwise, the result is a possibly empty unconstrained 1-dimensional array containing
the elements
of the collection that test True when compared to the value designated by
the right operand.
Examples:
PowerShell
The containment operators return a result of type bool that indicates whether a value
occurs (or
does not occur) at least once in the elements of an array. With -contains and
‑notcontains , the
value is designated by the right operand and the array is designated
by the left operand. With -in
and -notin , the operands are reversed. The value is
designated by the left operand and the array
is designated by the right operand.
For the purposes of these operators, if the array operand has a scalar value, the scalar
value is
treated as an array of one element.
Examples:
PowerShell
The type operator -is tests whether the value designated by the left operand has the
type, or is
derived from a type that has the type, designated by the right operand. The
right operand must
designate a type or a value that can be converted to a type (such as
a string that names a type).
The type of the result is bool . The type operator -isnot
returns the logical negation of the
corresponding -is form.
The type operator -as attempts to convert the value designated by the left operand to
the type
designated by the right operand. The right operand must designate a type or a
value that can be
converted to a type (such as a string that names a type). If the
conversion fails, $null is
returned; otherwise, the converted value is returned and the
return type of that result is the
runtime type of the converted value.
Examples:
PowerShell
$t = [int]
$a -isnot $t # False
$x = [int[]](10,20)
$x = [double]
Description:
If the left operand does not designate a collection, the result has type bool . Otherwise,
the
result is a possibly empty unconstrained 1-dimensional array containing the
elements of the
collection that test True when compared to the value designated by the
right operand. The right
operand may designate a string that contains wildcard
expressions (§3.15). These operators have
two variants (§7.8).
Examples:
PowerShell
"Hello" -like "h*" # True, starts with h
If the left operand does not designate a collection, the result has type bool and if that
result
is $true , the elements of the Hashtable $matches are set to the strings that match
(or
do-not-match) the value designated by the right operand. Otherwise, the result is a
possibly empty
unconstrained 1-dimensional array containing the elements of the
collection that test True when
compared to the value designated by the right operand,
and $matches is not set. The right operand
may designate a string that contains regular
expressions (§3.16), in which case, it is referred
to as a pattern. These operators have two
variants (§7.8).
Examples:
PowerShell
0/"Hello"
The -replace operator allows text replacement in one or more strings designated by
the left
operand using the values designated by the right operand. This operator has
two variants
(§7.8). The right operand has one of the following forms:
The string to be located, which may contain regular expressions (§3.16). In this
case, the
replacement string is implicitly "".
An array of 2 objects containing the string to be located, followed by the
replacement string.
If the left operand designates a string, the result has type string. If the left operand
designates
a 1‑dimensional array of string, the result is an unconstrained 1-dimensional
array, whose length is
the same as for left operand's array, containing the input strings
after replacement has completed.
Examples:
PowerShell
The binary -join operator produces a string that is the concatenation of the value of
one or more
objects designated by the left operand after having been converted to
string (§6.7), if
necessary. The string designated by the right operand is used to separate
the (possibly empty)
values in the resulting string.
Examples:
PowerShell
(10, 20, 30) -join "\|" # result is "10\|20\|30"
The binary -split operator splits one or more strings designated by the left operand,
returning
their subparts in a constrained 1-dimensional array of string. This operator has
two variants
(§7.8). The left operand can designate a scalar value or an array of strings.
The right operand
has one of the following forms:
A delimiter string
An array of 2 objects containing a delimiter string followed by a numeric split count
An array of 3 objects containing a delimiter string, a numeric split count, and an
options
string
A script block
An array of 2 objects containing a script block followed by a numeric split count
The delimiter string may contain regular expressions (§3.16). It is used to locate subparts
with
the input strings. The delimiter is not included in the resulting strings. If the left
operand
designates an empty string, that results in an empty string element. If the
delimiter string is an
empty string, it is found at every character position in the input
strings.
By default, all subparts of the input strings are placed into the result as separate
elements;
however, the split count can be used to modify this behavior. If that count is
negative, zero, or
greater than or equal to the number of subparts in an input string,
each subpart goes into a
separate element. If that count is less than the number of
subparts in the input string, there are
count elements in the result, with the final element
containing all of the subparts beyond the first
count - 1 subparts.
An options string contains zero or more option names with each adjacent pair separated
by a comma.
Leading, trailing, and embedded white space is ignored. Option names
may be in any order and are
case-sensitive.
If an options string contains the option name SimpleMatch, it may also contain the
option name
IgnoreCase. If an options string contains the option name RegexMatch or
it does not contain
either RegexMatch or SimpleMatch, it may contain any option name
except SimpleMatch.
However, it must not contain both Multiline and Singleline.
Here is the set of option names:
Option Description
ExplicitCapture Ignores non-named match groups so that only explicit capture groups
are returned in the result list.
IgnorePatternWhitespace Ignores unescaped white space and comments marked with the
number sign (#).
Multiline This mode recognizes the start and end of lines and strings. The
default mode is Singleline.
RegexMatch Use regular expression matching to evaluate the delimiter. This is the
default.
Singleline This mode recognizes only the start and end of strings. It is the
default mode.
The script block (§7.1.8) specifies the rules for determining the delimiter, and must
evaluate
to type bool.
Examples:
PowerShell
"abc","de" -split "" # 9 strings: "" "a" "b" "c" "" ""
"d" "e" ""
7.8.4.6 Submatches
The pattern being matched by -match , -notmatch , and -replace may contain subparts
(called
submatches) delimited by parentheses. Consider the following example:
The result is $true and key 0 of $matches contains "red", that part of the string
designated by
the left operand that exactly matched the pattern designated by the right
operand.
As before, key 0 contains "red"; however, key 1 also contains "red", which is that part of
the
string designated by the left operand that exactly matched the submatch.
Again, key 0 contains "red". Key 1 contains "re", key 2 contains "r", and key 3 contains
"d". The
key/value pairs are in matching order from left-to-right in the pattern, with
longer string matches
preceding shorter ones.
In the case of -replace , the replacement text can access the submatches via names of
the form
$n , where the first match is $1 , the second is $3 , and so on. For example,
PowerShell
The shift left operator shifts the left operand left by a number of bits computed as
described
below. The low-order empty bit positions are set to zero.
The shift right operator shifts the left operand right by a number of bits computed as
described
below. The low-order bits of the left operand are discarded, the remaining
bits shifted right. When
the left operand is a signed value, the high-order empty bit
positions are set to zero if the left
operand is non-negative and set to one if the left
operand is negative. When the left operand is an
unsigned value, the high-order empty
bit positions are set to zero.
When the left operand has type int, the shift count is given by the low-order five bits of
the right
operand. When the right operand has type long, the shift count is given by the
low-order six bits of
the right operand.
Examples:
PowerShell
Syntax
bitwise-expression:
comparison-expression
Description:
The bitwise AND operator -band , the bitwise OR operator -bor , and the bitwise XOR
operator -bxor
convert the values designated by their operands to integer types, if
necessary, using the usual
arithmetic conversions (§6.15). After conversion, if both values
have type int that is the type
of the result. Otherwise, if both values have type long, that
is the type of the result. If one
value has type int and the other has type long, the type of
the result is long. Otherwise, the
expression is ill formed. The result is the bitwise AND,
bitwise OR, or bitwise XOR, respectively,
of the possibly converted operand values.
These operators are left associative. They are commutative if neither operand contains a
side
effect.
Examples:
PowerShell
Syntax
logical-expression:
bitwise-expression
Description:
The logical AND operator -and converts the values designated by its operands to bool ,
if
necessary (§6.2). The result is the logical AND of the possibly converted operand
values, and
has type bool . If the left operand evaluates to False the right operand is not
evaluated.
The logical OR operator -or converts the values designated by its operands to bool , if
necessary
(§6.2). The result is the logical OR of the possibly converted operand values,
and has type
bool . If the left operand evaluates to True the right operand is not
evaluated.
The logical XOR operator -xor converts the values designated by its operands to bool
(§6.2). The result is the logical XOR of the possibly converted operand values, and has
type
bool .
Examples:
PowerShell
$j = 10
$k = 20
($j -gt 5) -and (++$k -lt 15) # True -and False -> False
($j -gt 5) -and ($k -le 21) # True -and True -> True
($j++ -gt 5) -and ($j -le 10) # True -and False -> False
($j -eq 5) -and (++$k -gt 15) # False -and True -> False
$j = 10
$k = 20
($j++ -gt 5) -or (++$k -lt 15) # True -or False -> True
($j -eq 10) -or ($k -gt 15) # False -or True -> True
($j -eq 10) -or (++$k -le 20) # False -or False -> False
$j = 10
$k = 20
($j++ -gt 5) -xor (++$k -lt 15) # True -xor False -> True
($j -eq 10) -xor ($k -gt 15) # False -xor True -> True
($j -gt 10) -xor (++$k -le 25) # True -xor True -> False
Syntax
assignment-expression:
assignment-operator: *one of
= dash = += *= /= %=
Description:
An assignment operator stores a value in the writable location designated by expression.
For a
discussion of assignment-operator = see §7.11.1. For a discussion of all other
assignment-operators see §7.11.2.
An assignment expression has the value designated by expression after the assignment
has taken
place; however, that assignment expression does not itself designate a
writable location. If
expression is type-constrained (§5.3), the type used in that constraint
is the type of the
result; otherwise, the type of the result is the type after the usual
arithmetic conversions
(§6.15) have been applied.
In simple assignment ( = ), the value designated by statement replaces the value stored in
the
writable location designated by expression. However, if expression designates a non-
existent key
in a Hashtable, that key is added to the Hashtable with an associated value
of the value designated
by statement.
Examples:
PowerShell
$h = @{}
A compound assignment has the form E1 op= E2 , and is equivalent to the simple
assignment
expression E1 = E1 op (E2) except that in the compound assignment case
the expression E1 is
evaluated only once. If expression is type-constrained (§5.3), the
type used in that
constraint is the type of the result; otherwise, the type of the result is
determined by op. For
*= , see §7.6.1, §7.6.2, §7.6.3; for /= , see §7.6.4; for %= , see §7.6.5;
for += , see §7.7.1, §7.7.2, §7.7.3; for -= , see §7.7.5.
7 Note
An operand designating an unconstrained value of numeric type may have its type
changed by an
assignment operator when the result is stored.
Examples:
PowerShell
$i = 0
$b = 10,20,30
Syntax
pipeline:
assignment-expression
redirections:
redirection
redirections redirection
redirection:
merging-redirection-operator
file-redirection-operator redirected-file-name
redirected-file-name:
command-argument
primary-expression
file-redirection-operator: one of
> >> 2> 2>> 3> 3>> 4> 4>>
merging-redirection-operator: one of
Description:
The redirection operator > takes the standard output from the pipeline and redirects it
to the
location designated by redirected-file-name, overwriting that location's current
contents.
The redirection operator >> takes the standard output from the pipeline and redirects it
to the
location designated by redirected-file-name, appending to that location's current
contents, if
any. If that location does not exist, it is created.
The redirection operator with the form n> takes the output of stream n from the
pipeline and
redirects it to the location designated by redirected-file-name, overwriting
that location's
current contents.
The redirection operator with the form n>> takes the output of stream n from the
pipeline and
redirects it to the location designated by redirected-file-name, appending
to that location's
current contents, if any. If that location does not exist, it is created.
The redirection operator with the form m>&n writes output from stream m to the same
location as
stream n.
Stream Description
* Standard output, error output, warning output, verbose output, and debug output
streams
The redirection operators 1>&2 , 6> , 6>> and < are reserved for future use.
Ordinarily, the value of an expression containing a top-level side effect is not written to
the
pipeline unless that expression is enclosed in a pair of parentheses. However, if such
an expression
is the left operand of an operator that redirects standard output, the value
is written.
Examples:
PowerShell
8. Statements
Article • 05/16/2022
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
Syntax
statement-block:
statement-list:
statement
statement-list statement
statement:
if-statement
label~opt~ labeled-statement
function-statement
flow-control-statement statement-terminator
trap-statement
try-statement
data-statement
inlinescript-statement
parallel-statement
sequence-statement
pipeline statement-terminator
statement-terminator:
new-line-character
Description:
Syntax
labeled-statement:
switch-statement
foreach-statement
for-statement
while-statement
do-statement
Description:
White space is not permitted between the colon ( : ) and the token that follows it.
Examples:
PowerShell
# ...
:labelA
:labelB
:labelC
# ...
There are no iterations of the loop and nothing is written to the pipeline. The value of
the
statement is $null .
Although the loop iterates five times nothing is written to the pipeline. The value of the
statement
is $null.
The loop iterates five times each time writing to the pipeline the int value $i . The
value of
the statement is object[] of Length 5.
Although the loop iterates five times nothing is written to the pipeline. The value of the
statement
is $null .
The loop iterates five times with each value being written to the pipeline. The value of
the
statement is object[] of Length 5.
The loop iterates once. The value of the statement is the int with value 2.
PowerShell
$i = 1
if ($i -band 1) {
Syntax
pipeline:
assignment-expression
assignment-expression:
pipeline-tail:
| new-lines~opt~ command
command:
command-name command-elements~opt~
command-invocation-operator: one of
& .
command-module:
primary-expression
command-name:
generic-token
generic-token-with-subexpr
generic-token-with-subexpr:
generic-token-with-subexpr-start statement-list~opt~ )
command-namecommand-name-expr:
command-name
primary-expressioncommand-elements:
command-element
command-elements command-element
command-element:
command-parameter
command-argument
redirection
command-argument:
command-name-expr
verbatim-command-argument:
--% verbatim-command-argument-chars
Description:
An argument that is not an expression, but which contains arbitrary text without
unescaped white
space, is treated as though it were double quoted. Letter case is
preserved.
Text inside quotes allows leading, trailing, and embedded white space to be
included in the
argument's value. [Note: The presence of whitespace in a quoted
argument does not turn a single
argument into multiple arguments. end note]
To pass an argument that looks like a switch parameter (§2.3.4) but is not intended
as such,
enclose that argument in quotes.
When specifying an argument that matches a parameter having the [switch] type
constraint
(§8.10.5), the presence of the argument name on its own causes that
parameter to be set to
$true . However, the parameter's value can be set explicitly
by appending a suffix to the
argument. For example, given a type constrained
parameter p, an argument of -p:$true sets p to
True, while -p:$false sets p to
False.
An argument of -- indicates that all arguments following it are to be passed in
their actual
form as though double quotes were placed around them.
An argument of --% indicates that all arguments following it are to be passed with
minimal
parsing and processing. This argument is called the verbatim parameter.
Arguments after the
verbatim parameter are not PowerShell expressions even if
they are syntactically valid PowerShell
expressions.
If the command type is Application, the parameter --% is not passed to the command.
The arguments
after --% have any environment variables (strings surrounded by % )
expanded. For example:
PowerShell
For information about parameter binding see §8.14. For information about name lookup
see
§3.8.
Once argument processing has been completed, the command is invoked. If the invoked
command
terminates normally (§8.5.4), control reverts to the point in the script or
function immediately
following the command invocation. For a description of the
behavior on abnormal termination see
break (§8.5.1), continue (§8.5.2), throw (§8.5.3),
exit (§8.5.5), try
(§8.7), and trap (§8.8).
PowerShell
Get-Factorial 5
& Get-Factorial 5
& "Get-Factorial" 5
Direct and indirect recursive function calls are permitted. For example,
PowerShell
function Get-Power([int]$x, [int]$y) {
else { return 1 }
Examples:
PowerShell
Syntax
if-statement:
elseif-clauses~opt~ else-clause~opt~
elseif-clauses:
elseif-clause
elseif-clauses elseif-clause
elseif-clause:
else-clause:
Description:
The pipeline controlling expressions must have type bool or be implicitly convertible to
that
type. The else-clause is optional. There may be zero or more elseif-clauses.
If the top-level pipeline tests True, then its statement-block is executed and execution of
the
statement terminates. Otherwise, if an elseif-clause is present, if its pipeline tests
True,
then its statement-block is executed and execution of the statement terminates.
Otherwise, if an
else-clause is present, its statement-block is executed.
Examples:
PowerShell
$grade = 92
Syntax
while-statement:
while-condition:
new-lines~opt~ pipeline
Description:
Examples:
PowerShell
$i = 1
++$i
Syntax
do-statement:
while-condition:
new-lines~opt~ pipeline
Description:
Examples:
PowerShell
$i = 1
do {
$i = 1
do {
Syntax
for-statement:
for new-lines~opt~ (
new-lines~opt~ for-iterator~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-condition~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~
new-lines~opt~ ) statement-block
for-initializer:
pipeline
for-condition:
pipeline
for-iterator:
pipeline
Description:
The controlling expression for-condition must have type bool or be implicitly convertible
to that
type. The loop body, which consists of statement-block, is executed repeatedly
while the
controlling expression tests True. The controlling expression is evaluated
before each execution of
the loop body.
Expression for-iterator is evaluated after each execution of the loop body. Expression
for-
iterator is evaluated for its side effects only; any value it produces is discarded and is not
written to the pipeline.
Examples:
PowerShell
$i = 5
--$i
Syntax
foreach-statement:
new-lines~opt~ ) statement-block
foreach-parameter:
-parallel
Description:
The loop body, which consists of statement-block, is executed for each element
designated by the
variable variable in the collection designated by pipeline. The scope
of variable is not
limited to the foreach statement. As such, it retains its final value after
the loop body has
finished executing. If pipeline designates a scalar (excluding the value
$null) instead of a
collection, that scalar is treated as a collection of one element. If
pipeline designates the
value $null , pipeline is treated as a collection of zero elements.
Every foreach statement has its own enumerator, $foreach (§2.3.2.2, §4.5.16), which
exists
only while that loop is executing.
Examples:
PowerShell
...
...
...
Syntax
flow-control-statement:
break label-expression~opt~
continue label-expression~opt~
throw pipeline~opt~
return pipeline~opt~
exit pipeline~opt~
label-expression:
simple-name
unary-expression
Description:
A labeled break need not be resolved in any local scope; the search for a matching label
may
continue up the calling stack even across script and function-call boundaries. If no
matching label
is found, the current command invocation is terminated.
The name of the label designated by label-expression need not have a constant value.
Examples:
PowerShell
$i = 1
++$i
$lab = "go_here"
:go_here
:labelA
:labelB
:labelC
An unlabeled continue statement within a loop terminates execution of the current loop
and
transfers control to the closing brace of the smallest enclosing iteration statement
(§8.4). An
unlabeled continue statement within a switch terminates execution of the
current switch
iteration and transfers control to the smallest enclosing switch 's switch-
condition (§8.6).
A labeled continue need not be resolved in any local scope; the search for a matching
label may
continue up the calling stack even across script and function-call boundaries.
If no matching
label is found, the current command invocation is terminated.
The name of the label designated by label-expression need not have a constant value.
Examples:
PowerShell
$i = 1
while (...) {
...
if (...) {
...
$lab = "go_here"
:go_here
if (...) {
:labelA
:labelB
:labelC
If pipeline is omitted and the throw statement is not in a catch-clause, the behavior is
implementation defined. If pipeline is present and the throw statement is in a catch-
clause, the
exception that was caught by that catch-clause is re-thrown after any finally-
clause associated
with the catch-clause is executed.
Examples:
PowerShell
throw
throw 100
If pipeline is omitted and the throw statement is not from within a catch-clause, the text
"ScriptHalted" is written to the pipeline, and the type of the exception raised is
System.Management.Automation.RuntimeException .
exception as a
System.Management.Automation.ErrorRecord object (accessible via $_ ).
Example 1: throw 123 results in an exception of type RuntimeException. From within the
catch
block, $_.TargetObject contains the object wrapped inside, in this case, a
System.Int32 with
value 123.
10 and 20.
The return statement writes to the pipeline the value(s) designated by pipeline, if any,
and
returns control to the function or script's caller. A function or script may have zero
or more
return statements.
If execution reaches the closing brace of a function an implied return without pipeline is
assumed.
PowerShell
if ($v -eq 1) {
PowerShell
function Test {
# ...
# ...
The caller to Test gets back an unconstrained 1-dimensional array of three elements.
The exit statement terminates the current script and returns control and an exit code to
the host
environment or the calling script. If pipeline is provided, the value it designates
is converted
to int, if necessary. If no such conversion exists, or if pipeline is omitted, the
int value zero
is returned.
Examples:
PowerShell
switch-statement:
switch-parameters:
switch-parameter
switch-parameters switch-parameter
switch-parameter:
-regex
-wildcard
-exact
-casesensitive
-parallel
switch-condition:
switch-filename:
command-argument
primary-expression
switch-body:
switch-clauses:
switch-clause
switch-clauses switch-clause
switch-clause:
switch-clause-condition:
command-argument
primary-expression
Description:
A switch must contain one or more switch-clauses, each starting with a pattern (a non-
default
switch clause), or the keyword default (a default switch clause). A switch must
contain zero or
one default switch clauses, and zero or more non-default switch
clauses. Switch clauses may be
written in any order.
Multiple patterns may have the same value. A pattern need not be a literal, and a switch
may have
patterns with different types.
If the value of switch-condition matches a pattern value, that pattern's statement-block is
executed. If multiple pattern values match the value of switch-condition, each matching
pattern's
statement-block is executed, in lexical order, unless any of those statement-
blocks contains a
break statement (§8.5.1).
If the value of switch-condition does not match any pattern value, if a default switch
clause
exists, its statement-block is executed; otherwise, pattern matching for that
switch-condition
is terminated.
Switches may be nested, with each switch having its own set of switch clauses. In such
instances, a
switch clause belongs to the innermost switch currently in scope.
A pattern may contain wildcard characters (§3.15), in which case, wildcard string
comparisons
are performed, but only if the switch-parameter -wildcard is present. By
default, the comparison
is case-insensitive.
A pattern may contain a regular expression (§3.16), in which case, regular expression
string
comparisons are performed, but only if the switch-parameter -regex is present. By
default, the
comparison is case-insensitive. If -regex is present and a pattern is
matched, $matches is
defined in the switch-clause statement-block for that pattern.
If conflicting switch-parameters are specified, the lexically final one prevails. The
presence of
‑exact disables -regex and -wildcard ; it has no affect on ‑case , however.
A switch statement may have a label, and it may contain labeled and unlabeled break
(§8.5.1) and
continue (§8.5.2) statements.
Examples:
PowerShell
++$charCount
switch ($s[$i]) {
"`n" { ++$lineCount }
"`f" { ++$pageCount }
"`t" { }
" " { }
default { ++$otherCount }
a* { "a*, $_" }
^a* { "a*" }
^A* { "A*" }
{ $_ -band 1 } { "Odd" }
default { "default" }
Syntax
try-statement:
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
statement-block
catch-type-list:
new-lines~opt~ type-literal
type-literalfinally-clause:
Description:
The try statement provides a mechanism for catching exceptions that occur during
execution of a
block. The try statement also provides the ability to specify a block of
code that is always
executed when control leaves the try statement. The process of
raising an exception via the throw
statement is described in §8.5.3.
A try block is the statement-block associated with the try statement. A catch block is the
statement-block associated with a catch-clause. A finally block is the statement-block
associated with a finally-clause.
Although catch-clauses and finally-clause are optional, at least one of them must be
present.
If the try block of S encloses the throw point and if S has one or more catch
clauses, the
catch clauses are examined in lexical order to locate a suitable
handler for the exception. The
first catch clause that specifies the exception type
or a base type of the exception type is
considered a match. A general catch
clause is considered a match for any exception type. If a
matching catch clause
is located, the exception processing is completed by transferring control
to the
block of that catch clause. Within a matching catch clause, the variable $_
contains a
description of the current exception.
Otherwise, if the try block or a catch block of S encloses the throw point and if
S has
a finally block, control is transferred to the finally block. If the finally
block throws
another exception, processing of the current exception is
terminated. Otherwise, when control
reaches the end of the finally block,
processing of the current exception is continued.
If an exception handler was not located in the current scope, the steps above are
then repeated
for the enclosing scope with a throw point corresponding to the
statement from which the current
scope was invoked.
To prevent unreachable catch clauses in a try block, a catch clause may not specify an
exception
type that is equal to or derived from a type that was specified in an earlier
catch clause within
that same try block.
The statements of a finally block are always executed when control leaves a try
statement. This
is true whether the control transfer occurs as a result of normal
execution, as a result of
executing a break , continue , or return statement, or as a result
of an exception being thrown
out of the try statement.
try statements can co-exist with trap statements; see §8.8 for details.
Examples:
PowerShell
$a = new-object 'int[]' 10
$i = 20 # out-of-bounds subscript
while ($true) {
try {
$a[$i] = 10
break
catch [IndexOutOfRangeException] {
$i = 5
catch {
finally {
# ...
Syntax
trap-statement:
Description:
A trap statement with and without type-literal is analogous to a catch block (§8.7) with
and without catch-type-list, respectively, except that a trap statement can trap only one
type
at a time.
Multiple trap statements can be defined in the same statement-block, and their order of
definition is irrelevant. If two trap statements with the same type-literal are defined in
the
same scope, the lexically first one is used to process an exception of matching type.
Unlike a catch block, a trap statement matches an exception type exactly; no derived
type
matching is performed.
If a trap 's statement-body exits normally, by default, an error object is written to the
error
stream, the exception is considered handled, and execution continues with the
statement immediately
following the one in the scope containing the trap statement
that made the exception visible. The
cause of the exception might be in a command
called by the command containing the trap statement.
If the final statement executed in a trap 's statement-body is continue (§8.5.2), the
writing
of the error object to the error stream is suppressed, and execution continues
with the statement
immediately following the one in the scope containing the trap
statement that made the exception
visible. If the final statement executed in a trap 's
statement-body is break (§8.5.1), the
writing of the error object to the error stream is
suppressed, and the exception is re-thrown.
Within a trap statement the variable $_ contains a description of the current error.
Consider the case in which an exception raised from within a try block does not have a
matching
catch block, but a matching trap statement exists at a higher block level.
After the try
block's finally clause is executed, the trap statement gets control even if
any parent scope has a
matching catch block. If a trap statement is defined within the
try block itself, and that
try block has a matching catch block, the trap statement
gets control.
Examples:
In the following example, the error object is written and execution continues with the
statement
immediately following the one that caused the trap; that is, "Done" is written
to the pipeline.
PowerShell
$j = 0; $v = 10/$j; "Done"
trap { $j = 2 }
In the following example, the writing of the error object is suppressed and execution
continues with
the statement immediately following the one that caused the trap; that
is, "Done" is written to the
pipeline.
PowerShell
$j = 0; $v = 10/$j; "Done"
trap { $j = 2; continue }
In the following example, the writing of the error object is suppressed and the exception
is
re-thrown.
PowerShell
$j = 0; $v = 10/$j; "Done"
trap { $j = 2; break }
In the following example, the trap and exception-generating statements are in the same
scope. After
the exception is caught and handled, execution resumes with writing 1 to
the pipeline.
PowerShell
In the following example, the trap and exception-generating statements are in different
scopes.
After the exception is caught and handled, execution resumes with writing 2
(not 1) to the pipeline.
PowerShell
data-statement:
data-name:
simple-name
data-commands-allowed:
data-commands-list:
new-lines~opt~ data-command
data-command:
command-name-expr
Description:
A data statement creates a data section, keeping that section's data separate from the
code. This
separation supports facilities like separate string resource files for text, such
as error messages
and Help strings. It also helps support internationalization by making
it easier to isolate, locate,
and process strings that will be translated into different
languages.
Comments
Pipelines
Statements separated by semicolons ( ; )
Literals
Calls to the ConvertFrom-StringData
cmdlet
Any other cmdlets identified via the supportedcommand parameter
PowerShell
Consider the following example, in which the data section contains a ConvertFrom-
StringData
command that converts the strings into a hash table, whose value is
assigned to $messages .
PowerShell
$messages = data {
Greeting = Hello
Yes = yes
No = no
'@
The keys and values of the hash table are accessed using $messages.Greeting ,
$messages.Yes , and
$messages.No , respectively.
PowerShell
$messages = data {
Yes = ja
No = nein
"@
$messagesS = data {
Yes = sí
No = no
"@
If dataname is present, it names the variable (without using a leading $ ) into which the
value
of the data statement is to be stored. Specifically, $name = data { ... } is
equivalent to
data name { ... } .
Syntax
function-statement:
function-name:
command-argument
command-argument:
command-name-expr
function-parameter-declaration:
parameter-list:
script-parameter
script-parameter:
script-block:
param-block:
( parameter-list~opt~ new-lines~opt~ )
parameter-list:
script-parameter
script-parameter-default:
script-block-body:
named-block-list
statement-list
named-block-list:
named-block
named-block-list named-block
named-block:
block-name: one of
Description:
A function definition specifies the name of the function, filter, or workflow being defined
and
the names of its parameters, if any. It also contains zero or more statements that are
executed to
achieve that function's purpose.
A filter with no named blocks (§8.10.7) is equivalent to a function with a process block,
but
without any begin block or end block.
PowerShell
PowerShell
$result = 1
$result *= $base
return $result
This function has two parameters, $base and $exponent . It also contains a set of
statements
that, for non-negative exponent values, computes $base^$exponent^ and
returns the result to
Get-Power 's caller.
When a script, function, or filter begins execution, each parameter is initialized to its
corresponding argument's value. If there is no corresponding argument and a default
value
(§8.10.4) is supplied, that value is used; otherwise, the value $null is used. As such,
each
parameter is a new variable just as if it was initialized by assignment at the start of
the
script-block.
If a script-parameter contains a type constraint (such as [long] and [int] above), the
value
of the corresponding argument is converted to that type, if necessary; otherwise,
no conversion
occurs.
When a script, function, or filter begins execution, variable $args is defined inside it as
an
unconstrained 1-dimensional array, which contains all arguments not bound by name
or position, in
lexical order.
PowerShell
F -b 3 -d 5 2 4 # $a is 2, $b is 3, $c is 4, $d is 5, $args Length 0
F -a 2 -d 3 4 5 # $a is 2, $b is 4, $c is 5, $d is 3, $args Length 0
F 2 3 4 5 -c 7 -a 1 # $a is 1, $b is 2, $c is 7, $d is 3, $args Length 2
PowerShell
PowerShell
PowerShell
function Get-Square1 {
$i * $i
The statements in a begin block (i.e.; one marked with the keyword begin) are executed
once,
before the first pipeline object is delivered.
The statements in a process block (i.e.; one marked with the keyword process) are
executed for
each pipeline object delivered. ( $_ provides access to the current object
being processed from the
input collection coming from the pipeline.) This means that if
a collection of zero elements is sent
via the pipeline, the process block is not executed
at all. However, if the script or function is
called outside a pipeline context, this block is
executed exactly once, and $_ is set to $null ,
as there is no current collection object.
The statements in an end block (i.e.; one marked with the keyword end) are executed
once, after
the last pipeline object has been delivered.
Dynamic parameters are parameters of a cmdlet, function, filter, or script that are
available under
certain conditions only. One such case is the Encoding parameter of the
Set-Item cmdlet.
In the statement-block, use an if statement to specify the conditions under which the
parameter is
available in the function. Use the New-Object cmdlet
to create an object of
an implementation-defined type to represent the parameter, and specify its
name. Also,
use New-Object to create an object of a different implementation-defined type to
represent the implementation-defined attributes of the parameter.
The following example shows a function with standard parameters called Name and
Path, and an
optional dynamic parameter named DP1. The DP1 parameter is in the PSet1
parameter set and
has a type of Int32 . The DP1 parameter is available in the Sample
function only when the value
of the Path parameter contains "HKLM:", indicating that it
is being used in the HKEY_LOCAL_MACHINE
registry drive.
PowerShell
function Sample {
DynamicParam {
$dynParam1 = New-Object
System.Management.Automation.RuntimeDefinedParameter("dp1", [Int32],
$attributeCollection)
$attributes = New-Object
System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = 'pset1'
$attributes.Mandatory = $false
$attributeCollection.Add($attributes)
$paramDictionary = New-Object
System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("dp1", $dynParam1)
return $paramDictionary
The type used to create an object to represent the attributes of the parameter is
System.Management.Automation.ParameterAttribute .
PowerShell
function FindStr2 {
PowerShell
[string[]] $ComputerName )
The one parameter, $ComputerName , has type string[] , it is required, and it takes input
from the
pipeline.
See §12.3.7 for a discussion of the Parameter attribute and for more examples.
Syntax
parallel-statement:
*parallel* statement-block
The parallel statement contains zero or more statements that are executed in an
implementation
defined manner.
Syntax
sequence-statement:
*sequence* statement-block
The sequence statement contains zero or more statements that are executed in an
implementation
defined manner.
Syntax
inlinescript-statement:
inlinescript statement-block
The inlinescript statement contains zero or more statements that are executed in an
implementation
defined manner.
Consider the following definition fragment for a function called Get-Power , and the calls
to it:
PowerShell
When a script, function, filter, or cmdlet is invoked, an argument can be bound to the
corresponding
parameter by name. This is done by using a parameter with argument,
which is an argument that is
the parameter's name with a leading dash (-), followed by
the associated value for that argument.
The parameter name used can have any case-
insensitive spelling and can use any prefix that uniquely
designates the corresponding
parameter. When choosing parameter names, avoid using the names of the
common
parameters.
PowerShell
PowerShell
must use parameters -side1 and -side2 , as there is no prefix that uniquely designates
the
parameter.
The same parameter name cannot be used multiple times with or without different
associated argument
values.
Parameters can have attributes (§12). For information about the individual attributes see
the
sections within §12.3. For information about parameter sets see §12.3.7.
A script, function, filter, or cmdlet can receive arguments via the invocation command
line, from
the pipeline, or from both. Here are the steps, in order, for resolving
parameter binding:
Several of these steps involve conversion, as described in §6. However, the set of
conversions
used in binding is not exactly the same as that used in language
conversions. Specifically,
Although the value $null can be cast to bool, $null cannot be bound to bool .
When the value $null is passed to a switch parameter for a cmdlet, it is treated as
if $true
was passed. However, when passed to a switch parameter for a function, it
is treated as if
$false was passed.
Parameters of type bool or switch can only bind to numeric or bool arguments.
If the parameter type is not a collection, but the argument is some sort of
collection, no
conversion is attempted unless the parameter type is object or
PsObject. (The main point of this
restriction is to disallow converting a collection to
a string parameter.) Otherwise, the usual
conversions are attempted.
PowerShell
function Test {
[CmdletBinding(DefaultParameterSetname = "SetB")]
[decimal]$dec,
[int]$in
$PsCmdlet.ParameterSetName
9. Arrays
Article • 12/09/2022
9.1 Introduction
PowerShell supports arrays of one or more dimensions with each dimension having zero
or more
elements. Within a dimension, elements are numbered in ascending integer
order starting at zero.
Any individual element can be accessed via the array subscript
operator [] (§7.1.4). The
number of dimensions in an array is called its rank.
An element can contain a value of any type including an array type. An array having one
or more
elements whose values are of any array type is called a jagged array. A
multidimensional array
has multiple dimensions, in which case, the number of elements
in each row of a dimension is the
same. An element of a jagged array may contain a
multidimensional array, and vice versa.
By default, an array is polymorphic; i.e., its elements do not need to all have the same
type. For
example,
PowerShell
$items[1] = -2.345
$items[2] = "green"
$a[0,0] = 10
$a[0,1] = $false
$a[1,0] = "red"
$a[1,1] = $null
A 1-dimensional array has type type[] , a 2-dimensional array has type type[,] , a 3-
dimensional
array has type type[,,] , and so on, where type is object for an
unconstrained type array, or the
constrained type for a constrained array (§9.4).
All array types are derived from the type Array (§4.3.2).
PowerShell
"`$values[$i] = $($values[$i])"
$e
Output
$values[0] = 10
$values[1] = 20
$values[2] = 30
10
False
red
10.50
The default initial value of any element not explicitly initialized is the default value for
that
element's type (that is, $false , zero, or $null ).
9.3 Array concatenation
Arrays of arbitrary type and length can be concatenated via the + and += operators,
both of
which result in the creation of a new unconstrained 1-dimensional array. The
existing arrays are
unchanged. See §7.7.3 for more information, and §9.4 for a discussion
of adding to an array
of constrained type.
PowerShell
The syntax for creating a multidimensional array requires the specification of a type, and
that type
becomes the constraint type for that array. However, by specifying type
object[] , there really is
no constraint as a value of any type can be assigned to an
element of an array of that type.
Concatenating two arrays (§7.7.3) always results in a new array that is unconstrained
even if
both arrays are constrained by the same type. For example,
PowerShell
PowerShell
Assignment of an array involves a shallow copy; that is, the variable assigned to refers to
the same
array, no copy of the array is made. For example,
PowerShell
$a = 10,20,30
">$a<"
">$b<"
">$a<"
">$a<"
Output
>10 20 30<
>10 20 30<
>6 20 30<
>6 20 30<
>8 20 30<
>6 20 30 40<
PowerShell
$list = $colors, (,7), (1.2, "yes") # parens in (,7) are redundant; they
">$($list[1][0])<"
">$($list[2][1])<"
>7<
>yes<
$list[1] refers to an array of 1 element, the integer 7, which is accessed via $list[1]
[0] , as
shown. Compare this with the following subtly different case:
PowerShell
">$($list[1])<"
Here, $list[1] refers to a scalar, the integer 7, which is accessed via $list[1] .
PowerShell
$x = [string[]]("red","green")
PowerShell
$a = [int[]](10,20,30)
$b = [int[]](0,1,2,3,4,5)
$a[1]->$b[1]
$a[2]->$b[4]
PowerShell
$a = New-Object 'int[,]' 3, 2
PowerShell
$a = "red",$true
$b[0,0] = 10
$b[0,1] = 20
$b[1,0] = 30
$b[1,1] = 40
$c = $a + $b
The array designated by $c contains the elements "red", $true , 10, 20, 30, and 40.
10. Hashtables
Article • 07/29/2021
Syntax:
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
Syntax
hash-literal-expression:
hash-literal-body:
hash-entry
hash-entry:
key-expression:
simple-name
unary-expression
statement-terminator:
new-line-character
10.1 Introduction
The type Hashtable represents a collection of key/value pair objects that supports
efficient
retrieval of a value when indexed by the key. Each key/value pair is an element,
which is stored
in some implementation-defined object type.
An element's key cannot be the null value. There are no restrictions on the type of a key
or value.
Duplicate keys are not supported.
Given a key/value pair object, the key and associated value can be obtained by using the
instance
properties Key and Value, respectively.
Given one or more keys, the corresponding value(s) can be accessed via the Hashtable
subscript
operator [] (§7.1.4.3).
All Hashtables have type Hashtable (§4.3.3).
The order of the keys in the collection returned by Keys is unspecified; however, it is the
same
order as the associated values in the collection returned by Values.
PowerShell
Hashtable elements are stored in an object of type DictionaryEntry, and the collections
PowerShell
PowerShell
$h2 = $h1
PowerShell
11. Modules
Article • 09/23/2022
11.1 Introduction
As stated in §3.14, a module is a self-contained reusable unit that allows PowerShell
code to be
partitioned, organized, and abstracted. A module can contain one or more
module members, which are
commands (such as cmdlets and functions) and items (such
as variables and aliases). The names of
these members can be kept private to the
module or they may be exported to the session into which
the module is imported.
There are three different module types: manifest, script, and binary. A manifest module is
a
file that contains information about a module, and controls certain aspects of that
module's use. A
script module is a PowerShell script file with a file extension of .psm1
instead of .ps1 . A
binary module contains class types that define cmdlets and providers.
Unlike script modules,
binary modules are written in compiled languages. Binary
modules are not covered by this
specification.
A binary module is a .NET assembly (i.e.; a DLL) that was compiled against the
PowerShell libraries.
Modules may nest; that is, one module may import another module. A module that has
associated
nested modules is a root module.
When modules are imported, the search path used to locate them is defined by the
environment
variable PSModulePath.
This module contains two functions, each of which has an alias. By default, all function
names, and
only function names are exported. However, once the cmdlet Export-
ModuleMember has been used to
export anything, then only those things exported
When a module is imported, its script file is executed. That process can be configured by
defining
one or more parameters in the script file, and passing in corresponding
arguments via the
ArgumentList parameter of Import-Module .
Consider the following script that uses these functions and aliases defined in §11.2:
PowerShell
Importing a module causes a name conflict when commands or items in the module
have the same names
as commands or items in the session. A name conflict results in a
name being hidden or replaced. The
Prefix parameter of Import-Module can be used to
avoid naming conflicts. Also, the Alias,
Cmdlet, Function, and Variable parameters can
limit the selection of commands to be
imported, thereby reducing the chances of name
conflict.
Even if a command is hidden, it can be run by qualifying its name with the name of the
module in
which it originated. For example, & M\F 100 invokes the function F in module
M, and passes it
the argument 100.
When the session includes commands of the same kind with the same name, such as
two cmdlets with the
same name, by default it runs the most recently added command.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { *on-removal-code* }
Essentially, a manifest is a data file; however, it can contain references to data types, the
if
statement, and the arithmetic and comparison operators. (Assignments, function
definitions and loops
are not permitted.) A manifest also has read access to
environment variables and it can contain
calls to the cmdlet Join-Path , so paths can be
constructed.
7 Note
Editor's Note: The original document contains a list of keys allowed in a module
manifest file.
That list is outdated and incomplete. For a complete list of keys in a
module manifest, see
New-ModuleManifest.
PowerShell
@{
ModuleVersion = '1.0'
RequiredModules = @()
FunctionsToExport = 'Set*','Get*','Process*'
The key GUID has a string value. This specifies a Globally Unique IDentifier (GUID) for
the
module. The GUID can be used to distinguish among modules having the same
name. To create a new
GUID, call the method [guid]::NewGuid() .
PowerShell
$sb = {
Convert-CentigradeToFahrenheit 100
c2f 100
The script block $sb defines the contents of the module, in this case, two functions and
two
aliases to those functions. As with an on-disk module, only functions are exported
by default, so
Export-ModuleMember cmdlets calls exist to export both the functions and
the aliases.
Once New-Module runs, the four names exported are available for use in the session, as is
shown by
the calls to the Convert-CentigradeToFahrenheit and c2f.
Like all modules, the members of dynamic modules run in a private module scope that is
a child of
the global scope. Get-Module cannot get a dynamic module, but Get-Command
can get the exported
members.
11.8 Closures
A dynamic module can be used to create a closure, a function with attached data.
Consider the
following example:
PowerShell
function Get-NextID ([int]$startValue = 1) {
$nextID = $startValue
($script:nextID++)
}.GetNewClosure()
The intent here is that Get-NextID return the next ID in a sequence whose start value
can be
specified. However, multiple sequences must be supported, each with its own
$startValue and
$nextID context. This is achieved by the call to the method
[scriptblock]::GetNewClosure
(§4.3.7).
Each time a new closure is created by GetNewClosure , a new dynamic module is created,
and the
variables in the caller's scope (in this case, the script block containing the
increment) are copied
into this new module. To ensure that the nextId defined inside the
parent function (but outside the
script block) is incremented, the explicit script: scope
prefix is needed.
Of course, the script block need not be a named function; for example:
PowerShell
param ([int]$startValue = 1)
$nextID = $startValue
($script:nextID++)
}.GetNewClosure()
} 200
12. Attributes
Article • 07/29/2021
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
Syntax
attribute-list:
attribute
attribute:
type-literal
attribute-name:
type-spec
attribute-arguments:
attribute-argument
attribute-argument new-lines~opt~ ,
attribute-arguments
attribute-argument:
new-lines~opt~ expression
new-lines~opt~ simple-name
To create an object of some attribute type A, use the notation A() . An attribute is
declared by
enclosing its instance inside [] , as in [A()] . Some attribute types have
positional and named
parameters (§8.14), just like functions and cmdlets. For example,
[A(10,IgnoreCase=$true)]
Consider a function call Test1 that has the following param block, and which is called as
shown:
PowerShell
param (
[Parameter(Mandatory = $true)]
[Alias("CN")]
[Alias("name", "system")]
[string[]] $ComputerName
Consider a function call Test2 that has the following param block, and which is called as
shown:
PowerShell
param (
[Alias('PSPath')]
[string] $LiteralPath
$_.FullName + ".bak" }
Cmdlet Get-ChildItem (alias Dir ) adds to the object it returns a new NoteProperty of
type
string , called PSPath.
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[parameter(Mandatory = $true)]
[AllowEmptyCollection()]
[string[]] $ComputerName
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[parameter(Mandatory = $true)]
[AllowEmptyString()]
[string] $ComputerName
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[parameter(Mandatory = $true)]
[AllowNull()]
[int[]] $Values
Note that the second case above does not need this attribute; there is already an
implicit
conversion from $null to int.
12.3.5 The CmdletBinding attribute
This attribute is used in the attribute-list of param-block of a function to indicate that
function acts similar to a cmdlet. Specifically, it allows functions to access a number of
methods
and properties through the $PsCmdlet variable by using begin, process, and
end named blocks
(§8.10.7).
When this attribute is present, positional arguments that have no matching positional
parameters
cause parameter binding to fail and $args is not defined. (Without this
attribute $args would take
on any unmatched positional argument values.)
The following arguments are used to define the characteristics of the parameter:
Specifies the impact level of the action performed. The call to the
ShouldProcess method displays a confirmation prompt only when
the ConfirmImpact argument is greater than or equal to the value of
the $ConfirmPreference preference variable.
PowerShell
param ( ... )
begin { ... }
Get-process { ... }
end { ... }
PowerShell
[OutputType([int])] param ( ... )
[OutputType("double")] param ( ... )
Parameter Purpose
[string[]] $ComputerName )
[string[]] $ComputerName )
ParameterSetName = "Computer")]
[string[]] $ComputerName,
[Parameter(Mandatory = $true,
ParameterSetName = "User")]
[string[]] $UserName,
[Parameter(Mandatory = $true,
ParameterSetName = "Computer")]
[Parameter(ParameterSetName = "User")]
[int] $SharedParam = 5 )
Parameter Purpose
[string[]] $ComputerName )
Parameter Purpose
ValueFromPipeline=$true)]
[string[]] $ComputerName )
ValueFromPipelineByPropertyName = $true)]
[string[]] $ComputerName )
Parameter Purpose
function Process-Date
param(
[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Year,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Month,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Day
process { … }
Get-Date | Process-Date
[parameter(ValueFromRemainingArguments = $true)]
[string[]] $others )
Parameter Purpose
Name
Windows PowerShell: The value is used as part of the description of the parameter
for the help topic displayed by the [Get-Help](xref:Microsoft.PowerShell.Core.Get-
Help)cmdlet when the Help property is not specified.
This attribute is used as part of the description of the parameter for the help topic
displayed by
the Get-Help cmdlet.
In the absence of this attribute, the parameter's corresponding argument value list can
be of any
length.
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[ValidateCount(2, 5)]
[int[]] $Values
Temp 10, 20, 30, 40, 50, 60 # too many argument values
In the absence of this attribute, the parameter's corresponding argument can be of any
length.
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
[ValidateLength(3,6)]
[string[]] $ComputerName )
Consider a function call Test that has the following param block, and which is called as
`shown:
PowerShell
param (
[ValidateNotNull()]
[string[]] $Names
[ValidateNotNull()]$Name = "Jack" # ok
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[ValidateNotNullOrEmpty()]
[string[]] $Names
[ValidateNotNullOrEmpty()]$Name = "Jack" # ok
If the argument is a collection, each element in the collection must match the pattern.
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[ValidatePattern('\^[A-Z][1-5][0-9]$')]
[string] $Code,
[ValidatePattern('\^(0x|0X)([A-F]|[a-f]|[0-9])([A-F]|[a-f]|[0-9])$')]
[string] $HexNum,
[ValidatePattern('\^[+|-]?[1-9]$')]
[int] $Minimum
[ValidatePattern('\^[a-z][a-z0-9]\*$')]$ident = "abc"
Consider a function call Test1 that has the following param block, and which is called as
shown:
PowerShell
param (
[parameter(Mandatory = $true)]
[ValidateRange(1, 10)]
[int] $StartValue
Test1 2
Test1 -st 7
Consider a function call Test2 that has the following param block and calls:
PowerShell
param (
[parameter(Mandatory = $true)]
[ValidateRange("b", "f")]
[string] $Name
Test2 "Bravo" # ok
Consider a function call Test3 that has the following param block, and which is called as
shown:
PowerShell
param (
[parameter(Mandatory = $true)]
[ValidateRange(0.002, 0.003)]
[double] $Distance
Test3 0.002
[ValidateRange(13, 19)]$teenager = 15
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
param (
[Parameter(Mandatory = $true)]
[ValidateScript( { ($_ -ge 1 -and $_ -le 3) -or ($_ -ge 20) })]
[int] $Count
If the parameter has an array type, every element of the corresponding argument array
must match an
element of the value set.
Consider a function call Test that has the following param block, and which is called as
shown:
PowerShell
[string] $Color,
$false)]
[string] $Direction
Test -dir "Up" # case is not ignored, is not a member of the set
13. Cmdlets
Article • 07/29/2021
For each cmdlet, provide a help file that can be accessed by typing:
The detailed view of the cmdlet help file should include a description of the cmdlet, the
command
syntax, descriptions of the parameters, and an example that demonstrate the
use of that cmdlet.
Cmdlets are used similarly to operating system commands and utilities. PowerShell
commands are not
case-sensitive.
7 Note
Editor's note: The original document contains a list of cmdlet with descriptions,
syntax diagrams,
parameter definitions, and examples. This information is
incomplete and out dated. For current
information about cmdlet, consult the
Reference section of the
PowerShell documentation.
Although the common parameters are accepted by any cmdlet, they might not have any
semantics for
that cmdlet. For example, if a cmdlet does not generate any verbose
output, using the Verbose
common parameter has no effect.
Several common parameters override system defaults or preferences that can be set via
preference
variables (§2.3.2.3). Unlike the preference variables, the common parameters
affect only the
commands in which they are used.
7 Note
Editor's note: The original document contains a list of the Common Parameters.
This information is
incomplete and out dated. For current information see
about_CommonParameters.
A. Comment-Based Help
Article • 07/29/2021
A.1 Introduction
A help comment contains a help directive of the form .name followed on one or more
subsequent
lines by the help content text. The help comment can be made up of a
series of
single-line-comments or a delimited-comment (§2.2.3). The set of comments
comprising the
documentation for a single entity is called a help topic.
For example,
PowerShell
# <help-directive-1>
# <help-content-1>
...
# <help-directive-n>
# <help-content-n>
or
PowerShell
<#
<help-directive-1>
<help-content-1>
...
<help-directive-n>
<help-content-n>
#>
All of the lines in a help topic must be contiguous. If a help topic follows a comment
that is not
part of that topic, there must be at least one blank line between the two.
The directives can appear in any order, and some of the directives may appear multiple
times.
Directive names are not case-sensitive.
When documenting a function, help topics may appear in one of three locations:
Immediately before the function definition with no more than one blank line
between the last line
of the function help and the line containing the function
statement.
Inside the function's body immediately following the opening curly bracket.
Inside the function's body immediately preceding the closing curly bracket.
When documenting a script file, help topics may appear in one of two locations:
At the beginning of the script file, optionally preceded by comments and blank
lines only. If the
first item in the script after the help is a function definition, there
must be at least two blank
lines between the end of the script help and that
function declaration. Otherwise, the help will
be interpreted as applying to the
function instead of the script file.
At the end of the script file.
A.2.1 .DESCRIPTION
Syntax:
Syntax
.DESCRIPTION
Description:
This directive allows for a detailed description of the function or script. (The .SYNOPSIS
directive (§A.2.11) is intended for a brief description.) This directive can be used only
once
in each topic.
Examples:
PowerShell
<#
.DESCRIPTION
powers only.
#>
A.2.2 .EXAMPLE
Syntax:
Syntax
.EXAMPLE
Description:
If this directive occurs multiple times, each associated help content block is displayed as
a
separate example.
Examples:
PowerShell
<#
.EXAMPLE
Get-Power 3 4
81
.EXAMPLE
81
#>
A.2.3 .EXTERNALHELP
Syntax:
Syntax
.EXTERNALHELP <XMLHelpFilePath>
Description:
This directive specifies the path to an XML-based help file for the script or function.
Examples:
PowerShell
<#
.ExternalHelp C:\MyScripts\Update-Month-Help.xml
#>
A.2.4 .FORWARDHELPCATEGORY
Syntax:
Syntax
.FORWARDHELPCATEGORY <Category>
Description:
Specifies the help category of the item in ForwardHelpTargetName (§A.2.5). Valid values
are
Alias, All, Cmdlet, ExternalScript, FAQ, Filter, Function, General,
Glossary, HelpFile,
Provider, and ScriptCommand. Use this directive to avoid
conflicts when there are
commands with the same name.
Examples:
See §A.2.5.
A.2.5 .FORWARDHELPTARGETNAME
Syntax:
Syntax
.FORWARDHELPTARGETNAME <Command-Name>
Description:
Examples:
PowerShell
function Help {
<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
...
A.2.6 .INPUTS
Syntax:
Syntax
.INPUTS
Description:
The pipeline can be used to pipe one or more objects to a script or function. This
directive is used
to describe such objects and their types.
If this directive occurs multiple times, each associated help content block is collected in
the one
documentation entry, in the directives' lexical order.
Examples:
PowerShell
<#
.INPUTS
.INPUTS
For the Value parameter, one or more objects of any kind can be written
#>
function Process-Thing {
param ( ...
[Parameter(ValueFromPipeline=$true)]
[object[]]$Value,
...
...
A.2.7 .LINK
Syntax:
Syntax
.LINK
Description:
If this directive occurs multiple times, each associated help content block is collected in
the one
documentation entry, in the directives' lexical order.
The Link directive content can also include a URI to an online version of the same help
topic. The
online version is opens when Get-Help is invoked with the Online parameter.
The URI must begin with
"http" or "https".
Examples:
PowerShell
<#
.LINK
.LINK
Set-ProcedureName
#>
A.2.8 .NOTES
Syntax:
Syntax
.NOTES
Description:
This directive allows additional information about the function or script to be provided.
This
directive can be used only once in each topic.
Examples:
PowerShell
<#
.Notes
#>
A.2.9 .OUTPUTS
Syntax:
Syntax
.OUTPUTS
Description:
If this directive occurs multiple times, each associated help content block is collected in
the one
documentation entry, in the directives' lexical order.
Examples:
PowerShell
<#
.OUTPUTS
.OUTPUTS
#>
A.2.10 .PARAMETER
Syntax:
Syntax
.PARAMETER <Parameter-Name>
Description:
This directive allows for a detailed description of the given parameter. This directive can
be used
once for each parameter. Parameter directives can appear in any order in the
comment block; however,
the order in which their corresponding parameters are
actually defined in the source determines the
order in which the parameters and their
descriptions appear in the resulting documentation.
Examples:
PowerShell
<#
.PARAMETER Base
.PARAMETER Exponent
#>
function Get-Power {
...
function Get-Power {
param ([long]
$Base,
[int]
$Exponent
...
A.2.11 .SYNOPSIS
Syntax:
PowerShell
.SYNOPSIS
Description:
This directive allows for a brief description of the function or script. (The .DESCRIPTION
directive (§A.2.1) is intended for a detailed description.) This directive can be used only
once
in each topic.
Examples:
PowerShell
<#
.SYNOPSIS
#>
B. Grammar
Article • 05/22/2021
This appendix contains summaries of the lexical and syntactic grammars found in the
main document.
Tip
The ~opt~ notation in the syntax definitions indicates that the lexical entity is
optional in
the syntax.
input:
input-elements~opt~ signature-block~opt~
input-elements:
input-element
input-elements input-element
input-element:
whitespace
comment
token
signature-block:
signature-begin:
signature:
signature-end:
new-lines:
new-line-character
new-lines new-line-character
B.1.2 Comments
Syntax
comment:
single-line-comment
requires-comment
delimited-comment
single-line-comment:
# input-characters~opt~
input-characters:
input-character
input-characters input-character
input-character:
requires-comment:
dash:
- (U+002D)
dashdash:
dash dash
delimited-comment:
delimited-comment-text:
delimited-comment-section
delimited-comment-text delimited-comment-section
delimited-comment-section:
>
hashes~opt~ not-greater-than-or-hash
hashes:
hashes #
not-greater-than-or-hash:
whitespace:
B.1.4 Tokens
Syntax
token:
keyword
variable
command
command-parameter
command-argument-token
integer-literal
real-literal
string-literal
type-literal
operator-or-punctuator
B.1.5 Keywords
Syntax
keyword: one of
B.1.6 Variables
Syntax
variable:
$$
$?
$^
$ variable-scope~opt~ variable-characters
@ variable-scope~opt~ variable-characters
braced-variable
braced-variable:
${ variable-scope~opt~ braced-variable-characters }
variable-scope:
global:
local:
private:
script:
using:
workflow:
variable-namespace
variable-namespace:
variable-characters :
variable-characters:
variable-character
variable-characters variable-character
variable-character:
braced-variable-characters:
braced-variable-character
braced-variable-characters braced-variable-character
braced-variable-character:
escaped-character
escaped-character:
B.1.7 Commands
Syntax
generic-token:
generic-token-parts
generic-token-parts:
generic-token-part
generic-token-parts generic-token-part
generic-token-part:
expandable-string-literal
verbatim-here-string-literal
variable
generic-token-char
generic-token-char:
{ } ( ) ; , | & $
double-quote-character
single-quote-character
whitespace
new-line-character
escaped-character
generic-token-with-subexpr-start:
generic-token-parts $(
B.1.8 Parameters
Syntax
command-parameter:
first-parameter-char:
parameter-chars:
parameter-char
parameter-chars parameter-char
parameter-char:
{ } ( ) ; , | & . [
colon
whitespace
new-line-character
colon:
verbatim-command-argument-chars:
verbatim-command-argument-part
verbatim-command-argument-chars verbatim-command-argument-part
verbatim-command-argument-part:
verbatim-command-string
& non-ampersand-character
new-line-character
non-ampersand-character:
verbatim-command-string:
double-quote-character non-double-quote-chars
double-quote-character
non-double-quote-chars:
non-double-quote-char
non-double-quote-chars non-double-quote-char
non-double-quote-char:
double-quote-character
B.1.9 Literals
Syntax
literal:
integer-literal
real-literal
string-literal
Syntax
integer-literal:
decimal-integer-literal
hexadecimal-integer-literal
decimal-integer-literal:
decimal-digits:
decimal-digit
decimal-digit decimal-digits
decimal-digit: one of
0 1 2 3 4 5 6 7 8 9
numeric-type-suffix:
long-type-suffix
decimal-type-suffix
hexadecimal-integer-literal:
0x hexadecimal-digits long-type-suffix~opt~
numeric-multiplier~opt~
hexadecimal-digits:
hexadecimal-digit
hexadecimal-digit decimal-digits
hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9 a b c d e f
long-type-suffix:
numeric-multiplier: one of
kb mb gb tb pb
Syntax
real-literal:
exponent-part:
e sign~opt~ decimal-digits
sign: one of
dash
decimal-type-suffix:
Syntax
string-literal:
expandable-string-literal
expandable-here-string-literal
verbatim-string-literal
verbatim-here-string-literal
expandable-string-literal:
double-quote-character:
" (U+0022)
expandable-string-characters:
expandable-string-part
expandable-string-characters
expandable-string-part
expandable-string-part:
double-quote-character
braced-variable
double-quote-character
$ escaped-character
escaped-character
double-quote-character double-quote-character
dollars:
dollars $
expandable-here-string-literal:
expandable-here-string-characters:
expandable-here-string-part
expandable-here-string-characters expandable-here-string-part
expandable-here-string-part:
new-line-character
braced-variable
new-line-character
expandable-string-with-subexpr-start:
double-quote-character expandable-string-chars~opt~ $(
expandable-string-with-subexpr-end:
double-quote-char
expandable-here-string-with-subexpr-start:
expandable-here-string-with-subexpr-end:
new-line-character double-quote-character @
verbatim-string-literal:
single-quote-character:
' (U+0027)
verbatim-string-characters:
verbatim-string-part
verbatim-string-characters verbatim-string-part
verbatim-string-part:
single-quote-character single-quote-character
verbatim-here-string-literal:
verbatim-here-string-characters~opt~ new-line-character
single-quote-character *@*
verbatim-*here-string-characters:
verbatim-here-string-part
verbatim-here-string-characters verbatim-here-string-part
verbatim-here-string-part:
simple-name:
simple-name-first-char simple-name-chars
simple-name-first-char:
simple-name-chars:
simple-name-char
simple-name-chars simple-name-char
simple-name-char:
type-name:
type-identifier
type-name . type-identifier
type-identifier:
type-characters
type-characters:
type-character
type-characters type-character
type-character:
array-type-name:
type-name [
generic-type-name:
type-name [
operator-or-punctuator: one of
{ } [ ] ( ) @( @{ $( ;
&& || & | , ++ .. :: .
! * / % +
dash dashdash
assignment-operator
merging-redirection-operator
file-redirection-operator
comparison-operator
format-operator
assignment-operator: one of
= dash = += *= /= %=
file-redirection-operator: one of
> >> 2> 2>> 3> 3>> 4> 4>>
merging-redirection-operator: one of
comparison-operator: one of
format-operator:
dash f
script-file:
script-block
module-file:
script-block
interactive-input:
script-block
data-file:
statement-list
B.2.2 Statements
Syntax
script-block:
param-block:
( parameter-list~opt~ new-lines~opt~ )
parameter-list:
script-parameter
script-parameter:
script-parameter-default:
script-block-body:
named-block-list
statement-list
named-block-list:
named-block
named-block-list named-block
named-block:
block-name: one of
statement-block:
statement-list:
statement
statement-list statement
statement:
if-statement
label~opt~ labeled-statement
function-statement
flow-control-statement statement-terminator
trap-statement
try-statement
data-statement
inlinescript-statement
parallel-statement
sequence-statement
pipeline statement-terminator
statement-terminator:
new-line-character
statement-terminators:
statement-terminator
statement-terminators statement-terminator
if-statement:
elseif-clauses~opt~ else-clause~opt~
elseif-clauses:
elseif-clause
elseif-clauses elseif-clause
elseif-clause:
else-clause:
labeled-statement:
switch-statement
foreach-statement
for-statement
while-statement
do-statement
switch-statement:
switch-parameters:
switch-parameter
switch-parameters switch-parameter
switch-parameter:
-regex
-wildcard
-exact
-casesensitive
-parallel
switch-condition:
switch-filename:
command-argument
primary-expression
switch-body:
switch-clauses:
switch-clause
switch-clauses switch-clause
switch-clause:
switch-clause-condition:
command-argument
primary-expression
foreach-statement:
new-lines~opt~ ) statement-block
foreach-parameter:
-parallel
for-statement:
for new-lines~opt~ (
new-lines~opt~ for-iterator~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-condition~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~
new-lines~opt~ ) statement-block
for-initializer:
pipeline
for-condition:
pipeline
for-iterator:
pipeline
while-statement:
do-statement:
while-condition:
new-lines~opt~ pipeline
function-statement:
function-name:
command-argument
function-parameter-declaration:
flow-control-statement:
break label-expression~opt~
continue label-expression~opt~
throw pipeline~opt~
return pipeline~opt~
exit pipeline~opt~
label-expression:
simple-name
unary-expression
trap-statement:
try-statement:
catch-clauses:
catch-clause
catch-clauses catch-clause
catch-clause:
catch-type-list:
new-lines~opt~ type-literal
finally-clause:
data-statement:
statement-block
data-name:
simple-name
data-commands-allowed:
data-commands-list:
new-lines~opt~ data-command
data-command:
command-name-expr
inlinescript-statement:
inlinescript statement-block
parallel-statement:
parallel statement-block
sequence-statement:
sequence statement-block
pipeline:
assignment-expression
assignment-expression:
pipeline-tail:
| new-lines~opt~ command
command:
command-name command-elements~opt~
command-invocation-operator: one of
& .
command-module:
primary-expression
command-name:
generic-token
generic-token-with-subexpr
generic-token-with-subexpr:
command-name-expr:
command-name
primary-expression
command-elements:
command-element
command-elements command-element
command-element:
command-parameter
command-argument
redirection
command-argument:
command-name-expr
verbatim-command-argument:
--% verbatim-command-argument-chars
redirections:
redirection
redirections redirection
redirection:
merging-redirection-operator
file-redirection-operator redirected-file-name
redirected-file-name:
command-argument
primary-expression
B.2.3 Expressions
Syntax
expression:
logical-expression
logical-expression:
bitwise-expression
bitwise-expression:
comparison-expression
comparison-expression:
additive-expression
additive-expression
additive-expression:
multiplicative-expression
multiplicative-expression:
format-expression
format-expression:
range-expression
range-expression:
array-literal-expression
array-literal-expression:
unary-expression
unary-expression:
primary-expression
expression-with-unary-operator
expression-with-unary-operator:
, new-lines~opt~ unary-expression
! new-lines~opt~ unary-expression
+ new-lines~opt~ unary-expression
pre-increment-expression
pre-decrement-expression
cast-expression
pre-increment-expression:
++ new-lines~opt~ unary-expression
pre-decrement-expression:
cast-expression:
type-literal unary-expression
attributed-expression:
type-literal variable
primary-expression:
value
member-access
element-access
invocation-expression
post-increment-expression
post-decrement-expression
value:
parenthesized-expression
sub-expression
array-expression
script-block-expression
hash-literal-expression
literal
type-literal
variable
parenthesized-expression:
sub-expression:
array-expression:
script-block-expression:
hash-literal-expression:
hash-literal-body:
hash-entry
hash-entry:
key-expression:
simple-name
unary-expression
post-increment-expression:
primary-expression ++
post-decrement-expression:
primary-expression dashdash
primary-expression.
primary-expression . member-name
primary-expression :: member-name
primary-expression.
argument-list:
( argument-expression-list~opt~ new-lines~opt~ )
argument-expression-list:
argument-expression
argument-expression:
new-lines~opt~ logical-argument-expression
logical-argument-expression:
bitwise-argument-expression
bitwise-argument-expression:
comparison-argument-expression
comparison-argument-expression:
additive-argument-expression
comparison-argument-expression comparison-operator
new-lines~opt~ additive-argument-expression
additive-argument-expression:
multiplicative-argument-expression
multiplicative-argument-expression:
format-argument-expression
format-argument-expression:
range-argument-expression
range-argument-expression:
unary-expression
member-name:
simple-name
string-literal
string-literal-with-subexpression
expression-with-unary-operator
value
string-literal-with-subexpression:
expandable-string-literal-with-subexpr
expandable-here-string-literal-with-subexpr
expandable-string-literal-with-subexpr:
expandable-string-with-subexpr-start statement-list~opt~ )
expandable-string-with-subexpr-characters expandable-string-with-
subexpr-end
expandable-here-string-with-subexpr-start statement-list~opt~ )
expandable-here-string-with-subexpr-characters
expandable-here-string-with-subexpr-end
expandable-string-with-subexpr-characters:
expandable-string-with-subexpr-part
expandable-string-with-subexpr-characters expandable-string-with-
subexpr-part
expandable-string-with-subexpr-part:
sub-expression
expandable-string-part
expandable-here-string-with-subexpr-characters:
expandable-here-string-with-subexpr-part
expandable-here-string-with-subexpr-characters expandable-here-string-
with-subexpr-part
expandable-here-string-with-subexpr-part:
sub-expression
expandable-here-string-part
type-literal:
[ type-spec ]
type-spec:
type-name
dimension:
dimension ,
generic-type-arguments:
type-spec new-lines~opt~
B.2.4 Attributes
Syntax
attribute-list:
attribute
attribute:
type-literal
attribute-name:
type-spec
attribute-arguments:
attribute-argument
attribute-argument:
new-lines~opt~ expression
new-lines~opt~ simple-name
C. References
Article • 01/18/2023
The Open Group Base Specifications: Pattern Matching, IEEE Std 1003.1, 2004 Edition.
http://www.opengroup.org/onlinepubs/000095399/utilities/xcu_chap02.html#tag_02_13
_01
The Open Group Base Specifications: Regular Expressions, IEEE Std 1003.1, 2004 Edition.
http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap09.html .
ISO 639-1, Codes for the representation of names of languages - Part 1: Alpha-2 code.
ISO 3166-1, Codes for the representation of names of countries and their subdivisions -
Part 1:
Country codes.
The documents published here are written primarily for cmdlet, provider, and host
application
developers who require reference information about the APIs provided by
Windows PowerShell.
However, system administrators might also find the information
provided by these documents useful.
For the basic information needed to start using Windows PowerShell, see Getting
Started with
Windows PowerShell .
The following topic describes how to install the PowerShell SDK on different versions of
Windows.
SDK download site. Windows PowerShell code samples are also available in the
powershell-sdk-samples
repository.
7 Note
Code that is compiled against the Windows PowerShell 2.0 assemblies cannot be
loaded into Windows
PowerShell 1.0 installations. However, code that is compiled
against the Windows PowerShell 1.0
assemblies can be loaded into Windows
PowerShell 2.0 installations.
Samples
Code samples are installed in the following location by default: C:\Program
Files\Microsoft SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\ . The following
sections provide a brief
description of what each sample does.
Cmdlet samples
GetProcessSample01 - Shows how to write a simple cmdlet that gets all the
processes on the local
computer.
GetProcessSample02 - Shows how to add parameters to the cmdlet. The cmdlet
takes one or more
process names and returns the matching processes.
GetProcessSample03 - Shows how to add parameters that accept input from the
pipeline.
GetProcessSample04 - Shows how to handle non-terminating errors.
GetProcessSample05 - Shows how to display a list of specified processes.
SelectObject - Shows how to write a filter to select only certain objects.
SelectString - Shows how to search files for specified patterns.
StopProcessSample01 - Shows how to implement a PassThru parameter, and how
to request user
feedback by calls to the ShouldProcess and ShouldContinue
methods. Users specify the PassThru
parameter when they want to force the
cmdlet to return an object,
StopProcessSample02 - Shows how to stop a specific process.
StopProcessSample03 - Shows how to declare aliases for parameters and how to
support wildcards.
StopProcessSample04 - Shows how to declare parameter sets, the object that the
cmdlet takes as
input, and how to specify the default parameter set to use.
Remoting samples
RemoteRunspace01 - Shows how to create a remote runspace that is used to
establish a remote
connection.
RemoteRunspacePool01 - Shows how to construct a remote runspace pool and
how to run multiple
commands concurrently by using this pool.
Serialization01 - Shows how to look at an existing .NET class and make sure that
information from
selected public properties of this class is preserved across
serialization/deserialization.
Serialization02 - Shows how to look at an existing .NET class and make sure that
information from
instance of this class is preserved across
serialization/deserialization when the information is
not available in public
properties of the class.
Serialization03 - Shows how to look at an existing .NET class and make sure that
instances of this
class and of derived classes are deserialized (rehydrated) into live
.NET objects.
Event samples
Event01 - Shows how to create a cmdlet for event registration by deriving from
ObjectEventRegistrationBase.
Event02 - Shows how to shows how to receive notifications of Windows PowerShell
events that are
generated on remote computers. It uses the PSEventReceived event
exposed through the Runspace
class.
Runspace01 - Shows how to use the PowerShell class to run the Get-Process
cmdlet synchronously.
The Get-Process cmdlet returns Process objects for each
process running on the local computer.
Runspace02 - Shows how to use the PowerShell class to run the Get-Process and
Sort-Object
cmdlets synchronously. The Get-Process cmdlet returns Process
Host samples
Host01 - Shows how to implement a host application that uses a custom host. In
this sample a
runspace is created that uses the custom host, and then the
PowerShell API is used to run a script
that calls exit . The host application then
looks at the output of the script and prints out the
results.
Host02 - Shows how to write a host application that uses the Windows PowerShell
runtime along with
a custom host implementation. The host application sets the
host culture to German, runs the
Get-Process cmdlet and displays the results as
you would see them by using pwrsh.exe, and then
prints out the current data and
time in German.
Host03 - Shows how to build an interactive console-based host application that
reads commands from
the command line, executes the commands, and then
displays the results to the console.
Host04 - Shows how to build an interactive console-based host application that
reads commands from
the command line, executes the commands, and then
displays the results to the console. This host
application also supports displaying
prompts that allow the user to specify multiple choices.
Host05 - Shows how to build an interactive console-based host application that
reads commands from
the command line, executes the commands, and then
displays the results to the console. This host
application also supports calls to
remote computers by using the Enter-PsSession and
Exit-PsSession cmdlets.
Host06 - Shows how to build an interactive console-based host application that
reads commands from
the command line, executes the commands, and then
displays the results to the console. In
addition, this sample uses the Tokenizer APIs
to specify the color of the text that is entered by
the user.
Provider samples
AccessDBProviderSample01 - Shows how to declare a provider class that derives
directly from the
CmdletProvider class. It is included here only for completeness.
Developer Audience
The Windows PowerShell Software Development Kit (SDK) is written for command
developers who require
reference information about the APIs provided by Windows
PowerShell. Command developers use Windows
PowerShell to create both commands
and providers that extend the tasks that can be performed by
Windows PowerShell.
Class Libraries
System.Management.Automation This namespace is the root
namespace for Windows
PowerShell. It contains the classes, enumerations, and interfaces required to
implement
custom cmdlets. In particular, the
System.Management.Automation.Cmdlet class is the
base class from which all cmdlet classes must be derived. For more information about
cmdlets, see.
System.Management.Automation.Provider This
namespace contains the classes,
enumerations, and interfaces required to implement a Windows
PowerShell provider. In
particular, the
System.Management.Automation.Provider.Cmdletprovider
class is the
base class from which all Windows PowerShell provider classes must be derived.
System.Management.Automation.Internal This
namespace contains the base classes
used by other namespace classes. For example, the
System.Management.Automation.Internal.Cmdletmetadataattribute
class is the base
class for the
System.Management.Automation.CmdletAttribute
class.
System.Management.Automation.Runspaces This
namespace contains the classes,
enumerations, and interfaces used to create a Windows PowerShell
runspace. In this
context, the Windows PowerShell runspace is the context in which one or more
Windows PowerShell pipelines invoke cmdlets. That is, cmdlets work within the context
of a Windows
PowerShell runspace. For more information aboutWindows PowerShell
runspaces, see
Windows PowerShell Runspaces.
What's New
Article • 09/17/2021
Windows PowerShell 2.0 provides the following new features for use when writing
cmdlets, providers,
and host applications.
Modules
You can now package and distribute Windows PowerShell solutions by using modules.
Modules allow you
to partition, organize, and abstract your Windows PowerShell code
into self-contained, reusable
units. For more information about modules, see Writing a
Windows PowerShell Module.
Remote runspaces
You can now create runspaces that can be opened on remote computers, allowing you
to run commands
on the remote machine and collect the results locally. To create a
remote runspace, you must
specify information about the remote connection when
creating the runspace. See the CreateRunspace
and CreateRunspacePool methods for
examples. The connection information is defined by the
RunspaceConnectionInfo class.
You can now get the apartment state of the threads that are used to run commands in a
runspace. See
the
System.Management.Automation.Runspaces.Runspace.ApartmentState and
System.Management.Automation.Runspaces.RunspacePool.ApartmentState properties.
Transaction cmdlets
You can now create cmdlets that can be used within a transaction. When a cmdlet is
used in a
transaction, its actions are temporary, and they can be accepted or rejected by
the transaction
cmdlets provided by Windows PowerShell.
Transaction provider
You can now create providers that can be used within a transaction. Similar to cmdlets,
when a
provider is used in a transaction, its actions are temporary, and they can be
accepted or rejected
by the transaction cmdlets provided by Windows PowerShell.
For more information about specifying support for transaction within a provider class,
see the
System.Management.Automation.Provider.CmdletProviderAttribute.ProviderCapabilities
property.
Job cmdlets
You can now write cmdlets that can perform their action as a job. These jobs are run in
the
background without interacting with the current session. For more information
about how Windows
PowerShell supports jobs, see Background Jobs.
Event support
You can now write cmdlets that add and consume events. See the PSEvent class.
Proxy commands
You can now write proxy commands that can be used to run another command. A proxy
command allows
you to control what functionality of the source cmdlet is available to
the user. For example, you
can create a proxy command that removes a parameter that
is supplied by the source command. See the
ProxyCommand class.
Interactive sessions
You can now write applications that can start and stop an interactive session on a
remote computer.
See the IHostSupportsInteractiveSession interface.
Cmdlets
Cmdlets perform an action and typically return a Microsoft .NET object to the next
command in the
pipeline. A cmdlet is a single command that participates in the pipeline
semantics of PowerShell.
This includes binary (C#) cmdlets, advanced script functions,
CDXML, and Workflows.
This SDK documentation describes how to create binary cmdlets written in C#. For
information about
script-based cmdlets, see:
about_Functions_Advanced
about_Functions_CmdletBindingAttribute
about_Functions_Advanced_Methods
To create a binary cmdlet, you must implement a cmdlet class that derives from one of
two
specialized cmdlet base classes. The derived class must:
You can load the assembly that contains the class directly by using the
Import-Module
cmdlet, or you can
create a host application that loads the assembly by using the
System.Management.Automation.Runspaces.Initialsessionstate
API. Both methods
provide programmatic and command-line access to the functionality of the cmdlet.
Cmdlet Terms
The following terms are used frequently in the PowerShell cmdlet documentation:
Cmdlet attribute
A .NET attribute that is used to declare a cmdlet class as a cmdlet. Although PowerShell
uses
several other attributes that are optional, the Cmdlet attribute is required. For more
information
about this attribute, see Cmdlet Attribute Declaration.
Cmdlet parameter
The public properties that define the parameters that are available to the user or to the
application that is running the cmdlet. Cmdlets can have required, named, positional,
and switch
parameters. Switch parameters allow you to define parameters that are
evaluated only if the
parameters are specified in the call. For more information about
the different types of parameters,
see Cmdlet Parameters.
Parameter set
A group of parameters that can be used in the same command to perform a specific
action. A cmdlet
can have multiple parameter sets, but each parameter set must have at
least one parameter that is
unique. Good cmdlet design strongly suggests that the
unique parameter also be a required parameter.
For more information about parameter
sets, see Cmdlet Parameter Sets.
Dynamic parameter
A parameter that is added to the cmdlet at runtime. Typically, the dynamic parameters
are added to
the cmdlet when another parameter is set to a specific value. For more
information about dynamic
parameters, see Cmdlet Dynamic Parameters.
System.Management.Automation.Cmdlet.BeginProcessing:
Used to provide
optional one-time, pre-processing functionality for the cmdlet.
System.Management.Automation.Cmdlet.ProcessRecord:
Used to provide record-
by-record processing functionality for the cmdlet. The
System.Management.Automation.Cmdlet.ProcessRecord
method might be called
any number of times, or not at all, depending on the input of the cmdlet.
System.Management.Automation.Cmdlet.EndProcessing:
Used to provide optional
one-time, post-processing functionality for the cmdlet.
System.Management.Automation.Cmdlet.StopProcessing:
Used to stop processing
when the user stops the cmdlet asynchronously (for example, by pressing
CTRL + C
).
When you implement a cmdlet, you must override at least one of these input processing
methods.
Typically, the ProcessRecord() is the method that you override because it is
called for every
record that the cmdlet processes. In contrast, the BeginProcessing()
method and the
EndProcessing() method are called one time to perform pre-processing
or post-processing of the
records. For more information about these methods, see
Input
Processing Methods.
ShouldProcess feature
PowerShell allows you to create cmdlets that prompt the user for feedback before the
cmdlet makes a
change to the system. To use this feature, the cmdlet must declare that
it supports the
ShouldProcess feature when you declare the Cmdlet attribute, and the
cmdlet must call the
System.Management.Automation.Cmdlet.ShouldProcess
and
System.Management.Automation.Cmdlet.ShouldContinue
methods from within an input
processing method. For more information about how to support the
ShouldProcess
functionality, see
Requesting Confirmation.
Transaction
A logical group of commands that are treated as a single task. The task automatically
fails if any
command in the group fails, and the user has the choice to accept or reject
the actions performed
within the transaction. To participate in a transaction, the cmdlet
must declare that it supports
transactions when the Cmdlet attribute is declared.
Support for transactions was introduced in
Windows PowerShell 2.0. For more
information about transactions, see
How to Support Transactions.
Cmdlets are instances of .NET classes; they are not stand-alone executables.
Cmdlets can be created from as few as a dozen lines of code.
Cmdlets do not generally do their own parsing, error presentation, or output
formatting. Parsing,
error presentation, and output formatting are handled by the
PowerShell runtime.
Cmdlets process input objects from the pipeline rather than from streams of text,
and cmdlets
typically deliver objects as output to the pipeline.
Cmdlets are record-oriented because they process a single object at a time.
Most cmdlets are based on .NET classes that derive from the
System.Management.Automation.Cmdlet base class.
Deriving from this class allows
a cmdlet to use the minimum set of dependencies on the Windows
PowerShell
runtime. This has two benefits. The first benefit is that the cmdlet objects are
smaller, and you are less likely to be affected by changes to the PowerShell
runtime. The second
benefit is that, if you have to, you can directly create an
instance of the cmdlet object and then
invoke it directly instead of invoking it
through the PowerShell runtime.
The more-complex cmdlets are based on .NET classes that derive from the
System.Management.Automation.PSCmdlet base
class. Deriving from this class
gives you much more access to the PowerShell runtime. This access
allows your
cmdlet to call scripts, to access providers, and to access the current session state.
(To access the current session state, you get and set session variables and
preferences.) However,
deriving from this class increases the size of the cmdlet
object, and it means that your cmdlet is
more tightly coupled to the current
version of the PowerShell runtime.
In general, unless you need the extended access to the PowerShell runtime, you should
derive from
the System.Management.Automation.Cmdlet class.
However, the PowerShell
runtime has extensive logging capabilities for the execution of cmdlets. If
your auditing
model depends on this logging, you can prevent the execution of your cmdlet from
within another cmdlet by deriving from the
System.Management.Automation.PSCmdlet
class.
Cmdlet Attributes
PowerShell defines several .NET attributes that are used to manage cmdlets and to
specify common
functionality that is provided by PowerShell and that might be required
by the cmdlet. For example,
attributes are used to designate a class as a cmdlet, to
specify the parameters of the cmdlet, and
to request the validation of input so that
cmdlet developers do not have to implement that
functionality in their cmdlet code. For
more information about attributes, see
PowerShell Attributes.
Cmdlet Names
PowerShell uses a verb-and-noun name pair to name cmdlets. For example, the Get-
Command cmdlet
included in PowerShell is used to get all the cmdlets that are registered
These names are specified when the .NET class is declared as a cmdlet. For more
information about how to declare a .NET class as a cmdlet, see
Cmdlet Attribute
Declaration.
For more information about the guidelines for writing cmdlets, see
Cmdlet Development
Guidelines.
See Also
PowerShell Cmdlet Concepts
PowerShell SDK
Windows PowerShell Cmdlet Concepts
Article • 09/17/2021
In This Section
This section includes the following topics.
Cmdlet Parameters
This section describes the different types of parameters that you can
add to cmdlets.
Cmdlet Attributes
This section describes the attributes that are used to declare .NET
Framework classes as cmdlets, to declare fields as cmdlet parameters, and to declare
input validation rules for parameters.
Cmdlet Aliases
This topic describes cmdlet aliases.
Cmdlet Output
This section describes the type of output that cmdlets can return and
how to define and display the objects that are returned by cmdlets.
Registering Cmdlets
This section describes how to register cmdlets by using modules
and snap-ins.
Requesting Confirmation
This section describes how cmdlets request confirmation from
a user before they make a change to the system.
Cmdlet Sets
This topic describes using base classes to create sets of cmdlets.
The topics in this section provide development guidelines that you can use to produce
well-formed cmdlets. By leveraging the common functionality provided by the Windows
PowerShell runtime and by following these guidelines, you can develop robust cmdlets
with minimal effort and provide the user with a consistent experience. Additionally, you
will reduce the test burden because common functionality does not require retesting.
In This Section
Required Development Guidelines
See Also
Writing a Windows PowerShell Cmdlet
The following guidelines must be followed when you write your cmdlets. They are
separated into guidelines for designing cmdlets and guidelines for writing your cmdlet
code. If you do not follow these guidelines, your cmdlets could fail, and your users
might have a poor experience when they use your cmdlets.
In this Topic
Design Guidelines
Use Only Approved Verbs (RD01)
Code Guidelines
Derive from the Cmdlet or PSCmdlet Classes (RC01)
Design Guidelines
The following guidelines must be followed when designing cmdlets to ensure a
consistent user experience between using your cmdlets and other cmdlets. When you
find a Design guideline that applies to your situation, be sure to look at the Code
guidelines for similar guidelines.
System.Management.Automation.VerbsCommon
System.Management.Automation.VerbsCommunications
System.Management.Automation.VerbsData
System.Management.Automation.VerbsDiagnostic
System.Management.Automation.VerbsLifeCycle
System.Management.Automation.VerbsSecurity
System.Management.Automation.VerbsOther
For more information about the approved verb names, see Cmdlet Verbs.
Users need a set of discoverable and expected cmdlet names. Use the appropriate verb
so that the user can make a quick assessment of what a cmdlet does and to easily
discover the capabilities of the system. For example, the following command-line
command gets a list of all the commands on the system whose names begin with
"start": get-command start-* . Use the nouns in your cmdlets to differentiate your
cmdlets from other cmdlets. The noun indicates the resource on which the operation will
be performed. The operation itself is represented by the verb.
Character Name
# number sign
, comma
Character Name
() parentheses
{} braces
[] brackets
& ampersand
- hyphen Note: The hyphen can be used to separate the verb from the noun, but it
cannot be used within the noun or within the verb.
/ slash mark
\ backslash
$ dollar sign
^ caret
; semicolon
: colon
| vertical bar
? question mark
@ at sign
* asterisk
% percent sign
+ plus sign
= equals sign
~ tilde
To make these calls the cmdlet must specify that it supports confirmation requests by
setting the SupportsShouldProcess keyword of the Cmdlet attribute. For more
information about setting this attribute, see Cmdlet Attribute Declaration.
7 Note
If the Cmdlet attribute of the cmdlet class indicates that the cmdlet supports calls
to the System.Management.Automation.Cmdlet.ShouldProcess* method, and the
cmdlet fails to make the call to the
System.Management.Automation.Cmdlet.ShouldProcess* method, the user could
modify the system unexpectedly.
If your cmdlets support these calls, the user can determine whether the action should
actually be performed. For example, the Stop-Process cmdlet calls the
System.Management.Automation.Cmdlet.ShouldContinue* method before it stops a set
of critical processes, including the System, Winlogon, and Spoolsv processes.
For more information about supporting these methods, see Requesting Confirmation.
System.Management.Automation.Host.PSHostUserInterface.Prompt*
System.Management.Automation.Host.Pshostuserinterface.PromptForChoice
System.Management.Automation.Host.Ihostuisupportsmultiplechoiceselection.Pro
mptForChoice
System.Management.Automation.Host.Pshostuserinterface.PromptForCredential*
System.Management.Automation.Host.Pshostuserinterface.ReadLine*
System.Management.Automation.Host.Pshostuserinterface.ReadLineAsSecureString
*
Code Guidelines
The following guidelines must be followed when writing cmdlet code. When you find a
Code guideline that applies to your situation, be sure to look at the Design guidelines
for similar guidelines.
All cmdlet classes that you implement must be public classes. For more information
about these cmdlet classes, see Cmdlet Overview.
The default parameter set that is used when multiple parameter sets are specified.
The default parameter set is used when Windows PowerShell does not have
enough information to determine which parameter set to use.
Indicate the impact level (or severity) of the action associated with the
confirmation message. In most cases, the default value of Medium should be used.
For more information about how the impact level affects the confirmation requests
that are displayed to the user, see Requesting Confirmation.
For more information about how to declare the cmdlet attribute, see CmdletAttribute
Declaration.
System.Management.Automation.Cmdlet.BeginProcessing
This method is called one
time, and it is used to provide pre-processing functionality.
System.Management.Automation.Cmdlet.ProcessRecord
This method is called multiple
times, and it is used to provide record-by-record functionality.
System.Management.Automation.Cmdlet.EndProcessing
This method is called one time,
and it is used to provide post-processing functionality.
When an error prevents a cmdlet from continuing to process any more records, it
is a terminating error. The cmdlet must call the
System.Management.Automation.Cmdlet.ThrowTerminatingError* method that
references an System.Management.Automation.ErrorRecord object. If an exception
is not caught by the cmdlet, the Windows PowerShell runtime itself throws a
terminating error that contains less information.
For a non-terminating error that does not stop operation on the next record that is
coming from the pipeline (for example, a record produced by a different process),
the cmdlet must call the System.Management.Automation.Cmdlet.WriteError*
method that references an System.Management.Automation.ErrorRecord object.
An example of a non-terminating error is the error that occurs if a particular
process fails to stop. Calling the
System.Management.Automation.Cmdlet.WriteError* method allows the user to
consistently perform the actions requested and to retain the information for
particular actions that fail. Your cmdlet should handle each record as
independently as possible.
If a cmdlet creates a new thread, and if the code that is running in that thread
throws an unhandled exception, Windows PowerShell will not catch the error and
will terminate the process.
See Also
Strongly Encouraged Development Guidelines
This section describes guidelines that you should follow when you write your cmdlets.
They are
separated into guidelines for designing cmdlets and guidelines for writing your
cmdlet code. You
might find that these guidelines are not applicable for every scenario.
However, if they do apply
and you do not follow these guidelines, your users might have
a poor experience when they use your
cmdlets.
Design Guidelines
The following guidelines should be followed when designing cmdlets to ensure a
consistent user
experience between using your cmdlets and other cmdlets. When you
find a Design guideline that
applies to your situation, be sure to look at the Code
guidelines for similar guidelines.
To enhance the user experience, the noun that you choose for a cmdlet name should be
singular. For
example, use the name Get-Process instead of Get-Processes . It is best to
follow this rule for
all cmdlet names, even when a cmdlet is likely to act upon more than
one item.
For more information about parameter names and their data types, see
Cmdlet
Parameter Name and Functionality Guidelines.
Avoid using plural names for parameters whose value is a single element. This includes
parameters
that take arrays or lists because the user might supply an array or list with
only one element.
Plural parameter names should be used only in those cases where the value of the
parameter is always
a multiple-element value. In these cases, the cmdlet should verify
that multiple elements are
supplied, and the cmdlet should display a warning to the user
if multiple elements are not supplied.
errorAction
erroraction
Define an enumeration type (or use an existing enumeration type) that specifies
the valid values.
Then, use the enumeration type to create a parameter of that
type.
Add the ValidateSet attribute to the parameter declaration. For more information
about this
attribute, see ValidateSet Attribute Declaration.
To ensure consistency with other cmdlets, use standard types for parameters where ever
possible. For
more information about the types that should be used for different
parameter, see
Standard Cmdlet Parameter Names and Types. This
topic provides links
to several topics that describe the names and .NET Framework types for groups
of
standard parameters, such as the "activity parameters".
If your parameter takes only true and false , define the parameter as type
System.Management.Automation.SwitchParameter.
A switch parameter is treated as
true when it is specified in a command. If the parameter is not
included in a command,
Windows PowerShell considers the value of the parameter to be false . Do not
define
Boolean parameters.
If your parameter needs to differentiate between 3 values: $true, $false and
"unspecified", then
define a parameter of type Nullable<bool>. The need for a 3rd,
"unspecified" value typically occurs
when the cmdlet can modify a Boolean property of
an object. In this case "unspecified" means to not
change the current value of the
property.
PowerShell
In most cases, Add, Set, and New cmdlets should support a PassThru parameter.
When parameter sets are used, the default parameter set is defined by the Cmdlet
attribute. The
default parameter set should include the parameters most likely to be
used in an interactive Windows
PowerShell session. For more information about how to
declare the Cmdlet attribute, see
CmdletAttribute Declaration.
The Windows PowerShell runtime allows a user to specify how to handle output from
each call to the
Write method by setting a preference variable. The user can set several
preference variables,
including a variable that determines whether the system should
display information and a variable
that determines whether the system should query the
user before taking further action.
Occasionally, a cmdlet must communicate directly with the user instead of by using the
various Write
or Should methods supported by the
System.Management.Automation.Cmdlet class. In
this case, the cmdlet should derive
from the
System.Management.Automation.PSCmdlet class and
use the
System.Management.Automation.PSCmdlet.Host*
property. This property supports
different levels of communication type, including the
PromptForChoice, Prompt, and
WriteLine/ReadLine types. At the most specific level, it also provides
ways to read and
write individual keys and to deal with buffers.
7 Note
Code Guidelines
The following guidelines should be followed when coding cmdlets to ensure a
consistent user
experience between using your cmdlets and other cmdlets. When you
find a Code guideline that applies
to your situation, be sure to look at the Design
guidelines for similar guidelines.
The Windows PowerShell path is the mechanism for normalizing access to namespaces.
When you assign a
Windows PowerShell path to a parameter in the cmdlet, the user can
define a custom "drive" that acts
as a shortcut to a specific path. When a user
designates such a drive, stored data, such as data in
the Registry, can be used in a
consistent way.
If your cmdlet allows the user to specify a file or a data source, it should define a
parameter of
type System.String. If more than one drive is supported, the type
should be
an array. The name of the parameter should be Path , with an alias of PSPath .
Additionally, the Path parameter should support wildcard characters. If support for
wildcard
characters is not required, define a LiteralPath parameter.
If the data that the cmdlet reads or writes has to be a file, the cmdlet should accept
Windows
PowerShell path input, and the cmdlet should use the
System.Management.Automation.Sessionstate.Path
property to translate the Windows
PowerShell paths into paths that the file system recognizes. The
specific mechanisms
include the following methods:
System.Management.Automation.PSCmdlet.GetResolvedProviderPathFromPSPath
System.Management.Automation.PSCmdlet.GetUnresolvedProviderPathFromPSPat
h
System.Management.Automation.PathIntrinsics.GetResolvedProviderPathFromPSPa
th
System.Management.Automation.PathIntrinsics.GetUnresolvedProviderPathFromPS
Path
If the data that the cmdlet reads or writes is only a set of strings instead of a file, the
cmdlet
should use the provider content information ( Content member) to read and
write. This information
is obtained from the
System.Management.Automation.Provider.CmdletProvider.InvokeProvider
property.
These mechanisms allow other data stores to participate in the reading and writing of
data.
When support for wildcard characters is available, a cmdlet operation usually produces
an array.
Occasionally, it does not make sense to support an array because the user
might use only a single
item at a time. For example, the
Set-Location cmdlet does not
need
to support an array because the user is setting only a single location. In this
instance, the cmdlet
still supports wildcard characters, but it forces resolution to a single
location.
Defining Objects
This section contains guidelines for defining objects for cmdlets and for extending
existing
objects.
Define standard members to extend an object type in a custom Types.ps1xml file (use
the Windows
PowerShell Types.ps1xml file as a template). Standard members are
defined by a node with the name
PSStandardMembers. These definitions allow other
cmdlets and the Windows PowerShell runtime to work
with your object in a consistent
way.
If you are designing an object for a cmdlet, ensure that its members map directly to the
parameters
of the cmdlets that will use it. This mapping allows the object to be easily
sent to the pipeline
and to be passed from one cmdlet to another.
Preexisting .NET Framework objects that are returned by cmdlets are frequently missing
some
important or convenient members that are needed by the script developer or
user. These missing
members can be particularly important for display and for creating
the correct member names so that
the object can be correctly passed to the pipeline.
Create a custom Types.ps1xml file to document
these required members. When you
create this file, we recommend the following naming convention:
<Your_Product_Name>.Types.ps1xml.
If the display for an object does not provide the expected results, create a custom
<YourProductName>.Format.ps1xml file for that object.
In each parameter set for a cmdlet, include at least one parameter that supports input
from the
pipeline. Support for pipeline input allows the user to retrieve data or objects,
to send them to
the correct parameter set, and to pass the results directly to a cmdlet.
A parameter accepts input from the pipeline if the Parameter attribute includes the
ValueFromPipeline keyword, the ValueFromPipelineByPropertyName keyword attribute, or
both
keywords in its declaration. If none of the parameters in a parameter set support
the
ValueFromPipeline or ValueFromPipelineByPropertyName keywords, the cmdlet
cannot meaningfully be
placed after another cmdlet because it will ignore any pipeline
input.
To accept all the records from the preceding cmdlet in the pipeline, your cmdlet must
implement the
System.Management.Automation.Cmdlet.ProcessRecord
method.
Windows PowerShell calls this method multiple times, once for every record that is sent
to
your cmdlet.
See Also
Required Development Guidelines
This section describes guidelines that you should consider to ensure good development
and user
experiences. Sometimes they might apply, and sometimes they might not.
Design Guidelines
The following guidelines should be considered when designing cmdlets. When you find
a Design
guideline that applies to your situation, be sure to look at the Code guidelines
for similar
guidelines.
Code Guidelines
The following guidelines should be considered when writing cmdlet code. When you
find a guideline that applies to your situation, be sure to look at the Design guidelines
for similar guidelines.
Primitive types:
Byte, SByte, Decimal, Single, Double, Int16, Int32, Int64, Uint16, UInt32, and UInt64.
PSPrimitiveDictionary
SwitchParameter
PSListModifier
PSCredential
IPAddress, MailAddress
CultureInfo
X509Certificate2, X500DistinguishedName
Other types:
SecureString
See Also
Required Development Guidelines
7 Note
Nouns
The noun of the cmdlet specifies the resources upon which the cmdlet acts. The noun
differentiates
your cmdlets from other cmdlets.
Nouns in cmdlet names must be specific, and in the case of generic nouns, such as
server, it is
best to add a short prefix that differentiates your resource from other similar
resources. For
example, a cmdlet name that includes a noun with a prefix is Get-
SQLServer . The combination of a
specific noun with a more general verb enables the
For a list of special characters that cannot be used in cmdlet names, see
Required
Development Guidelines.
Verbs
When you specify a verb, the development guidelines require you to use one of the
predefined verbs
provided by Windows PowerShell. By using one of these predefined
verbs, you will ensure consistency
between the cmdlets that you write and the cmdlets
that are written by Microsoft and by others. For
example, the "Get" verb is used for
cmdlets that retrieve data.
For more information about the declaration syntax that is used to specify the Cmdlet
attribute,
see Cmdlet Attribute Declaration.
C#
[Cmdlet(VerbsCommon.Get, "Proc")]
Pascal Casing
When you name cmdlets, use Pascal casing. For example, the Get-Item and Get-
ItemProperty cmdlets
show the correct way to use capitalization when you are naming
cmdlets.
See Also
System.Management.Automation.CmdletAttribute
CmdletAttribute Declaration
PowerShell uses a verb-noun pair for the names of cmdlets and for their derived .NET
classes.
The verb part of the name identifies the action that the cmdlet performs. The
noun part of
the name identifies the entity on which the action is performed. For
example, the Get-Command
cmdlet retrieves all the commands that are registered in
PowerShell.
7 Note
PowerShell uses the term verb to describe a word that implies an action even if that
word is not
a standard verb in the English language. For example, the term New is a
valid PowerShell verb
name because it implies an action even though it is not a
verb in the English language.
Each approved verb has a corresponding alias prefix defined. We use this alias prefix in
aliases
for commands using that verb. For example, the alias prefix for Import is ip and,
accordingly,
the alias for Import-Module is ipmo . This is a recommendation but not a
rule; in particular, it
need not be respected for command aliases mimicking well known
commands from other environments.
You may get a complete list of verbs using the Get-Verb cmdlet.
Common Verbs
PowerShell uses the
System.Management.Automation.VerbsCommon
enumeration class
to define generic actions that can apply to almost any cmdlet. The following table
lists
most of the defined verbs.
Add (a) Adds a resource to a container, or attaches an item to another Append, Attach,
item. For example, the Add-Content cmdlet adds content to a file. Concatenate,
This verb is paired with Remove . Insert
Clear (cl) Removes all the resources from a container but does not delete Flush, Erase,
the container. For example, the Clear-Content cmdlet removes Release, Unmark,
the contents of a file but does not delete the file. Unset, Nullify
Copy Copies a resource to another name or to another container. For Duplicate, Clone,
(cp) example, the Copy-Item cmdlet copies an item (such as a file) Replicate, Sync
from one location in the data store to another location.
Enter (et) Specifies an action that allows the user to move into a resource. Push, Into
For example, the Enter-PSSession cmdlet places the user in an
interactive session. This verb is paired with Exit .
Exit (ex) Sets the current environment or context to the most recently Pop, Out
used context. For example, the Exit-PSSession cmdlet places the
user in the session that was used to start the interactive session.
This verb is paired with Enter .
Find (fd) Looks for an object in a container that is unknown, implied, Search
optional, or specified.
Get (g) Specifies an action that retrieves a resource. This verb is paired Read, Open, Cat,
with Set . Type, Dir, Obtain,
Dump, Acquire,
Examine, Find,
Search
Verb Action Synonyms to
(alias) avoid
Hide (h) Makes a resource undetectable. For example, a cmdlet whose Block
name includes the Hide verb might conceal a service from a user.
This verb is paired with Show .
Join (j) Combines resources into one resource. For example, the Join- Combine, Unite,
Path cmdlet combines a path with one of its child paths to create Connect,
a single path. This verb is paired with Split . Associate
Lock (lk) Secures a resource. This verb is paired with Unlock . Restrict, Secure
Move Moves a resource from one location to another. For example, the Transfer, Name,
(m) Move-Item cmdlet moves an item from one location in the data Migrate
store to another location.
New (n) Creates a resource. (The Set verb can also be used when creating Create, Generate,
a resource that includes data, such as the Set-Variable cmdlet.) Build, Make,
Allocate
Pop Removes an item from the top of a stack. For example, the Pop-
(pop) Location cmdlet changes the current location to the location that
was most recently pushed onto the stack.
Push Adds an item to the top of a stack. For example, the Push-
(pu) Location cmdlet pushes the current location onto the stack.
Remove Deletes a resource from a container. For example, the Remove- Clear, Cut,
(r) Variable cmdlet deletes a variable and its value. This verb is Dispose, Discard,
paired with Add . Erase
Rename Changes the name of a resource. For example, the Rename-Item Change
(rn) cmdlet, which is used to access stored data, changes the name of
an item in the data store.
Select Locates a resource in a container. For example, the Select-String Find, Locate
(sc) cmdlet finds text in strings and files.
Set (s) Replaces data on an existing resource or creates a resource that Write, Reset,
contains some data. For example, the Set-Date cmdlet changes Assign, Configure
the system time on the local computer. (The New verb can also be
used to create a resource.) This verb is paired with Get .
Show Makes a resource visible to the user. This verb is paired with Display, Produce
(sh) Hide .
Skip (sk) Bypasses one or more resources or points in a sequence. Bypass, Jump
Split (sl) Separates parts of a resource. For example, the Split-Path Separate
cmdlet returns different parts of a path. This verb is paired with
Join .
Unlock Releases a resource that was locked. This verb is paired with Release,
(uk) Lock . Unrestrict,
Unsecure
Communications Verbs
PowerShell uses the
System.Management.Automation.VerbsCommunications
class to
define actions that apply to communications. The following table lists most of the
defined
verbs.
Connect Creates a link between a source and a destination. This verb is Join, Telnet
(cc) paired with Disconnect .
Verb Action Synonyms to
(alias) avoid
Disconnect Breaks the link between a source and a destination. This verb is Break, Logoff
(dc) paired with Connect .
Read (rd) Acquires information from a source. This verb is paired with Acquire, Prompt,
Write . Get
Receive Accepts information sent from a source. This verb is paired with Read, Accept,
(rc) Send . Peek
Send (sd) Delivers information to a destination. This verb is paired with Put, Broadcast,
Receive . Mail, Fax
Write (wr) Adds information to a target. This verb is paired with Read . Put, Print
Data Verbs
PowerShell uses the
System.Management.Automation.VerbsData class
to define actions
that apply to data handling. The following table lists most of the defined verbs.
Checkpoint Creates a snapshot of the current state of the data or of its Diff
(ch) configuration.
Compare (cr) Evaluates the data from one resource against the data from Diff
another resource.
Convert (cv) Changes the data from one representation to another when the Change,
cmdlet supports bidirectional conversion or when the cmdlet Resize,
supports conversion between multiple data types. Resample
ConvertFrom Converts one primary type of input (the cmdlet noun indicates the Export,
(cf) input) to one or more supported output types. Output, Out
ConvertTo Converts from one or more types of input to a primary output type Import,
(ct) (the cmdlet noun indicates the output type). Input, In
Verb Name Action Synonyms
(alias) to avoid
Dismount Detaches a named entity from a location. This verb is paired with Unmount,
(dm) Mount . Unlink
Expand (en) Restores the data of a resource that has been compressed to its Explode,
original state. This verb is paired with Compress . Uncompress
Export (ep) Encapsulates the primary input into a persistent data store, such as Extract,
a file, or into an interchange format. This verb is paired with Backup
Import .
Import (ip) Creates a resource from data that is stored in a persistent data BulkLoad,
store (such as a file) or in an interchange format. For example, the Load
Import-CSV cmdlet imports data from a comma-separated value
(CSV) file to objects that can be used by other cmdlets. This verb is
paired with Export .
Initialize (in) Prepares a resource for use, and sets it to a default state. Erase, Init,
Renew,
Rebuild,
Reinitialize,
Setup
Mount (mt) Attaches a named entity to a location. This verb is paired with Connect
Dismount .
Out (o) Sends data out of the environment. For example, the Out-Printer
cmdlet sends data to a printer.
Publish (pb) Makes a resource available to others. This verb is paired with Deploy,
Unpublish . Release,
Install
Restore (rr) Sets a resource to a predefined state, such as a state set by Repair,
Checkpoint . For example, the Restore-Computer cmdlet starts a Return,
system restore on the local computer. Undo, Fix
Sync (sy) Assures that two or more resources are in the same state. Replicate,
Coerce,
Match
Unpublish Makes a resource unavailable to others. This verb is paired with Uninstall,
(ub) Publish . Revert, Hide
Update (ud) Brings a resource up-to-date to maintain its state, accuracy, Refresh,
conformance, or compliance. For example, the Update-FormatData Renew,
cmdlet updates and adds formatting files to the current PowerShell Recalculate,
console. Re-index
Diagnostic Verbs
PowerShell uses the
System.Management.Automation.VerbsDiagnostic
class to define
actions that apply to diagnostics. The following table lists most of the defined
verbs.
Lifecycle Verbs
PowerShell uses the
System.Management.Automation.VerbsLifeCycle
class to define
actions that apply to the lifecycle of a resource. The following table lists most of
the
defined verbs.
Build (bd) Creates an artifact (usually a binary or document) out of some set
of input files (usually source code or declarative documents.) This
verb was added in PowerShell 6.
Deny (dn) Refuses, objects, blocks, or opposes the state of a resource or Block, Object,
process. Refuse, Reject
Enable (e) Configures a resource to an available or active state. For example, Start, Begin
the Enable-PSBreakpoint cmdlet makes a breakpoint active. This
verb is paired with Disable .
Install (is) Places a resource in a location, and optionally initializes it. This verb Setup
is paired with Uninstall .
Invoke (i) Performs an action, such as running a command or a method. Run, Start
Restart (rt) Stops an operation and then starts it again. For example, the Recycle
Restart-Service cmdlet stops and then starts a service.
Verb Action Synonyms to
(alias) avoid
Resume Starts an operation that has been suspended. For example, the
(ru) Resume-Service cmdlet starts a service that has been suspended.
This verb is paired with Suspend .
Start (sa) Initiates an operation. For example, the Start-Service cmdlet starts Launch,
a service. This verb is paired with Stop . Initiate, Boot
Stop (sp) Discontinues an activity. This verb is paired with Start . End, Kill,
Terminate,
Cancel
Suspend Pauses an activity. For example, the Suspend-Service cmdlet pauses Pause
(ss) a service. This verb is paired with Resume .
Unregister Removes the entry for a resource from a repository. This verb is Remove
(ur) paired with Register .
Wait (w) Pauses an operation until a specified event occurs. For example, the Sleep, Pause
Wait-Job cmdlet pauses operations until one or more of the
background jobs are complete.
Security Verbs
PowerShell uses the
System.Management.Automation.VerbsSecurity
class to define
actions that apply to security. The following table lists most of the defined verbs.
Block (bl) Restricts access to a resource. This verb is paired with Unblock . Prevent,
Limit, Deny
Grant (gr) Allows access to a resource. This verb is paired with Revoke . Allow,
Enable
Protect Safeguards a resource from attack or loss. This verb is paired with Encrypt,
(pt) Unprotect . Safeguard,
Seal
Verb Action Synonyms
(alias) to avoid
Revoke Specifies an action that does not allow access to a resource. This verb Remove,
(rk) is paired with Grant . Disable
Unblock Removes restrictions to a resource. This verb is paired with Block . Clear, Allow
(ul)
Unprotect Removes safeguards from a resource that were added to prevent it Decrypt,
(up) from attack or loss. This verb is paired with Protect . Unseal
Other Verbs
PowerShell uses the
System.Management.Automation.VerbsOther class
to define
canonical verb names that do not fit into a specific verb name category such as the
common, communications, data, lifecycle, or security verb names verbs.
See Also
System.Management.Automation.VerbsCommon
System.Management.Automation.VerbsCommunications
System.Management.Automation.VerbsData
System.Management.Automation.VerbsDiagnostic
System.Management.Automation.VerbsLifeCycle
System.Management.Automation.VerbsSecurity
System.Management.Automation.VerbsOther
Cmdlet Declaration
Windows PowerShell Programmer's Guide
Windows PowerShell Shell SDK
Cmdlet Input Processing Methods
Article • 09/17/2021
Cmdlets must override one or more of the input processing methods described in this
topic to perform their work.
These methods allow the cmdlet to perform operations of
pre-processing, input processing, and post-processing.
These methods also allow you to
stop cmdlet processing.
For a more detailed example of how to use these methods, see
SelectStr Tutorial.
Pre-Processing Operations
Cmdlets should override the System.Management.Automation.Cmdlet.BeginProcessing
method to add any preprocessing operations that are valid for all the records that will
be processed later by the cmdlet.
When PowerShell processes a command pipeline,
PowerShell calls this method once for each instance of the cmdlet in the pipeline.
For
more information about how PowerShell invokes the command pipeline, see Cmdlet
Processing Lifecycle.
C#
// Replace the WriteObject method with the logic required by your cmdlet.
C#
// Replace the WriteObject method with the logic required by your cmdlet.
Post-Processing Operations
Cmdlets should override the System.Management.Automation.Cmdlet.EndProcessing
method to add any post-processing operations that are valid for all the records that
were processed by the cmdlet.
For example, your cmdlet might have to clean up object
variables after it is finished processing.
When PowerShell processes a command pipeline, PowerShell calls this method once for
each instance of the cmdlet in the pipeline.
However, it is important to remember that
the PowerShell runtime will not call the EndProcessing method if the cmdlet is canceled
midway through its input processing or if a terminating error occurs in any part of the
cmdlet.
For this reason, a cmdlet that requires object cleanup should implement the
complete System.IDisposable pattern, including a finalizer, so that the runtime can call
both the EndProcessing and System.IDisposable.Dispose methods at the end of
processing.
For more information about how PowerShell invokes the command pipeline,
see Cmdlet Processing Lifecycle.
C#
// Replace the WriteObject method with the logic required by your cmdlet.
See Also
System.Management.Automation.Cmdlet.BeginProcessing
System.Management.Automation.Cmdlet.ProcessRecord
System.Management.Automation.Cmdlet.EndProcessing
SelectStr Tutorial
System.IDisposable
Cmdlet parameters provide the mechanism that allows a cmdlet to accept input.
Parameters can accept input directly from the command line, or from objects passed to
the cmdlet through the pipeline, The arguments (also known as values) of these
parameters can specify the input that the cmdlet accepts, how the cmdlet should
perform its actions, and the data that the cmdlet returns to the pipeline.
In This Section
Declaring Properties as Parameters
Provides basic information you must understand
before you declare the parameters of a cmdlet.
Parameter Aliases
Discusses the aliases that you can define for parameters.
Related Sections
How to Validate Parameter Input
See Also
Parameter Attribute Declaration
This topic provides basic information you must understand before you declare the
parameters of a cmdlet.
To declare the parameters of a cmdlet within your cmdlet class, define the public
properties that represent each parameter, and then add one or more Parameter
attributes to each property. The Windows PowerShell runtime uses the Parameter
attributes to identify the property as a cmdlet parameter. The basic syntax for declaring
the Parameter attribute is [Parameter()] .
C#
A parameter must be explicitly marked as public. Parameters that are not marked
as public default to internal and will not be found by the Windows PowerShell
runtime.
Avoid basic string parameters for all but free-form text properties.
You can add a parameter to any number of parameter sets. For more information
about parameter sets, see Cmdlet Parameter Sets.
Windows PowerShell also provides a set of common parameters that are automatically
available to every cmdlet. For more information about these parameters and their
aliases, see Cmdlet Common Parameters.
See Also
Cmdlet Common Parameters
This topic describes the different types of parameters that you can declare in cmdlets.
Cmdlet parameters can be positional, named, required, optional, or switch parameters.
To define a named parameter, omit the Position keyword in the Parameter attribute
declaration, as shown in the following parameter declaration.
C#
[Parameter(ValueFromPipeline=true)]
To define a positional parameter, add the Position keyword in the Parameter attribute
declaration, and then specify a position. In the following sample, the UserName
parameter is declared as a positional parameter with position 0. This means that the first
argument of the call will be automatically bound to this parameter.
C#
[Parameter(Position = 0)]
7 Note
The following commands show the different ways in which you can specify single and
multiple arguments for the parameters of the Get-Command cmdlet. Notice that in the last
two samples, -name does not need to be specified because the Name parameter is
defined as a positional parameter.
PowerShell
Get-Command get-service
Get-Command get-service,set-service
C#
To define an optional parameter, omit the Mandatory keyword in the Parameter attribute
declaration, as shown in the following parameter declaration.
C#
[Parameter(Position = 0)]
Switch Parameters
Windows PowerShell provides a System.Management.Automation.SwitchParameter type
that allows you to define a parameter whose value is automatically set to false if the
parameter is not specified when the cmdlet is called. Whenever possible, use switch
parameters in place of Boolean parameters.
Consider the following sample. By default, several Windows PowerShell cmdlets do not
pass an output object down the pipeline. However, these cmdlets have a PassThru
switch parameter that overrides the default behavior. If the PassThru parameter is
specified when these cmdlets are called, the cmdlet returns an output object to the
pipeline.
If you need the parameter to have a default value of true when the parameter is not
specified in the call, consider reversing the sense of the parameter. For sample, instead
of setting the parameter attribute to a Boolean value of true , declare the property as
the System.Management.Automation.SwitchParameter type, and then set the default
value of the parameter to false .
C#
[Parameter(Position = 1)]
To make the cmdlet act on the parameter when it is specified, use the following
structure within one of the input processing methods.
C#
if(goodbye)
WriteObject(" Goodbye!");
} // End ProcessRecord
See Also
Writing a Windows PowerShell Cmdlet
Standard Cmdlet Parameter Names and
Types
Article • 09/17/2021
Cmdlet parameter names should be consistent across the cmdlets that you design. The
following topics list the parameter names that we recommend you use when you
declare cmdlet parameters. The topics also describe the recommended data type and
functionality of each parameter.
In This Section
Activity Parameters
Format Parameters
Property Parameters
Quantity Parameters
Resource Parameters
Security Parameters
Activity Parameters
Article • 06/23/2022
The following table lists the recommended names and functionality for activity
parameters.
Parameter Functionality
Append
Implement this parameter so that the user can add content to the end of a
Data type: resource when the parameter is specified.
SwitchParameter
CaseSensitive
Implement this parameter so the user can require case sensitivity when the
Data type: parameter is specified.
SwitchParameter
Command
Implement this parameter so the user can specify a command string to run.
Data type: String
CompatibleVersion
Implement this parameter so the user can specify the semantics that the
Data type: cmdlet must be compatible with for compatibility with previous versions.
System.Version
object
Compress
Implement this parameter so that data compression is used when the
Data type: parameter is specified.
SwitchParameter
Compress
Implement this parameter so that the user can specify the algorithm to use
Data type: Keyword for data compression.
Continuous
Implement this parameter so that data is processed until the user
Data type: terminates the cmdlet when the parameter is specified. If the parameter is
SwitchParameter not specified, the cmdlet processes a predefined amount of data and then
terminates the operation.
Create
Implement this parameter to indicate that a resource is created if one does
Data type: not already exist when the parameter is specified.
SwitchParameter
Delete
Implement this parameter so that resources are deleted when the cmdlet
Data type: has completed its operation when the parameter is specified.
SwitchParameter
Drain
Implement this parameter to indicate that outstanding work items are
Data type: processed before the cmdlet processes new data when the parameter is
SwitchParameter specified. If the parameter is not specified, the work items are processed
immediately.
Parameter Functionality
Erase
Implement this parameter so that the user can specify the number of times
Data type: Int32 a resource is erased before it is deleted.
ErrorLevel
Implement this parameter so that the user can specify the level of errors to
Data type: Int32 report.
Exclude
Implement this parameter so that the user can exclude something from an
Data type: String[] activity. For more information about how to use input filters, see Input Filter
Parameters.
Filter
Implement this parameter so that the user can specify a filter that selects
Data type: Keyword the resources upon which to perform the cmdlet action. For more
information about how to use input filters, see Input Filter Parameters.
Follow
Implement this parameter so that progress is tracked when the parameter is
Data type: specified.
SwitchParameter
Force
Implement this parameter to indicate that the user can perform an action
Data type: even if restrictions are encountered when the parameter is specified. The
SwitchParameter parameter does not allow security to be compromised. For example, this
parameter lets a user overwrite a read-only file.
Include
Implement this parameter so that the user can include something in an
Data type: String[] activity. For more information about how to use input filters, see Input Filter
Parameters.
Incremental
Implement this parameter to indicate that processing is performed
Data type: incrementally when the parameter is specified. For example, this parameter
SwitchParameter lets a user perform incremental backups that back up files only since the
last backup.
InputObject
Implement this parameter when the cmdlet takes input from other cmdlets.
Data type: Object When you define an InputObject parameter, always specify the
ValueFromPipeline keyword when you declare the Parameter attribute. For
more information about using input filters, see Input Filter Parameters.
Insert
Implement this parameter so that the cmdlet inserts an item when the
Data type: parameter is specified.
SwitchParameter
Interactive
Implement this parameter so that the cmdlet works interactively with the
Data type: user when the parameter is specified.
SwitchParameter
Interval
Implement this parameter so that the user can specify a hash table of
Data type: keywords that contains the values. The following example shows sample
HashTable values for the Interval parameter: -interval @{ResumeScan=15; Retry=3} .
Parameter Functionality
Log
Implement this parameter audit the actions of the cmdlet when the
Data type: parameter is specified.
SwitchParameter
NoClobber
Implement this parameter so that the resource will not be overwritten when
Data type: the parameter is specified. This parameter generally applies to cmdlets that
SwitchParameter create new objects so that they can be prevented from overwriting existing
objects with the same name.
Notify Implement this parameter so that the user will be notified that the activity is
Data type: complete when the parameter is specified.
SwitchParameter
NotifyAddress
Implement this parameter so that the user can specify the e-mail address to
Data type: Email use to send a notification when the Notify parameter is specified.
address
Overwrite
Implement this parameter so that the cmdlet overwrites any existing data
Data type: when the parameter is specified.
SwitchParameter
Prompt
Implement this parameter so that the user can specify a prompt for the
Data type: String cmdlet.
Quiet
Implement this parameter so that the cmdlet suppresses user feedback
Data type: during its actions when the parameter is specified.
SwitchParameter
Recurse
Implement this parameter so that the cmdlet recursively performs its
Data type: actions on resources when the parameter is specified.
SwitchParameter
Repair
Implement this parameter so that the cmdlet will attempt to correct
Data type: something from a broken state when the parameter is specified.
SwitchParameter
RepairString
Implement this parameter so that the user can specify a string to use when
Data type: String the Repair parameter is specified.
Retry
Implement this parameter so the user can specify the number of times the
Data type: Int32 cmdlet will attempt an action.
Select
Implement this parameter so that the user can specify an array of the types
Data type: Keyword of items.
array
Stream
Implement this parameter so the user can stream multiple output objects
Data type: through the pipeline when the parameter is specified.
SwitchParameter
Parameter Functionality
Strict
Implement this parameter so that all errors are handled as terminating
Data type: errors when the parameter is specified.
SwitchParameter
TempLocation
Implement this parameter so the user can specify the location of temporary
Data type: String data that is used during the operation of the cmdlet.
Timeout
Implement this parameter so that the user can specify the timeout interval
Data type: Int32 (in milliseconds).
Truncate
Implement this parameter so that the cmdlet will truncate its actions when
Data type: the parameter is specified. If the parameter is not specified, the cmdlet
SwitchParameter performs another action.
Verify
Implement this parameter so that the cmdlet will test to determine whether
Data type: an action has occurred when the parameter is specified.
SwitchParameter
Wait Implement this parameter so that the cmdlet will wait for user input before
Data type: continuing when the parameter is specified.
SwitchParameter
WaitTime
Implement this parameter so that the user can specify the duration (in
Data type: Int32 seconds) that the cmdlet will wait for user input when the Wait parameter is
specified.
See Also
Cmdlet Parameters
The following table lists recommended names and functionality for parameters that
handle date and time information. Date and time parameters are typically used to
record when something is created or accessed.
Parameter Functionality
Accessed
Implement this parameter so that when it is specified the cmdlet will operate
Data type: on the resources that have been accessed based on the date and time
SwitchParameter specified by the Before and After parameters. If this parameter is specified, the
Created and Modified parameters must be not be specified.
After
Implement this parameter to specify the date and time after which the cmdlet
Data type: was used. For the After parameter to work, the cmdlet must also have an
DateTime Accessed, Created, or Modified parameter. And, that parameter must be set to
true when the cmdlet is called.
Before
Implement this parameter to specify the date and time before which the
Data type: cmdlet was used. For the Before parameter to work, the cmdlet must also have
DateTime an Accessed, Created, or Modified parameter. And, that parameter must be
set to true when the cmdlet is called.
Created
Implement this parameter so that when it is specified the cmdlet will operate
Data type: on the resources that have been created based on the date and time specified
SwitchParameter by the Before and After parameters. If this parameter is specified, the
Accessed and Modified parameters must not be specified.
Exact
Implement this parameter so that when it is specified the resource term must
Data type: match the resource name exactly. When the parameter is not specified the
SwitchParameter resource term and name do not need to match exactly.
Modified
Implement this parameter so that when it is specified the cmdlet will operate
Data type: on resources that have been changed based on the date and time specified by
DateTime the Before and After parameters. If this parameter is specified, the Accessed
and Created parameters must not be specified.
See Also
Cmdlet Parameters
The following table lists recommended names and functionality for parameters that are
used to format or to generate data.
Parameter Functionality
As
Implement this parameter to specify the cmdlet output format. For example,
Data type: possible values could be Text or Script.
Keyword
Binary
Implement this parameter to indicate that the cmdlet handles binary values.
Data type:
SwitchParameter
Encoding
Implement this parameter to specify the type of encoding that is supported.
Data type: For example, possible values could be ASCII, UTF8, Unicode, UTF7,
Keyword BigEndianUnicode, Byte, and String.
NewLine
Implement this parameter so that the newline characters are supported when
Data type: the parameter is specified.
SwitchParameter
ShortName
Implement this parameter so that short names are supported when the
Data type: parameter is specified.
SwitchParameter
Width
Implement this parameter so that the user can specify the width of the output
Data type: Int32 device.
Wrap
Implement this parameter so that text wrapping is supported when the
Data type: parameter is specified.
SwitchParameter
See Also
Cmdlet Parameters
The following table lists the recommended names and functionality for property
parameters.
Parameter Functionality
Count
Implement this parameter so that the user can specify the number of objects
Data type: Int32 to be processed.
Description
Implement this parameter so that the user can specify a description for a
Data type: String resource.
From
Implement this parameter so that the user can specify the reference object to
Data type: String get information from.
Id
Implement this parameter so that the user can specify the identifier of a
Data type: resource.
Resource
dependent
Input
Implement this parameter so that the user can specify the input file
Data type: String specification.
Location
Implement this parameter so that the user can specify the location of the
Data type: String resource.
LogName
Implement this parameter so that the user can specify the name of the log file
Data type: String to process or use.
Name
Implement this parameter so that the user can specify the name of the
Data type: String resource.
Output
Implement this parameter so that the user can specify the output file.
Data type: String
Owner
Implement this parameter so that the user can specify the name of the owner
Data type: String of the resource.
Property
Implement this parameter so that the user can specify the name or the names
Data type: String of the properties to use.
Reason
Implement this parameter so that the user can specify why this cmdlet is being
Data type: String invoked.
Regex
Implement this parameter so that regular expressions are used when the
Data type: parameter is specified. When this parameter is specified, wildcard characters
SwitchParameter are not resolved.
Parameter Functionality
Speed
Implement this parameter so that the user can specify the baud rate. The user
Data type: Int32 sets this parameter to the speed of the resource.
State
Implement this parameter so that the user can specify the names of states,
Data type: such as KEYDOWN.
Keyword array
Value
Implement this parameter so that the user can specify a value to provide to
Data type: the cmdlet.
Object
Version
Implement this parameter so that the user can specify the version of the
Data type: String property.
See Also
Cmdlet Parameters
The following table lists the recommended names and functionality for quantity
parameters.
Parameter Functionality
All
Implement this parameter so that true indicates that all resources should be acted
Data type: upon instead of a default subset of resources. Implement this parameter so that
Boolean false indicates a subset of the resources.
Allocation
Implement this parameter so that the user can specify the number of items to
Data type: allocate.
Int32
BlockCount
Implement this parameter so that the user can specify the block count.
Data type:
Int64
Count
Implement this parameter so that the user can specify the count.
Data type:
Int64
Scope
Implement this parameter so that the user can specify the scope to operate on.
Data type:
Keyword
See Also
Cmdlet Parameters
The following table lists the recommended names and functionality for resource
parameters. For these parameters, the resources could be the assembly that contains
the cmdlet class or the host application that is running the cmdlet.
Parameter Functionality
Application
Implement this parameter so that the user can specify an application.
Data type:
String
Assembly
Implement this parameter so that the user can specify an assembly.
Data type:
String
Attribute
Implement this parameter so that the user can specify an attribute.
Data type:
String
Class
Implement this parameter so that the user can specify a Microsoft .NET Framework
Data type: class.
String
Cluster
Implement this parameter so that the user can specify a cluster.
Data type:
String
Culture
Implement this parameter so that the user can specify the culture in which to run
Data type: the cmdlet.
String
Domain
Implement this parameter so that the user can specify the domain name.
Data type:
String
Drive
Implement this parameter so that the user can specify a drive name.
Data type:
String
Event
Implement this parameter so that the user can specify an event name.
Data type:
String
Interface
Implement this parameter so that the user can specify a network interface name.
Data type:
String
Parameter Functionality
IpAddress
Implement this parameter so that the user can specify an IP address.
Data type:
String
Job
Implement this parameter so that the user can specify a job.
Data type:
String
LiteralPath
Implement this parameter so that the user can specify the path to a resource when
Data type: wildcard characters are not supported. (Use the Path parameter when wildcard
String characters are supported.)
Mac
Implement this parameter so that the user can specify a media access controller
Data type: (MAC) address.
String
ParentId
Implement this parameter so that the user can specify the parent identifier.
Data type:
String
Path
Implement this parameter so that the user can indicate the paths to a resource
Data type: when wildcard characters are supported. (Use the LiteralPath parameter when
String, wildcard characters are not supported.) We recommend that you develop this
String[] parameter so that it supports the full provider:path syntax used by providers. We
also recommend that you develop it so that it works with as many providers as
possible.
Port
Implement this parameter so that the user can specify an integer value for
Data type: networking or a string value such as "biztalk" for other types of port.
Integer,
String
Printer
Implement this parameter so that the user can specify the printer for the cmdlet to
Data type: use.
Integer,
String
Size
Implement this parameter so that the user can specify a size.
Data type:
Int32
TID
Implement this parameter so that the user can specify a transaction identifier (TID)
Data type: for the cmdlet.
String
Type Implement this parameter so that the user can specify the type of resource on
Data type: which to operate.
String
Parameter Functionality
URL
Implement this parameter so that the user can specify a Uniform Resource Locator
Data type: (URL).
String
User
Implement this parameter so that the user can specify their name or the name of
Data type: another user.
String
See Also
Cmdlet Parameters
The following table lists the recommended names and functionality for parameters used
to provide security information for an operation, such as parameters that specify
certificate key and privilege information.
Parameter Functionality
ACL
Implement this parameter to specify the access
Data type: String control level of protection for a catalog or for a
Uniform Resource Identifier (URI).
CertFile
Implement this parameter so that the user can
Data type: String specify the name of a file that contains one of
the following:
CertIssuerName
Implement this parameter so that the user can
Data type: String specify the name of the issuer of a certificate or
so that the user can specify a substring.
CertRequestFile
Implement this parameter to specify the name of
Data type: String a file that contains a Base64 or DER-encoded
PKCS #10 certificate request.
CertStoreLocation
Implement this parameter so that the user can
Data type: String specify the location of the certificate store. The
location is typically a file path.
CertSubjectName
Implement this parameter so that the user can
Data type: String specify the issuer of a certificate or so that the
user can specify a substring.
CertUsage
Implement this parameter to specify the key
Data type: String usage or the enhanced key usage. The key can
be represented as a bit mask, a bit, an object
identifier (OID), or a string.
Parameter Functionality
Credential
Implement this parameter so that the cmdlet will
Data type: automatically prompt the user for a user name
System.Management.Automation.PSCredential or password. A prompt for both is displayed if a
full credential is not supplied directly.
CSPName
Implement this parameter so that the user can
Data type: String specify the name of the certificate service
provider (CSP).
CSPType
Implement this parameter so that the user can
Data type: Integer specify the type of CSP.
Group
Implement this parameter so that the user can
Data type: String specify a collection of principals for access. For
more information, see the description of the
Principal parameter.
KeyAlgorithm
Implement this parameter so that the user can
Data type: String specify the key generation algorithm to use for
security.
KeyContainerName
Implement this parameter so that the user can
Data type: String specify the name of the key container.
KeyLength
Implement this parameter so that the user can
Data type: Integer specify the length of the key in bits.
Operation
Implement this parameter so that the user can
Data type: String specify an action that can be performed on a
protected object.
Principal
Implement this parameter so that the user can
Data type: String specify a unique identifiable entity for access.
Privilege
Implement this parameter so that the user can
Data type: String specify the right a cmdlet needs to perform an
operation for a particular entity.
Privileges
Implement this parameter so that the user can
Data type: Array of privileges specify the rights that a cmdlet needs to perform
its operation for a particular entry.
Role
Implement this parameter so that the user can
Data type: String specify a set of operations that can be
performed by an entity.
SaveCred
Implement this parameter so that credentials
Data type: SwitchParameter that were previously saved by the user will be
used when the parameter is specified.
Parameter Functionality
Scope
Implement this parameter so that the user can
Data type: String specify the group of protected objects for the
cmdlet.
SID
Implement this parameter so that the user can
Data type: String specify a unique identifier that represents a
principal.
Trusted
Implement this parameter so that trust levels are
Data type: SwitchParameter supported when the parameter is specified.
TrustLevel
Implement this parameter so that the user can
Data type: Keyword specify the trust level that is supported. For
example, possible values include internet,
intranet, and fulltrust.
See Also
Cmdlet Parameters
Cmdlet parameters can also have aliases. You can use the aliases instead of the
parameter names when you type or specify the parameter in a command.
You can provide a shortcut so that the user does not have to use the complete
parameter name when the cmdlet is called. For example, you could use the "CN"
alias instead of the parameter name "ComputerName".
You can define multiple aliases if you want to provide different names for the same
parameter. You might want to define multiple aliases if you have to work with
multiple user groups that refer to the same data in different ways.
You can provide backwards compatibility for existing scripts if the name of a
parameter changes.
For more information about aliases that can be used with specific parameters, see
Common Parameter Names.
C#
[Alias("UN","Writer","Editor")]
[Parameter()]
See Also
Common Parameter Names
The parameters described in this topic are referred to as common parameters. They are
added to
cmdlets by the Windows PowerShell runtime and cannot be declared by the
cmdlet.
7 Note
These parameters are also added to provider cmdlets and to functions that are
decorated with the
CmdletBinding attribute.
This parameter specifies whether the cmdlet displays a prompt that asks if the user is
sure that
they want to continue.
This parameter specifies the variable in which to place objects when an error occurs. To
append to
this variable, use +varname rather than clearing and setting the variable.
This parameter defines the number of objects to store in the output buffer before any
objects are
passed down the pipeline. By default, objects are passed immediately down
the pipeline.
This parameter specifies the variable in which to place all output objects generated by
the cmdlet.
To append to this variable, use +varname rather than clearing and setting
the variable.
This parameter stores the value of the current pipeline element as a variable for any
named command
as it flows through the pipeline.
This parameter specifies whether the cmdlet writes explanatory messages that can be
displayed at the
command line. These messages are intended to provide additional help
to the user, and are generated
by calls to the
System.Management.Automation.Cmdlet.WriteVerbose
method.
WarningAction (alias: wa)
Data type: Enumeration
This parameter specifies what action should take place when the cmdlet writes a
warning message. The
possible values for this parameter are defined by the
System.Management.Automation.Actionpreference
enumeration.
This parameter specifies the variable in which warning messages can be saved. To
append to this
variable, use +varname rather than clearing and setting the variable.
Risk-Mitigation Parameters
The following parameters are added to cmdlets that requests confirmation before they
perform their
action. For more information about confirmation requests, see Requesting
Confirmation.
These parameters are defined by the
System.Management.Automation.Internal.Shouldprocessparameters
class.
This parameter specifies whether the cmdlet writes a message that describes the effects
of running
the cmdlet without actually performing any action.
Transaction Parameters
The following parameter is added to cmdlets that support transactions. These
parameters are defined
by the
System.Management.Automation.Internal.Transactionparameters
class. Transaction
support was introduced in PowerShell 3.0 and discontinued in PowerShell 6.0.
See Also
System.Management.Automation.Internal.Commonparameters
System.Management.Automation.Internal.Shouldprocessparameters
System.Management.Automation.Internal.Transactionparameters
PowerShell uses parameter sets to enable you to write a single cmdlet that can do
different actions
for different scenarios. Parameter sets enable you to expose different
parameters to the user. And,
to return different information based on the parameters
specified by the user.
Unique parameter
Each parameter set must have a unique parameter that the PowerShell runtime uses to
expose the
appropriate parameter set. If possible, the unique parameter should be a
mandatory parameter. When a
parameter is mandatory, the user must specify the
parameter, and the PowerShell runtime uses that
parameter to identify the parameter
set. The unique parameter can't be mandatory if your cmdlet is
designed to run without
specifying any parameters.
Each parameter set must have at least one unique parameter. If possible, make this
parameter a
mandatory parameter.
A parameter set that contains multiple positional parameters must define unique
positions for each
parameter. No two positional parameters can specify the same
position.
Only one parameter in a set can declare the ValueFromPipeline keyword with a
value of true .
Multiple parameters can define the
ValueFromPipelineByPropertyName keyword with a value of
true .
7 Note
C#
[Parameter(ParameterSetName = "Test02")]
Cmdlets can define parameters that are available to the user under special conditions,
such as when
the argument of another parameter is a specific value. These parameters
are added at runtime and are
referred to as dynamic parameters because they're only
added when needed. For example, you can
design a cmdlet that adds several
parameters only when a specific switch parameter is specified.
7 Note
The following examples show how the CodeSigningCert parameter is added at runtime
when
Get-Item is run.
In this example, the PowerShell runtime has added the parameter and the cmdlet is
successful.
PowerShell
Output
Location : CurrentUser
In this example, a FileSystem drive is specified and an error is returned. The error
message
indicates that the CodeSigningCert parameter can't be found.
PowerShell
Output
At line:1 char:37
--------
FullyQualifiedErrorId :
NamedParameterNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Interface
System.Management.Automation.IDynamicParameters.
This interface provides the
method that retrieves the dynamic parameters.
For example:
Method
System.Management.Automation.IDynamicParameters.GetDynamicParameters.
This
method retrieves the object that contains the dynamic parameter definitions.
For example:
C#
if (employee)
return context;
return null;
Class
A class that defines the dynamic parameters to be added. This class must include a
Parameter
attribute for each parameter and any optional Alias and Validation attributes
that are
needed by the cmdlet.
For example:
C#
[Parameter]
For a complete example of a cmdlet that supports dynamic parameters, see How to
Declare Dynamic Parameters.
See also
System.Management.Automation.IDynamicParameters
System.Management.Automation.IDynamicParameters.GetDynamicParameters
Often, you will have to design a cmdlet to run against a group of resources rather than
against a
single resource. For example, a cmdlet might need to locate all the files in a
data store that have
the same name or extension. You must provide support for wildcard
characters when you design a
cmdlet that will be run against a group of resources.
7 Note
Get-Command get-*
When you design cmdlets that support wildcard characters, allow for combinations of
wildcard
characters. For example, the following command uses the Get-ChildItem
cmdlet to retrieve all the
.txt files that are in the c:\Techdocs folder and that begin with
the letters "a" through "l."
Get-ChildItem c:\techdocs\[a-l]\*.txt
The previous command uses the range wildcard [a-l] to specify that the file name
should begin
with the characters "a" through "l" and uses the * wildcard character as a
placeholder
for any characters between the first letter of the filename and the .txt
extension.
The following example uses a range wildcard pattern that excludes the letter "d" but
includes all
the other letters from "a" through "f."
Get-ChildItem c:\techdocs\[a-cef]\*.txt
This pattern matches "John Smith [Marketing]" or "John Smith [Development]". For
example:
True
True
See Also
Writing a Windows PowerShell Cmdlet
WildcardPattern Class
Validating Parameter Input
Article • 09/17/2021
PowerShell can validate the arguments passed to cmdlet parameters in several ways.
PowerShell can
validate the length, the range, and the pattern of the characters of the
argument. It can validate
the number of arguments available (the count). These
validation rules are defined by validation
attributes that are declared with the Parameter
attribute on public properties of the cmdlet class.
ValidateCount
Specifies the minimum and maximum number of arguments that a parameter can
accept. For more
information, see ValidateCount Attribute Declaration.
ValidateLength
Specifies the minimum and maximum number of characters in the parameter argument.
For more
information, see ValidateLength Attribute Declaration.
ValidatePattern
Specifies a regular expression that validates the parameter argument. For more
information, see
ValidatePattern Attribute Declaration.
ValidateRange
Specifies the minimum and maximum values of the parameter argument. For more
information, see
ValidateRange Attribute Declaration.
ValidateScript
Specifies the valid values for the parameter argument. For more information, see
ValidateScript Attribute Declaration.
ValidateSet
Specifies the valid values for the parameter argument. For more information, see
ValidateSet Attribute Declaration.
See Also
How to Validate Parameter Input
A cmdlet can define Filter , Include , and Exclude parameters that filter the set of input
objects that the cmdlet affects.
Filter Parameter
The Filter parameter specifies a filter that is not expressed in the standard wildcard
language. For example, Active Directory Service Interfaces (ADSI) or SQL filters might be
passed to the cmdlet through its Filter parameter. In the cmdlets provided by
Windows PowerShell, these filters are specified by the Windows PowerShell providers
that use the cmdlet to access a data store. Each provider typically defines its own filter.
See Also
Writing a Windows PowerShell Cmdlet
Cmdlet Attributes
Article • 09/17/2021
Windows PowerShell defines several attributes that you can use to add common
functionality to your
cmdlets without implementing that functionality within your own
code. This includes the Cmdlet
attribute that identifies a Microsoft .NET Framework class
as a cmdlet class, the OutputType
attribute that specifies the .NET Framework types
returned by the cmdlet, the Parameter attribute
that identifies public properties as
cmdlet parameters, and more.
In This Section
Attributes in Cmdlet Code Describes the benefit of using
attributes in cmdlet code.
Reference
Writing a Windows PowerShell Cmdlet
Attributes in Cmdlet Code
Article • 09/17/2021
To use the common functionality provided by Windows PowerShell, the classes and
public properties defined in the cmdlet code are decorated with attributes. For example,
the following class definition uses the Cmdlet attribute to identify the Microsoft .NET
Framework class in which the Get-Proc cmdlet is implemented. (This cmdlet is used as
an example in this document, and is similar to the Get-Process cmdlet provided by
Windows PowerShell.)
C#
[Cmdlet(VerbsCommon.Get, "Proc")]
Although you might want to implement your own version of the functionality provided
by these attributes, a good cmdlet design uses these common functionalities.
For more information about the different attributes that can be declared in your
cmdlets, see Attribute Types.
See Also
Attribute Types
Cmdlet Attributes
Cmdlet
Identifies a .NET Framework class as a cmdlet.
This is the required base attribute.
For
more information, see Cmdlet Attribute Declaration.
Parameter Attributes
Parameter
Identifies a public property in the cmdlet class as a cmdlet parameter.
For more
information, see Parameter Attribute Declaration.
Alias
Specifies one or more aliases for a parameter.
For more information, see Alias Attribute
Declaration.
ValidateCount
Specifies the minimum and maximum number of arguments that are allowed for a
cmdlet parameter.
For more information, see ValidateCount Attribute Declaration.
ValidateLength
Specifies a minimum and maximum number of characters for a cmdlet parameter
argument.
For more information, see ValidateLength Attribute Declaration.
ValidatePattern
Specifies a regular expression pattern that the cmdlet parameter argument must match.
For more information, see ValidatePattern Attribute Declaration.
ValidateRange
Specifies the minimum and maximum values for a cmdlet parameter argument.
For
more information, see ValidateRange Attribute Declaration.
ValidateSet
Specifies a set of valid values for the cmdlet parameter argument.
For more information,
see ValidateSet Attribute Declaration.
See Also
Windows PowerShell SDK
Alias Attribute Declaration
Article • 09/17/2021
The Alias attribute allows the user to specify different names for a cmdlet or a cmdlet
parameter. Aliases can be used to provide shortcuts for a parameter name, or they can
provide
different names that are appropriate for different scenarios.
Syntax
C#
[Alias(aliasNames)]
Parameters
aliasNames (String[])
Required. Specifies a set of comma-separated alias names for the
cmdlet parameter.
Remarks
The Alias attribute is defined by the
System.Management.Automation.Aliasattribute
class.
Cmdlet aliases
The Alias attribute is used with the cmdlet declaration. For more information about
how to
declare these attributes, see Cmdlet Aliases.
Each parameter alias name must be unique. Windows PowerShell does not check
for duplicate alias
names.
Parameter aliases
The Alias attribute is used with the Parameter attribute when you specify a cmdlet
parameter. For more information about how to declare these attributes, see How
to Declare Cmdlet Parameters.
Each parameter alias name must be unique within a cmdlet. Windows PowerShell
does not check for
duplicate alias names.
The Alias attribute is used once for each parameter in a cmdlet.
See Also
Cmdlet Aliases
Parameter Aliases
The Cmdlet attribute identifies a Microsoft .NET Framework class as a cmdlet and
specifies the verb and noun used to invoke the cmdlet.
Syntax
C#
[Cmdlet("verbName", "nounName")]
Parameters
VerbName (System.String)
Required. Specifies the cmdlet verb. This verb specifies the
action taken by the cmdlet. For more information about approved cmdlet verbs, see
Cmdlet Verb Names and Required Development Guidelines.
NounName (System.String)
Required. Specifies the cmdlet noun. This noun specifies the
resource that the cmdlet acts upon. For more information about cmdlet nouns, see
Cmdlet Declaration and Strongly Encouraged Development Guidelines.
SupportsShouldProcess (System.Boolean)
Optional named parameter. True indicates
ConfirmImpact (System.Management.Automation.Confirmimpact)
Optional named
parameter. Specifies when the action of the cmdlet should be confirmed by a call to the
System.Management.Automation.Cmdlet.ShouldProcess method.
System.Management.Automation.Cmdlet.ShouldProcess will only be called when the
ConfirmImpact value of the cmdlet (by default, Medium) is equal to or greater than the
value of the $ConfirmPreference variable. This parameter should be specified only when
the SupportsShouldProcess parameter is specified.
DefaultParameterSetName (System.String)
Optional named parameter. Specifies the
default parameter set that the Windows PowerShell runtime attempts to use when it
cannot determine which parameter set to use. Notice that this situation can be
eliminated by making the unique parameter of each parameter set a mandatory
parameter.
There is one case where Windows PowerShell cannot use the default parameter set even
if a default parameter set name is specified. The Windows PowerShell runtime cannot
distinguish between parameter sets based solely on object type. For example, if you
have one parameter set that takes a string as the file path, and another set that takes a
FileInfo object directly, Windows PowerShell cannot determine which parameter set to
use based on the values passed to the cmdlet, nor does it use the default parameter set.
In this case, even if you specify a default parameter set name, Windows PowerShell
throws an ambiguous parameter set error message.
SupportsTransactions (System.Boolean)
Optional named parameter. True indicates that
the cmdlet can be used within a transaction. When True is specified, the Windows
PowerShell runtime adds the UseTransaction parameter to the parameter list of the
cmdlet. False , the default value, indicates that the cmdlet cannot be used within a
transaction.
Remarks
Together, the verb and noun are used to identify your registered cmdlet and to
invoke your cmdlet within a script.
When the cmdlet is invoked from the Windows PowerShell console, the command
resembles the following command:
VerbName-NounName
All cmdlets that change resources outside of Windows PowerShell should include
the SupportsShouldProcess keyword when the Cmdlet attribute is declared, which
allows the cmdlet to call the
System.Management.Automation.Cmdlet.ShouldProcess method before the cmdlet
performs its action. If the System.Management.Automation.Cmdlet.ShouldProcess
call returns false , the action should not be taken. For more information about the
confirmation requests generated by the
System.Management.Automation.Cmdlet.ShouldProcess call, see Requesting
Confirmation.
The Confirm and WhatIf cmdlet parameters are available only for cmdlets that support
System.Management.Automation.Cmdlet.ShouldProcess calls.
Example
The following class definition uses the Cmdlet attribute to identify the .NET Framework
class for a Get-Proc cmdlet that retrieves information about the processes running on
the local computer.
C#
[Cmdlet(VerbsCommon.Get, "Proc")]
For more information about the Get-Proc cmdlet, see GetProc Tutorial.
See Also
Writing a Windows PowerShell Cmdlet
Credential Attribute Declaration
Article • 09/17/2021
The Credential attribute is an optional attribute that can be used with credential
parameters of type System.Management.Automation.PSCredential so that a string can
also be passed as an argument to the parameter. When this attribute is added to a
parameter declaration, Windows PowerShell converts the string input into a
System.Management.Automation.PSCredential object. For example, the Get-Credential
cmdlet uses this attribute to have Windows PowerShell generate the
System.Management.Automation.PSCredential object that is returned by the cmdlet.
Syntax
C#
[Credential]
Remarks
Typically this attribute is used by parameters of type
System.Management.Automation.PSCredential so that a string can also be passed
as an argument to the parameter. When a
System.Management.Automation.PSCredential object is passed to the parameter,
Windows PowerShell does nothing.
This attribute is used with the Parameter attribute. For more information about
that attribute, see Parameter Attribute Declaration.
See Also
Parameter Aliases
The OutputType attribute identifies the .NET Framework types returned by a cmdlet,
function, or script.
Syntax
C#
Parameters
ParameterSetName (string[])
Optional. Specifies the parameter sets that return the types
specified in the type parameter.
providerCmdlet
Optional. Specifies the provider cmdlet that returns the types specified
in the type parameter.
See Also
Writing a Windows PowerShell Cmdlet
Parameter Attribute Declaration
Article • 09/17/2021
The Parameter attribute identifies a public property of the cmdlet class as a cmdlet
parameter.
Syntax
C#
[Parameter()]
[Parameter(Named Parameters...)]
Parameters
Mandatory (System.Boolean)
Optional named parameter. True indicates the cmdlet
parameter is required. If a required parameter is not provided when the cmdlet is
invoked, Windows PowerShell prompts the user for a parameter value. The default is
false .
ParameterSetName (System.String)
Optional named parameter. Specifies the parameter
set that this cmdlet parameter belongs to. If no parameter set is specified, the parameter
belongs to all parameter sets.
Position (System.Int32)
Optional named parameter. Specifies the position of the
ValueFromPipeline (System.Boolean)
Optional named parameter. True indicates that the
cmdlet parameter takes its value from a pipeline object. Specify this keyword if the
cmdlet accesses the complete object, not just a property of the object. The default is
false .
ValueFromPipelineByPropertyName (System.Boolean)
Optional named parameter. True
indicates that the cmdlet parameter takes its value from a property of a pipeline object
that has either the same name or the same alias as this parameter. For example, if the
cmdlet has a Name parameter and the pipeline object also has a Name property, the value
of the Name property is assigned to the Name parameter of the cmdlet. The default is
false .
ValueFromRemainingArguments (System.Boolean)
Optional named parameter. True
indicates that the cmdlet parameter accepts all remaining arguments that are passed to
the cmdlet. The default is false .
HelpMessage
Optional named parameter. Specifies a short description of the parameter.
Windows PowerShell displays this message when a cmdlet is run and a mandatory
parameter is not specified.
HelpMessageBaseName
Optional named parameter. Specifies the location where resource
identifiers reside. For example, this parameter could specify a resource assembly that
contains Help messages that you want to localize.
HelpMessageResourceId
Optional named parameter.Specifies the resource identifier for a
Help message.
Remarks
For more information about how to declare this attribute, see How to Declare
Cmdlet Parameters.
A cmdlet can have any number of parameters. However, for a better user
experience, limit the number of parameters.
When you specify positional parameters, limit the number of positional parameters
in a parameter set to less than five. And, positional parameters do not have to be
contiguous. Positions 5, 100, and 250 work the same as positions 0, 1, and 2.
When the Position keyword is not specified, the cmdlet parameter must be
referenced by its name.
Each parameter set must have at least one unique parameter. Good cmdlet
design indicates this unique parameter should also be mandatory if possible. If
your cmdlet is designed to be run without parameters, the unique parameter
cannot be mandatory.
No parameter set should contain more than one positional parameter with the
same position.
For more information about the guidelines for parameter names, see Cmdlet
Parameter Names.
See Also
System.Management.Automation.Parameterattribute
The ValidateCount attribute specifies the minimum and maximum number of arguments
allowed for a cmdlet parameter.
Syntax
C#
Parameters
MinLength (System.Int32)
Required. Specifies the minimum number of arguments.
MaxLength (System.Int32)
Required. Specifies the maximum number of arguments.
Remarks
For more information about how to declare this attribute, see
How to Validate an
Argument Count.
When this attribute is not invoked, the corresponding cmdlet parameter can have
any number of
arguments.
The Windows PowerShell runtime throws an error under the following conditions:
The MinLength and MaxLength attribute parameters are not of type
System.Int32.
The value of the MaxLength attribute parameter is less than the value of the
MinLength
attribute parameter.
See Also
System.Management.Automation.ValidateCountAttribute
The ValidateLength attribute specifies the minimum and maximum number of characters
for a cmdlet parameter argument. This attribute can also be used by Windows
PowerShell functions.
Syntax
C#
Parameters
MinLength (System.Int32)
Required. Specifies the minimum number of characters
allowed.
MaxLength (System.Int32)
Required. Specifies the maximum number of characters
allowed.
Remarks
For more information about how to declare this attribute, see How to Declare
Input Validation Rules.
When this attribute is not used, the corresponding parameter argument can be of
any length.
The Windows PowerShell runtime throws an error under the following conditions:
When the value of the MaxLength attribute parameter is less than the value of
the MinLength attribute parameter.
The ValidatePattern attribute specifies a regular expression pattern that validates the
argument of a cmdlet parameter. This attribute can also be used by Windows
PowerShell functions.
Syntax
C#
[ValidatePattern(string regexString)]
Parameters
RegexString (System.String)
Required. Specifies a regular expression that validates the
parameter argument.
Options (System.Text.Regularexpressions.Regexoptions)
Optional named parameter.
Specifies a bitwise combination of System.Text.Regularexpressions.Regexoptions flags
that specify regular expression options.
Remarks
This attribute can be used only once per parameter.
You can use the Option parameter of the attribute to further define the pattern.
For example, you can make the pattern case sensitive.
See Also
System.Management.Automation.Validatepatternattribute
The ValidateRange attribute specifies the minimum and maximum values (the range) for
the cmdlet parameter argument. This attribute can also be used by Windows PowerShell
functions.
Syntax
C#
Parameters
MinRange (System.Object)
Required. Specifies the minimum value allowed.
MaxRange (System.Object)
Required. Specifies the maximum value allowed.
Remarks
The Windows PowerShell runtime throws a construction error when the value of
the MinRange parameter is greater than the value of the MaxRange parameter.
The Windows PowerShell runtime throws a validation error under the following
conditions:
When the value of the argument is less than the MinRange limit or greater than
the MaxRange limit.
When the argument is not of the same type as the MinRange and the MaxRange
parameters.
See Also
System.Management.Automation.Validaterangeattribute
Writing a Windows PowerShell Cmdlet
ValidateScript Attribute Declaration
Article • 10/03/2022
When you use the ValidateScript attribute, the value that's being validated is mapped
to the $_
variable. You can use the $_ variable to refer to the value in the script.
Syntax
C#
[ValidateScriptAttribute(ScriptBlock scriptBlock)]
Parameters
scriptBlock - (System.Management.Automation.ScriptBlock) Required. The script
block used
to validate the input.
ErrorMessage - Optional named parameter - The item being validated and the
validating
scriptblock are passed as the first and second formatting arguments.
7 Note
Remarks
This attribute can be used only once per parameter.
If this attribute is applied to a collection, each element in the collection must
match the
pattern.
The ValidateScript attribute is defined by the
System.Management.Automation.ValidateScriptAttribute class.
See Also
System.Management.Automation.ValidateScriptAttribute
When this attribute is specified, the Windows PowerShell runtime determines whether
the supplied argument for the cmdlet parameter matches an element in the supplied
element set. The cmdlet is run only if the parameter argument matches an element in
the set. If no match is found, an error is thrown by the Windows PowerShell runtime.
Syntax
C#
Parameters
ValidValues (System.String)
Required. Specifies the valid parameter element values. The
C#
[ValidateSetAttribute("Steve")]
[ValidateSetAttribute("Steve","Mary")]
IgnoreCase (System.Boolean)
Optional named parameter. The default value of true
indicates that case is ignored. A value of false makes the cmdlet case-sensitive.
Remarks
This attribute can be used only once per parameter.
If the parameter value is an array, every element of the array must match an
element of the attribute set.
You can use cmdlet aliases to improve the cmdlet user experience. You can add aliases
to frequently
used cmdlets to reduce typing and to make it easier to complete tasks
quickly. You can include
built-in aliases in your cmdlets, or users can define their own
custom aliases.
Alias Guidelines
Follow these guidelines when you create built-in aliases for your cmdlets:
Before you assign aliases, start Windows PowerShell, and then run the
Get-Alias
cmdlet to see the aliases
that are already used.
Include an alias prefix that references the verb of the cmdlet name and an alias
suffix that
references the noun of the cmdlet name. For example, the alias for the
Import-Module cmdlet is
ipmo . For a list of all the verbs and their aliases, see
Cmdlet Verbs.
For cmdlets that have the same verb, include the same alias prefix. For example,
the aliases for
all the Windows PowerShell cmdlets that have the "Get" verb in their
name use the "g" prefix.
For cmdlets that have the same noun, include the same alias suffix. For example,
the aliases for
all the Windows PowerShell cmdlets that have the "Session" noun in
their name use the "sn" suffix.
For cmdlets that are equivalent to commands in other languages, use the name of
the command.
In general, make aliases as short as possible. Make sure the alias has at least one
distinct
character for the verb and one distinct character for the noun. Add more
characters as needed to
make the alias unique.
For cmdlet written in C# (or any other compiled .NET language), the alias can be
defined using the
Alias attibute. For example:
C#
[Cmdlet("Get", "SomeObject")]
[Alias("gso")]
See Also
Writing a Windows PowerShell Cmdlet
Cmdlet Output
Article • 09/17/2021
This section discusses the types of cmdlet output and the methods that cmdlets can call
to generate output such as error messages and objects. This section also describes how
to define the .NET Framework types that are returned by your cmdlets and how those
objects are displayed.
In This Section
Types of Cmdlet Output
Describes the types and output that cmdlets can generate and
the methods that cmdlets call to generate the output.
See Also
Writing a Windows PowerShell Cmdlet
Types of cmdlet output
Article • 09/17/2021
PowerShell provides several methods that can be called by cmdlets to generate output.
These methods
use a specific operation to write their output to a specific data stream,
such as the success data
stream or the error data stream. This article describes the types
of output and the methods used to
generate them.
Types of output
Success output
Cmdlets can report success by returning an object that can be processed by the next
command in the
pipeline. After the cmdlet has successfully performed its action, the
cmdlet calls the
System.Management.Automation.Cmdlet.WriteObject
method. We
recommend that you call this method instead of the
System.Console.WriteLine or
System.Management.Automation.Host.PSHostUserInterface.WriteLine
methods.
You can provide a PassThru switch parameter for cmdlets that do not typically return
objects.
When the PassThru switch parameter is specified at the command line, the
cmdlet is asked to
return an object. For an example of a cmdlet that has a PassThru
parameter, see
Add-History.
Error output
Cmdlets can report errors. When a terminating error occurs, the cmdlet throws an
exception. When a
non-terminating error occurs, the cmdlet calls the
System.Management.Automation.Provider.CmdletProvider.WriteError
method to send
an error record to the error data stream. For more information about error
reporting,
see Error Reporting Concepts.
Verbose output
Cmdlets can provide useful information to you while the cmdlet is correctly processing
records by
calling the
System.Management.Automation.Cmdlet.WriteVerbose
method.
The method generates verbose messages that indicate how the action is proceeding.
By default, verbose messages are not displayed. You can specify the Verbose parameter
when the
cmdlet is run to display these messages. Verbose is a common parameter that
is available to all
cmdlets.
Progress output
Cmdlets can provide progress information to you when the cmdlet is performing tasks
that take a
long time to complete, such as copying a directory recursively. To display
progress information the
cmdlet calls the
System.Management.Automation.Cmdlet.WriteProgress
method.
Debug output
Cmdlets can provide debug messages that are helpful when troubleshooting the cmdlet
code. To
display debug information the cmdlet calls the
System.Management.Automation.Cmdlet.WriteDebug
method.
By default, debug messages are not displayed. You can specify the Debug parameter
when the
cmdlet is run to display these messages. Debug is a common parameter that
is available to all
cmdlets.
Warning output
Cmdlets can display warning messages by calling the
System.Management.Automation.Cmdlet.WriteWarning
method.
By default, warning messages are displayed. However, you can configure warning
messages by using
the $WarningPreference variable or by using the Verbose and Debug
parameters when the
cmdlet is called.
Displaying output
For all write-method calls, the content display is determined by specific runtime
variables. The
exception is the
System.Management.Automation.Cmdlet.WriteObject
method. By using these variables, you can make the appropriate write call at the correct
place in
your code and not worry about when or if the output should be displayed.
See also
Error Reporting Concepts
Cmdlet Overview
Cmdlets should report errors differently depending on whether the errors are
terminating errors or
nonterminating errors. Terminating errors are errors that cause the
pipeline to be terminated
immediately, or errors that occur when there's no reason to
continue processing. Nonterminating
errors are those errors that report a current error
condition, but the cmdlet can continue to
process input objects. With nonterminating
errors, the user is typically notified of the problem,
but the cmdlet continues to process
the next input object.
Does the error condition prevent your cmdlet from successfully processing any
further input
objects? If so, this is a terminating error.
Is the error condition related to a specific input object or a subset of input objects?
If so,
this is a nonterminating error.
Does the cmdlet accept multiple input objects, such that processing may succeed
on another input
object? If so, this is a nonterminating error.
Cmdlets that can accept multiple input objects should decide between what are
terminating and
nonterminating errors, even when a particular situation applies to
only a single input object.
Cmdlets can receive any number of input objects and send any number of success
or error objects
before throwing a terminating exception. There's no relationship
between the number of input
objects received and the number of success and
error objects sent.
Cmdlets that can accept only 0-1 input objects and generate only 0-1 output
objects should treat
errors as terminating errors and generate terminating
exceptions.
You can also define your own exceptions for issues specific to your situation, or add
additional
information to an existing exception using its error record.
Error records
PowerShell describes a nonterminating error condition with
System.Management.Automation.ErrorRecord
objects. Each object provides error
category information, an optional target object, and details
about the error condition.
Error identifiers
The error identifier is a simple string that identifies the error condition within the cmdlet.
PowerShell combines this identifier with a cmdlet identifier to create a fully qualified
error
identifier that can be used later when filtering error streams or logging errors,
when responding to
specific errors, or with other user-specific activities.
Assign different, highly specific, error identifiers to different code paths. Each code
path that
calls
System.Management.Automation.Cmdlet.WriteError
or
System.Management.Automation.Cmdlet.ThrowTerminatingError
should have its
own error identifier.
Don't change the semantics of an error identifier between versions of your cmdlet
or PowerShell
provider. After the semantics of an error identifier is established, it
should remain constant
throughout the lifecycle of your cmdlet.
For terminating errors, use a unique error identifier for a particular CLR exception
type. If the
exception type changes, use a new error identifier.
For nonterminating errors, use a specific error identifier for a specific input object.
Choose text for the identifier that tersely corresponds to the error being reported.
Don't use
white space or punctuation.
Don't generate error identifiers that aren't reproducible. For example, don't
generate identifiers
that include a process identifier. Error identifiers are useful only
when they correspond to
identifiers that are seen by other users who are
experiencing the same problem.
Error categories
Error categories are used to group errors for the user. PowerShell defines these
categories and
cmdlets and PowerShell providers must choose between them when
generating the error record.
For a description of the error categories that are available, see the
System.Management.Automation.ErrorCategory
enumeration. In general, you should
avoid using NoError, UndefinedError, and
GenericError whenever possible.
Users can view errors based on category when they set $ErrorView to CategoryView.
See also
Cmdlet Overview
You can extend the .NET Framework objects that are returned by cmdlets, functions, and
scripts by using types files (.ps1xml). Types files are XML-based files that let you add
properties and methods to existing objects. For example, Windows PowerShell provides
the Types.ps1xml file, which adds elements to several existing .NET Framework objects.
The Types.ps1xml file is located in the Windows PowerShell installation directory
( $pshome ). You can create your own types file to further extend those objects or to
extend other objects. When you extend an object by using a types file, any instance of
the object is extended with the new elements.
XML
<Type>
<Name>System.Array</Name>
<Members>
<AliasProperty>
<Name>Count</Name>
<ReferencedMemberName>Length</ReferencedMemberName>
</AliasProperty>
</Members>
</Type>
To see this new alias property, use a Get-Member command on any array, as shown in
the following example.
PowerShell
...
You can use either the Count property or the Length property to determine how many
objects are in an array. For example:
PowerShell
Output
PowerShell
Output
To add your own extended types to the file, add a types element for each object that
you want to extend. The following topics provide examples.
For more information about adding properties and property sets, see Extended
Properties
For more information about adding member sets, see Extended Member Sets.
After you define your own extended types, use one of the following methods to make
your extended objects available:
To make your extended types file available to the current session, use the Update-
TypeData cmdlet to add the new file. If you want your types to take precedence
over the types that are defined in other types files (including the Types.ps1xml file),
use the PrependData parameter of the Update-TypeData cmdlet.
To make your extended types file available to all future sessions, add the types file
to a module, export the current session, or add the Update-TypeData command to
your Windows PowerShell profile.
See Also
Defining Default Properties for Objects
When you extend .NET Framework objects, you can add alias properties, code
properties, note
properties, script properties, and property sets to the objects. The XML
that defines these
properties is described in the following sections.
7 Note
The examples in the following sections are from the default Types.ps1xml types file
in the
PowerShell installation directory ( $PSHOME ). For more information, see About
Types.ps1xml.
Alias properties
An alias property defines a new name for an existing property.
XML
<Type>
<Name>System.Array</Name>
<Members>
<AliasProperty>
<Name>Count</Name>
<ReferencedMemberName>Length</ReferencedMemberName>
</AliasProperty>
</Members>
</Type>
Code properties
A code property references a static property of a .NET Framework object.
XML
<Type>
<Name>System.IO.DirectoryInfo</Name>
<Members>
<CodeProperty>
<Name>Mode</Name>
<GetCodeReference>
<TypeName>Microsoft.PowerShell.Commands.FileSystemProvider</TypeName>
<MethodName>Mode</MethodName>
</GetCodeReference>
</CodeProperty>
</Members>
</Type>
Note properties
A note property defines a property that has a static value.
In the following example, the Status property, whose value is always Success, is added
to
the System.IO.DirectoryInfo type. The NoteProperty
element defines the extended
property as a note property. The Name
element specifies the name of the extended
property. The Value
element specifies the static value of the extended property. The
NoteProperty element can also be
added to the members of the MemberSets
element.
XML
<Type>
<Name>System.IO.DirectoryInfo</Name>
<Members>
<NoteProperty>
<Name>Status</Name>
<Value>Success</Value>
</NoteProperty>
</Members>
</Type>
Script properties
A script property defines a property whose value is the output of a script.
In the following example, the VersionInfo property is added to the System.IO.FileInfo
type. The ScriptProperty element
defines the extended property as a script property. The
Name
element specifies the name of the extended property. And, the GetScriptBlock
element specifies the script that generates the property value. You can also add the
ScriptProperty element to the members of the MemberSets
element.
XML
<Type>
<Name>System.IO.FileInfo</Name>
<Members>
<ScriptProperty>
<Name>VersionInfo</Name>
<GetScriptBlock>
[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)
</GetScriptBlock>
</ScriptProperty>
</Members>
</Type>
Property sets
A property set defines a group of extended properties that can be referenced by the
name of the set.
For example, the Format-Table
Property parameter can specify a
specific property set to be displayed. When a property set is
specified, only those
properties that belong to the set are displayed.
There's no restriction on the number of property sets that can be defined for an object.
However,
the property sets used to define the default display properties of an object
must be specified
within the PSStandardMembers member set. In the Types.ps1xml
types file, the default property
set names include DefaultDisplayProperty,
DefaultDisplayPropertySet, and
DefaultKeyPropertySet. Any additional property sets
that you add to the PSStandardMembers
member set are ignored.
XML
<Type>
<Name>System.ServiceProcess.ServiceController</Name>
<Members>
<MemberSet>
<Name>PSStandardMembers</Name>
<Members>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<ReferencedProperties>
<Name>Status</Name
<Name>Name</Name>
<Name>DisplayName</Name>
</ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>
</Members>
</Type>
See also
About Types.ps1xml
System.Management.Automation
When you extend .NET Framework objects, you can add code methods and script
methods to the objects.
The XML that is used to define these methods is described in
the following sections.
7 Note
The examples in the following sections are from the Types.ps1xml types file in the
Windows
PowerShell installation directory ( $PSHOME ). For more information, see
About Types.ps1xml.
Code methods
A code method references a static method of a .NET Framework object.
XML
<Type>
<Name>System.Xml.XmlNode</Name>
<Members>
<CodeMethod>
<Name>ToString</Name>
<CodeReference>
<TypeName>Microsoft.PowerShell.ToStringCodeMethods</TypeName>
<MethodName>XmlNode</MethodName>
</CodeReference>
</CodeMethod>
</Members>
</Type>
Script methods
A script method defines a method whose value is the output of a script. In the following
example,
the ConvertToDateTime method is added to the
System.Management.ManagementObject type. The
PSScriptMethod element defines the
extended method as a script method. The
Name
element specifies the name of the
extended method. And, the
Script
element specifies the script that generates the
method value. You can also add the
PSScriptMethod element to the members of
the
PSMemberSets element.
XML
<Type>
<Name>System.Management.ManagementObject</Name>
<Members>
<ScriptMethod>
<Name>ConvertToDateTime</Name>
<Script>
[System.Management.ManagementDateTimeConverter]::ToDateTime($args[0])
</Script>
</ScriptMethod>
</Members>
</Type>
See also
Writing a Windows PowerShell Cmdlet
Defining Default Member Sets for
Objects
Article • 09/17/2021
XML
<Type>
<Name>System.Diagnostics.Process</Name>
<Members>
<MemberSet>
<Name>PSStandardMembers</Name>
<Members>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<ReferencedProperties>
<Name>Id</Name>
<Name>Handles</Name>
<Name>CPU</Name>
<Name>Name</Name>
</ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>
The following output shows the default properties returned by the Format-List cmdlet.
Only the Id , Handles , CPU , and Name properties are returned for each process object.
PowerShell
Get-Process | format-list
Output
Id : 2036
Handles : 27
CPU :
Name : AEADISRV
Id : 272
Handles : 38
CPU :
Name : agrsmsvc
...
See Also
Writing a Windows PowerShell Cmdlet
Custom Formatting Files
Article • 09/17/2021
The display format for the objects returned by cmdlets, functions, and scripts are
defined using formatting files (format.ps1xml files). Several of these files are provided by
Windows PowerShell to define the default display format for those objects returned by
Windows PowerShell cmdlets. However, you can also create your own custom
formatting files to overwrite the default display formats or to define the display of
objects returned by your own commands.
Windows PowerShell uses the data in these formatting files to determine what is
displayed and how the data is formatted. The displayed data can include the properties
of an object or the value of a script block. Script blocks are used if you want to display
some value that is not available directly from the properties of an object. For example,
you may want to add the value of two properties of an object and display the sum as a
separate piece of data. When you write your own formatting file, you will need to define
views for the objects that you want to display. You can define a single view for each
object, you can define a single view for multiple objects, or you can define multiple
views for the same object. There is no limit to the number of views that you can define.
) Important
Formatting files do not determine the elements of an object that are returned to
the pipeline. When an object is returned to the pipeline, all members of that object
are available.
Format Views
Formatting views can display objects in a table format, a list format, a wide format, and a
custom format. For the most part, each formatting definition is described by a set of
XML tags that describe a view. Each view contains the name of the view, the objects that
use the view, and the elements of the view, such as the column and row information for
a table view.
Table view
Lists the properties of an object or a script block value in one or more
columns. Each column represents a property of the object or a script block value. You
can define a table view that displays all the properties of an object, a subset of the
properties of an object, or a combination of properties and script block values. Each row
of the table represents a returned object. For more information about this view, see
Table View.
List view
Lists the properties of an object or a script block value in a single column. Each
row of the list displays an optional label or the property name followed by the value of
the property or script block. For more information about this view, see List View.
Wide view
Lists a single property of an object or a script block value in one or more
columns. There is no label or header for this view. For more information about this view,
see Wide View.
Custom view
Displays a customizable view of object properties or script block values
that does not adhere to the rigid structure of table views, list views, or wide views. You
can define a standalone custom view, or you can define a custom view that is used by
another view, such as a table view or list view. For more information about this view, see
Custom View.
XML
ViewDefinitions
<View>
<Name>Name of View</Name>
<ViewSelectedBy>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
</TableColumnItem>
<TableColumnItem>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl)
</View>
</ViewDefinitions>
See Also
Table View
List View
Wide View
Custom View
This section discusses confirmation messages that can be displayed before a cmdlet,
function, or provider performs an action.
In This Section
Requesting Confirmation Process for Commands
Discusses the process that cmdlets,
functions, and providers must follow to request a confirmation before they make a
change to the system.
Confirmation Messages
Provides samples of the different confirmation messages that
can be displayed.
See Also
Writing a Windows PowerShell Cmdlet
Requesting Confirmation from Cmdlets
Article • 09/17/2021
Cmdlets should request confirmation when they are about to make a change to the
system that is outside of the Windows PowerShell environment. For example, if a cmdlet
is about to add a user account or stop a process, the cmdlet should require confirmation
from the user before it proceeds. In contrast, if a cmdlet is about to change a Windows
PowerShell variable, the cmdlet does not need to require confirmation.
In order to make a confirmation request, the cmdlet must indicate that it supports
confirmation requests, and it must call the
System.Management.Automation.Cmdlet.ShouldProcess and
System.Management.Automation.Cmdlet.ShouldContinue (optional) methods to display
a confirmation request message.
The following example shows a Cmdlet attribute declaration that supports confirmation
requests.
C#
[Cmdlet(VerbsDiagnostic.Test, "RequestConfirmationTemplate1",
SupportsShouldProcess = true)]
C#
if (ShouldProcess (...) )
if (Force || ShouldContinue(...))
For most cmdlets, you do not have to explicitly specify ConfirmImpact . Instead, use the
default setting of the parameter, which is Medium. If you set ConfirmImpact to High, the
operation will be confirmed by default. Reserve this setting for highly disruptive actions,
such as reformatting a hard-disk volume.
To caution the user and continue with the operation, the cmdlet or provider can
call the System.Management.Automation.Cmdlet.WriteWarning method.
To provide additional information that the user can retrieve using the Verbose
parameter, the cmdlet or provider can call the
System.Management.Automation.Cmdlet.WriteVerbose method.
To provide debugging-level detail for other developers or for product support, the
cmdlet or provider can call the
System.Management.Automation.Cmdlet.WriteDebug method. The user can
retrieve this information using the Debug parameter.
Cmdlets and providers first call the following methods to request confirmation before
they attempt to perform an operation that changes a system outside of Windows
PowerShell:
System.Management.Automation.Cmdlet.Shouldprocess
System.Management.Automation.Provider.Cmdletprovider.Shouldprocess
See Also
Writing a Windows PowerShell Cmdlet
Users Requesting Confirmation
Article • 09/30/2021
When you specify a value of true for the SupportsShouldProcess parameter of the
Cmdlet attribute
declaration, the Confirm parameter is added to the parameters of the
cmdlet.
In the default environment, users can specify the Confirm parameter or "-Confirm:$true
so that
confirmation is requested when the ShouldProcess() method is called. This
forces confirmation
regardless of the impact level setting.
If Confirm parameter is not used, the ShouldProcess() call requests confirmation if the
$ConfirmPreference preference variable is equal to or greater than the ConfirmImpact
setting of
the cmdlet or provider. The default setting of $ConfirmPreference is High.
Therefore, in the
default environment, only cmdlets and providers that specify a high-
impact action request
confirmation.
If Confirm is explicitly set to false ( -Confirm:$false ), the cmdlet runs without prompting
for
confirmation and the $ConfirmPreference shell variable is ignored.
Remarks
For cmdlets and providers that specify SupportsShouldProcess , but not
ConfirmImpact , those
actions are handled as "medium impact" actions, and they
will not prompt by default. Their impact
level is less than the default setting of the
$ConfirmPreference preference variable.
If the user specifies the Verbose parameter, they will be notified of the operation
even if they
are not prompted for confirmation.
See Also
Writing a Windows PowerShell Cmdlet
System.Management.Automation.Cmdlet.ShouldProcess
Confirmation Messages
Article • 09/17/2021
Here are different confirmation messages that can be displayed depending on the
variants of the
System.Management.Automation.Cmdlet.ShouldProcess
and
System.Management.Automation.Cmdlet.ShouldContinue
methods that are called.
) Important
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
If the user selects Yes or Yes to All to the confirmation request (as shown in the
following
example), a call to the
System.Management.Automation.Cmdlet.ShouldContinue
method is made, which
causes a second confirmation message to be displayed.
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): y
Confirm
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):
If the user selects Yes or Yes to All to the previous message, a call to the
System.Management.Automation.Cmdlet.ShouldContinue
method is made, which
causes a second confirmation message to be displayed.
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): y
Confirm
See Also
Writing a Windows PowerShell Cmdlet
Windows PowerShell Error Reporting
Article • 09/17/2021
In This Section
Error Reporting Concepts
Describes the two mechanisms that cmdlets can use to report
errors.
Terminating Errors
Describes the method used to report terminating errors, where that
method can be called from within the cmdlet, and exceptions that can be returned by
the Windows PowerShell runtime when the method is called.
Non-Terminating Errors
Describes the method used to report non-terminating errors
and where that method can be called from within the cmdlet.
See Also
Writing a Windows PowerShell Cmdlet
Error Reporting Concepts
Article • 09/17/2021
Windows PowerShell provides two mechanisms for reporting errors: one mechanism for
terminating errors and another mechanism for non-terminating errors. It is important for
your cmdlet to report errors correctly so that the host application that is running your
cmdlets can react in an appropriate manner.
See Also
System.Management.Automation.Cmdlet.Throwterminatingerror*
System.Management.Automation.Cmdlet.WriteError
This topic discusses the method used to report terminating errors. It also discusses how
to call the method from within the cmdlet, and it discusses the exceptions that can be
returned by the Windows PowerShell runtime when the method is called.
When a terminating error occurs, the cmdlet should report the error by calling the
System.Management.Automation.Cmdlet.Throwterminatingerror* method. This method
allows the cmdlet to send an error record that describes the condition that caused the
terminating error. For more information about error records, see Windows PowerShell
Error Records.
Cmdlets can write any number of output objects or non-terminating errors before
reporting a terminating error. However, the terminating error permanently stops the
pipeline, and no further output, terminating errors, or non-terminating errors can be
reported.
See Also
System.Management.Automation.Cmdlet.BeginProcessing
System.Management.Automation.Cmdlet.EndProcessing
System.Management.Automation.Cmdlet.ProcessRecord
System.Management.Automation.Pipelinestoppedexception
System.Management.Automation.Cmdlet.Throwterminatingerror*
System.Management.Automation.Cmdlet.WriteError
This topic discusses the method used to report non-terminating errors. It also discusses
how to call the method from within the cmdlet.
When a non-terminating error occurs, the cmdlet should report this error by calling the
System.Management.Automation.Cmdlet.WriteError method. When the cmdlet reports a
non-terminating error, the cmdlet can continue to operate on this input object and on
further incoming pipeline objects. If the cmdlet calls the
System.Management.Automation.Cmdlet.WriteError method, the cmdlet can write an
error record that describes the condition that caused the non-terminating error. For
more information about error records, see Windows PowerShell Error Records.
See Also
System.Management.Automation.Cmdlet.WriteError
System.Management.Automation.Cmdlet.BeginProcessing
System.Management.Automation.Cmdlet.ProcessRecord
System.Management.Automation.Cmdlet.EndProcessing
This topic discusses the ways in which users can display error information.
When your cmdlet encounters an error, the presentation of the error information will, by
default, resemble the following error output.
PowerShell
$ stop-service lanmanworkstation
However, users can view errors by category by setting the $ErrorView variable to
"CategoryView" . Category view displays specific information from the error record rather
than a free-text description of the error. This view can be useful if you have a long list of
errors to scan. In category view, the previous error message is displayed as follows.
PowerShell
$ $ErrorView = "CategoryView"
$ stop-service lanmanworkstation
CloseError: (System.ServiceProcess.ServiceController:ServiceController)
[stop-service], ServiceCommandException
For more information about error categories, see Windows PowerShell Error Records.
See Also
Windows PowerShell Error Records
The
System.Management.Automation.ErrorRecord
object contains the following
information:
The exception that describes the error. Often, this is an exception that the cmdlet
caught and
converted into an error record. Every error record must contain an
exception.
If the cmdlet did not catch an exception, it must create a new exception and choose the
exception
class that best describes the error condition. However, you do not need to
throw the exception
because it can be accessed through the
System.Management.Automation.ErrorRecord.Exception
property of the
System.Management.Automation.ErrorRecord
object.
An error identifier that provides a targeted designator that can be used for
diagnostic purposes
and by Windows PowerShell scripts to handle specific error
conditions with specific error
handlers. Every error record must contain an error
identifier (see Error Identifier).
An error category that provides a general designator that can be used for
diagnostic purposes.
Every error record must specify an error category (see Error
Category).
Optional invocation information about the cmdlet that threw the error. This
information is
specified by Windows PowerShell (see Invocation Message).
The target object that was being processed when the error occurred. This might be
the input
object, or it might be another object that your cmdlet was processing.
For example, for the
command remove-item -recurse c:\somedirectory , the error
might be an instance of a FileInfo
object for "c:\somedirectory\lockedfile". The
target object information is optional.
Error Identifier
When you create an error record, specify an identifier that designates the error
condition within
your cmdlet. Windows PowerShell combines the targeted identifier with
the name of your cmdlet to
create a fully qualified error identifier. The fully qualified
error identifier can be accessed
through the
System.Management.Automation.ErrorRecord.FullyQualifiedErrorId
property of the
System.Management.Automation.ErrorRecord
object. The error identifier is not available
by itself. It is available only as part of the fully
qualified error identifier.
Use the following guidelines to generate error identifiers when you create error records:
Make error identifiers specific to an error condition. Target the error identifiers for
diagnostic
purposes and for scripts that handle specific error conditions with
specific error handlers. A
user should be able to use the error identifier to identify
the error and its source. Error
identifiers also enable reporting for specific error
conditions from existing exceptions so that
new exception subclasses are not
required.
In general, assign different error identifiers to different code paths. The end-user
benefits from
specific identifiers. Often, each code path that calls
System.Management.Automation.Cmdlet.WriteError
or
System.Management.Automation.Cmdlet.Throwterminatingerror*
has its own
identifier. As a rule, define a new identifier when you define a new template string
for the error message, and vice-versa. Do not use the error message as an
identifier.
When you publish code using a particular error identifier, you establish the
semantics of errors
with that identifier for your complete product support lifecycle.
Do not reuse it in a context
that is semantically different from the original context.
If the semantics of this error change,
create and then use a new identifier.
You should generally use a particular error identifier only for exceptions of a
particular CLR
type. If the type of the exception or the type of the target object
changes, create and then use a
new identifier.
Choose text for your error identifier that concisely corresponds to the error that
you are
reporting. Use standard .NET Framework naming and capitalization
conventions. Do not use white
space or punctuation. Do not localize error
identifiers.
TargetName: By default, the name of the object the cmdlet was processing when
the error occurred.
Or, another cmdlet-defined string.
TargetType: By default, the type of the target object. Or, another cmdlet-defined
string.
Activity: By default, the name of the cmdlet that created the error record. Or, some
other
cmdlet-defined string.
The replacement message should conform to the .NET Framework design guidelines for
writing exception
messages with a small difference. The guidelines state that exception
messages should be written for
developers. These replacement messages should be
written for the cmdlet user.
Invocation information
When a cmdlet uses
System.Management.Automation.Cmdlet.WriteError
or
System.Management.Automation.Cmdlet.Throwterminatingerror*
to report an error
record, Windows PowerShell automatically adds information that describes the
command that was invoked when the error occurred. This information is provided by a
System.Management.Automation.Invocationinfo
object that contains the name of the
cmdlet that was invoked by the command, the command itself, and
information about
the pipeline or script. This property is read-only.
See Also
System.Management.Automation.Cmdlet.WriteError
System.Management.Automation.Cmdlet.Throwterminatingerror*
System.Management.Automation.ErrorCategory
System.Management.Automation.Errorcategoryinfo
System.Management.Automation.ErrorRecord
System.Management.Automation.ErrorDetails
System.Management.Automation.Invocationinfo
If you want to write an error handler in your script or a host to handle specific errors
that occur during command or script execution, you must interpret the
System.Management.Automation.ErrorRecord object to determine whether it represents
the class of error that you want to handle.
7 Note
Other information
The cmdlet can specify the CloseError, OpenError, InvalidType, ReadError, and WriteError
categories, and other error categories. The host application can use the error category
to capture groups of errors.
The Exception
The exception included in the error record is provided by the cmdlet and can be
accessed through the System.Management.Automation.ErrorRecord.Exception* property
of the System.Management.Automation.ErrorRecord object.
Host applications can use the is keyword to identify that the exception is of a specific
class or of a derived class. It is better to branch on the exception type, as shown in the
following example.
if (MyNonTerminatingError.Exception is AccessDeniedException)
This way, you catch the derived classes. However, there are problems if the exception is
deserialized.
The FQID
The FQID is the most specific information you can use to identify the error. It is a string
that includes a cmdlet-defined identifier, the name of the cmdlet class, and the source
that reported the error. In general, an error record is analogous to an event record of a
Windows Event log. The FQID is analogous to the following tuple, which identifies the
class of the event record: (log name, source, event ID).
The FQID is designed to be inspected as a single string. However, cases exist in which
the error identifier is designed to be parsed by the host application. The following
example is a well-formed fully qualified error identifier.
CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand.
In the previous example, the first token is the error identifier, which is followed by the
name of the cmdlet class. The error identifier can be a single token, or it can be a dot-
separated identifier that allows for branching on inspection of the identifier. Do not use
white space or punctuation in the error identifier. It is especially important not to use a
comma; a comma is used by Windows PowerShell to separate the identifier and the
cmdlet class name.
Other Information
The System.Management.Automation.ErrorRecord object might also provide information
that describes the environment in which the error occurred. This information includes
items such as error details, invocation information, and the target object that was being
processed when the error occurred. Although this information might be useful to the
host application, it is not typically used to identify the error. This information is available
through the following properties:
System.Management.Automation.ErrorRecord.ErrorDetails
System.Management.Automation.ErrorRecord.InvocationInfo
System.Management.Automation.ErrorRecord.TargetObject
See Also
System.Management.Automation.ErrorRecord
System.Management.Automation.Errorcategory
System.Management.Automation.Errorcategoryinfo
System.Management.Automation.Cmdlet.WriteError
System.Management.Automation.Cmdlet.Throwterminatingerror*
For more information about how background jobs are handled at the command line, see
the following:
about_Jobs
about_Job_Details
about_Remote_Jobs
Define an asJob switch parameter so that the user can decide whether to run the
cmdlet as a background job.
Create an object that derives from the System.Management.Automation.Job class.
This object can be a custom job object or a job object provided by Windows
PowerShell, such as a System.Management.Automation.Pseventjob object.
System.Management.Automation.Job
Derives custom job objects. This is an abstract
class.
System.Management.Automation.Jobrepository
Manages and provides information
about the current active background jobs.
System.Management.Automation.Jobstate
Defines the state of the background job.
States include Started, Running, and Stopped.
System.Management.Automation.Jobstateinfo
Provides information about the state of a
background job and, if the last state change was caused by an error, the reason the job
entered its current state.
System.Management.Automation.Jobstateeventargs
Provides the arguments for an
event that is raised when a background job changes state.
Get-Job
Gets Windows PowerShell background jobs that are running in the current session.
Receive-Job
Gets the results of the Windows PowerShell background jobs in the current session.
Remove-Job
Start-Job
Stop-Job
Wait-Job
Suppresses the command prompt until one or all of the Windows PowerShell
background jobs running in the session are complete.
See Also
Writing a Windows PowerShell Cmdlet
Invoking Cmdlets and Scripts Within a
Cmdlet
Article • 09/17/2021
A cmdlet can invoke other cmdlets and scripts from within the input processing method
of the cmdlet. This allows you to add the functionality of existing cmdlets and scripts to
your cmdlet without having to rewrite the code.
System.Management.Automation.Cmdlet.Invoke
This variant invokes the cmdlet object
and returns a collection of "T" type objects.
System.Management.Automation.Cmdlet.Invoke
This variant invokes the cmdlet object
and returns a strongly typed emumerator. This variant allows the user to use the objects
in the collection to perform custom operations.
Examples
Example Description
Invoking Cmdlets This example shows how to invoke a cmdlet from within another
Within a Cmdlet cmdlet.
Invoking Scripts Within This example shows how to invoke a script that is supplied to the
a Cmdlet cmdlet from within another cmdlet.
See Also
Writing a Windows PowerShell Cmdlet
Cmdlet Sets
Article • 09/17/2021
When you design your cmdlets, you might encounter cases in which you need to
perform several actions on the same piece of data. For example, you might need to get
and set data or start and stop a process. Although you will need to create separate
cmdlets to perform each action, your cmdlet design should include a base class from
which the classes for the individual cmdlets are derived.
Declare any common parameters used by all the derived cmdlets in the base class.
Implement a System.Management.Automation.PSSnapIn or
System.Management.Automation.Custompssnapin class whose name and
description reflects the set of cmdlets.
Example
The following example shows the implementation of a base class that is used by Get-
Proc and Stop-Proc cmdlet that derive from the same base class.
C#
using System;
using System.Diagnostics;
namespace Microsoft.Samples.PowerShell.Commands
#region ProcessCommands
/// <summary>
/// </summary>
if (ShouldProcess(process.ProcessName, "Stop-Proc"))
process.Kill();
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
WriteObject(process);
/// <summary>
/// This class is the base class that defines the common
/// cmdlets.
/// </summary>
#region Parameters
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
[Parameter()]
#endregion Parameters
// <summary>
// </summary>
WildcardOptions.Compiled;
if (wIn.IsMatch(p.ProcessName))
if (wOut.IsMatch(p.ProcessName))
processThisOne = false;
break;
if (processThisOne)
ProcessObject(p);
break;
#endregion ProcessCommands
See Also
Writing a Windows PowerShell Cmdlet
Windows PowerShell Session State
Article • 09/17/2021
From a developer perspective, a Windows PowerShell session refers to the time between
when a host application opens a Windows PowerShell runspace and when it closes the
runspace. Looked at another way, the session is the lifetime of an instance of the
Windows PowerShell engine that is invoked while the runspace exists.
Session-State Data
Session state data can be public or private. Public data is available to calls from outside
the session state while private data is available only to calls from within the session
state. For example, a module can have a private function that can be called only by the
module or only internally by a public element that has been exported. This is similar to
the private and public members of a .NET Framework type.
Session-state data is stored by the current instance of the execution engine within the
context of the current Windows PowerShell session. Session-state data consists of the
following items:
Path information
Drive information
Information about the imported modules and references to the module elements
(such as cmdlets, functions, and scripts) that are exported by the module. This
information and these references are for the global session state only.
See Also
System.Management.Automation.PSCmdlet.Sessionstate
System.Management.Automation.Sessionstate?Displayproperty=Fullname
This section contains examples of cmdlet code that you can use to start writing your
own cmdlets.
) Important
If you want step-by-step instructions for writing cmdlets, see Tutorials for Writing
Cmdlets.
In This Section
How to Write a Simple Cmdlet
This example shows the basic structure of cmdlet code.
See Also
Writing a Windows PowerShell Cmdlet
How to write a cmdlet
Article • 09/17/2021
This article shows how to write a cmdlet. The Send-Greeting cmdlet takes a single user
name as
input and then writes a greeting to that user. Although the cmdlet does not do
much work, this
example demonstrates the major sections of a cmdlet.
For more information about the Cmdlet attribute, see CmdletAttribute Declaration.
3. Specify that the cmdlet derives from either of the following classes:
System.Management.Automation.Cmdlet
System.Management.Automation.PSCmdlet
4. To define the parameters for the cmdlet, use the Parameter attribute. In this case,
only one
required parameter is specified.
5. Override the input processing method that processes the input. In this case, the
System.Management.Automation.Cmdlet.ProcessRecord
method is overridden.
Output
Hello <UserName>!
Example
C#
using System.Management.Automation; // Windows PowerShell assembly.
namespace SendGreeting
[Cmdlet(VerbsCommunications.Send, "Greeting")]
[Parameter(Mandatory=true)]
// method.
See also
System.Management.Automation.Cmdlet
System.Management.Automation.PSCmdlet
System.Management.Automation.Cmdlet.ProcessRecord
System.Management.Automation.Cmdlet.WriteObject
CmdletAttribute Declaration
ParameterAttribute Declaration
These examples show how to declare named, positional, required, optional, and switch
parameters. These examples also show how to define a parameter alias.
C#
[Parameter()]
For more information about the Parameter attribute, see Parameter Attribute
Declaration.
C#
[Parameter(Position = 0)]
For more information about the Parameter attribute, see Parameter Attribute
Declaration.
How to Declare a Mandatory Parameter
Define a public property as shown in the following code. When you add the
Parameter attribute, set the Mandatory keyword to true .
C#
For more information about the Parameter attribute, see Parameter Attribute
Declaration.
C#
[Parameter(Position = 0)]
C#
[Parameter(Position = 1)]
For more information about the Parameter attribute, see Parameter Attribute
Declaration.
C#
[Alias("UN","Writer","Editor")]
[Parameter()]
For more information about the Alias attribute, see Alias Attribute Declaration.
See Also
System.Management.Automation.SwitchParameter
This example shows how to define two parameter sets when you declare the parameters
for a cmdlet. Each parameter set has both a unique parameter and a shared parameter
that is used by both parameter sets. For more information about parameters sets,
including how to specify the default parameter set, see Cmdlet Parameter Sets.
) Important
C#
ParameterSetName = "Test01")]
2. Add the ParameterSet keyword to the Parameter attribute for the unique
parameter of the second parameter set.
C#
ParameterSetName = "Test02")]
3. For the parameter that belongs to both parameter sets, add a Parameter attribute
for each parameter set and then add the ParameterSet keyword to each set. In
each Parameter attribute, you can specify how that parameter is defined. A
parameter can be optional in one set and mandatory in another.
C#
[Parameter(ParameterSetName = "Test02")]
See Also
Cmdlet Parameter Sets
This section contains examples that show how to validate parameter input by using
various attributes
to implement validation rules.
In This Section
How to Validate an Argument with a Script
Describes how to validate an argument set
by using the ArgumentSet attribute.
The way a parameter is declared can affect validation. For more information, see
How to
Declare Cmdlet Parameters.
Reference
See Also
Writing a Windows PowerShell Cmdlet
How to validate an argument using a
script
Article • 09/17/2021
This example shows how to specify a validation rule that uses a script to check the
parameter
argument before the cmdlet is run. The value of the parameter is piped to the
script. The script
must return $true for every value piped to it.
7 Note
For more information about the class that defines this attribute, see
System.Management.Automation.ValidateScriptAttribute.
C#
See Also
System.Management.Automation.ValidateScriptAttribute
This example shows how to specify a validation rule that the Windows PowerShell
runtime can use to check the parameter argument before the cmdlet is run. This
validation rule provides a set of the valid values for the parameter argument.
7 Note
For more information about the class that defines this attribute, see
System.Management.Automation.Validatesetattribute.
C#
For more information about how to declare this attribute, see ValidateSet Attribute
Declaration.
See Also
System.Management.Automation.Validatesetattribute
This example shows how to specify a validation rule that the Windows PowerShell
runtime can use to check the minimum and maximum values of the parameter
argument before the cmdlet is run. You set this validation rule by declaring the
ValidateRange attribute.
7 Note
For more information about the class that defines this attribute, see
System.Management.Automation.Validaterangeattribute.
C#
[ValidateRange(0, 5)]
For more information about how to declare this attribute, see ValidateRange Attribute
Declaration.
See Also
ValidateRange Attribute Declaration
This example shows how to specify a validation rule that the Windows PowerShell
runtime can use to check the character pattern of the parameter argument before the
cmdlet is run. You set this validation rule by declaring the ValidatePattern attribute.
7 Note
For more information about the class that defines this attribute, see
System.Management.Automation.Validatepatternattribute.
C#
[ValidatePattern("[0-9][0-9][0-9][0-9]")]
For more information about how to declare this attribute, see ValidatePattern Attribute
Declaration.
See Also
ValidatePattern Attribute Declaration
This example shows how to specify a validation rule that the Windows PowerShell
runtime can use to check the number of characters (the length) of the parameter
argument before the cmdlet is run. You set this validation rule by declaring the
ValidateLength attribute.
7 Note
For more information about the class that defines this attribute, see
System.Management.Automation.Validatelengthattribute.
C#
[ValidateLength(0, 10)]
For more information about how to declare this attribute, see ValidateLength Attribute
Declaration.
See Also
ValidateLength Attribute Declaration
This example shows how to specify a validation rule that the Windows PowerShell
runtime can use to check the number of arguments (the count) that a parameter accepts
before the cmdlet is run. You set this validation rule by declaring the ValidateCount
attribute.
7 Note
For more information about the class that defines this attribute, see
System.Management.Automation.Validatecountattribute.
C#
[ValidateCount(1, 3)]
For more information about how to declare this attribute, see ValidateCount Attribute
Declaration.
See Also
ValidateCount Attribute Declaration
This example shows how to define dynamic parameters that are added to the cmdlet at
runtime. In this example, the Department parameter is added to the cmdlet whenever
the user specifies the Employee switch parameter. For more information about dynamic
parameters, see Cmdlet Dynamic Parameters.
C#
2. Call the
System.Management.Automation.Idynamicparameters.Getdynamicparameters*
method, which returns the object in which the dynamic parameters are defined. In
this example, the method is called when the Employee parameter is specified.
C#
if (employee)
return context;
return null;
3. Declare a class that defines the dynamic parameters to be added. You can use the
attributes that you used to declare the static cmdlet parameters to declare the
dynamic parameters.
C#
[Parameter]
Example
In this example, the Department parameter is added whenever the user specifies the
Employee parameter. The Department parameter is an optional parameter, and the
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SendGreeting
// IDynamicParameters interface.
[Cmdlet(VerbsCommunications.Send, "Greeting")]
[Parameter(Mandatory = true)]
[Parameter]
[Alias ("FTE")]
// Implement GetDynamicParameters to
if (employee)
return context;
return null;
if (employee)
[Parameter]
See Also
System.Management.Automation.Runtimedefinedparameterdictionary
System.Management.Automation.Idynamicparameters.Getdynamicparameters*
This example shows how to invoke a script that is supplied to a cmdlet. The script is
executed by the cmdlet, and its results are returned to the cmdlet as a collection of
System.Management.Automation.PSObject objects.
C#
if (script != null)
Collection<PSObject> PSObjects =
script.Invoke(
line,
simpleMatch,
caseSensitive
);
C#
if (LanguagePrimitives.IsTrue(psObject))
result.Line = line;
result.IgnoreCase = !caseSensitive;
break;
See Also
Writing a Windows PowerShell Cmdlet
How to Override Input Processing
Methods
Article • 09/17/2021
These examples show how to overwrite the input processing methods within a cmdlet.
These methods are used to perform the following operations:
The following class prints a sample message. To use this class, change the verb and
noun in the Cmdlet attribute, change the name of the class to reflect the new verb and
noun, and then add the functionality you require to the override of the
System.Management.Automation.Cmdlet.BeginProcessing method.
C#
[Cmdlet(VerbsDiagnostic.Test, "BeginProcessingClass")]
// output:
The following class prints a sample message. To use this class, change the verb and
noun in the Cmdlet attribute, change the name of the class to reflect the new verb and
noun, and then add the functionality you require to the override of the
System.Management.Automation.Cmdlet.ProcessRecord method.
C#
[Cmdlet(VerbsDiagnostic.Test, "ProcessRecordClass")]
// output:
The following class prints a sample. To use this class, change the verb and noun in the
Cmdlet attribute, change the name of the class to reflect the new verb and noun, and
then add the functionality you require to the override of the
System.Management.Automation.Cmdlet.EndProcessing method.
C#
[Cmdlet(VerbsDiagnostic.Test, "EndProcessingClass")]
// output:
See Also
System.Management.Automation.Cmdlet.BeginProcessing
System.Management.Automation.Cmdlet.EndProcessing
System.Management.Automation.Cmdlet.ProcessRecord
) Important
For more information about how Windows PowerShell handles these requests, see
Requesting Confirmation.
To request confirmation
1. Ensure that the SupportsShouldProcess parameter of the Cmdlet attribute is set to
true . (For
functions this is a parameter of the CmdletBinding attribute.)
C#
[Cmdlet(VerbsDiagnostic.Test, "RequestConfirmationTemplate1",
7 Note
2. Add a Force parameter to your cmdlet so that the user can override a
confirmation request.
C#
[Parameter()]
Example
In the following code example, the
System.Management.Automation.Cmdlet.ShouldProcess
and
System.Management.Automation.Cmdlet.ShouldContinue
methods are called from
within the override of the
System.Management.Automation.Cmdlet.ProcessRecord
method. However, you can also call these methods from the other input processing
methods.
C#
if (ShouldProcess("ShouldProcess target"))
See Also
Writing a Windows PowerShell Cmdlet
How to Support Transactions
Article • 09/17/2021
This example shows the basic code elements that add support for transactions to a
cmdlet.
) Important
To support transactions
1. When you declare the Cmdlet attribute,
specify that the cmdlet supports
transactions.
When the cmdlet supports transactions,
Windows PowerShell adds
the UseTransaction parameter to the cmdlet when it is run.
C#
[Cmdlet(VerbsCommunications.Send, "GreetingTx",
SupportsTransactions=true )]
C#
if (TransactionAvailable())
using (CurrentPSTransaction)
See Also
Writing a Windows PowerShell Cmdlet
How to Support Jobs
Article • 09/23/2021
This example shows how to support jobs when you write cmdlets. If you want users to
run your cmdlet
as a background job, you must include the code described in the
following procedure. For more
information about background jobs, see Background
Jobs.
To support jobs
1. Define an AsJob switch parameter so that the user can decide whether to run the
cmdlet as a
job.
C#
[Parameter()]
C#
C#
if (asjob)
JobRepository.Add(job);
WriteObject(job);
ThreadPool.QueueUserWorkItem(WorkItem);
else
job.ProcessJob();
WriteObject(p);
C#
: base(command)
SetJobState(JobState.NotStarted);
get
return hasMoreData;
SetJobState(JobState.Running);
DoProcessLogic();
SetJobState(JobState.Completed);
void DoProcessLogic()
Process[] p = Process.GetProcesses();
foreach (Process pl in p)
Output.Add(PSObject.AsPSObject(pl));
Output.Complete();
} // End DoProcessLogic.
C#
Process[] p = Process.GetProcesses();
foreach (Process pl in p)
if (!asjob)
WriteObject(pl);
else
job.ChildJobs[0].Output.Add(PSObject.AsPSObject(pl));
} // End DoProcessLogic.
Example
The following sample code shows the code for a Get-Proc cmdlet that can retrieve
processes
internally or by using a background job.
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// process objects.
// This sample shows a cmdlet whose work can be done by the cmdlet or by
using
//
// assembly into the module folder. Make sure that the path to the module
folder
// user/documents/WindowsPowerShell/modules/GetProcessSample06
//
// To test the cmdlet, run the following command: Get-Proc -name <process
name>
//
//
namespace Microsoft.Samples.PowerShell.Commands
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
/// <summary>
/// </summary>
[Parameter()]
#endregion Parameters
/// <summary>
/// </summary>
if (asjob)
JobRepository.Add(job);
WriteObject(job);
ThreadPool.QueueUserWorkItem(WorkItem);
else
job.ProcessJob();
WriteObject(p);
#endregion Overrides
: base(command)
SetJobState(JobState.NotStarted);
get
return hasMoreData;
SetJobState(JobState.Running);
DoProcessLogic();
SetJobState(JobState.Completed);
void DoProcessLogic()
Process[] p = Process.GetProcesses();
foreach (Process pl in p)
Output.Add(PSObject.AsPSObject(pl));
Output.Complete();
} // End DoProcessLogic.
job.ProcessJob();
Process[] p = Process.GetProcesses();
foreach (Process pl in p)
if (!asjob)
WriteObject(pl);
else
job.ChildJobs[0].Output.Add(PSObject.AsPSObject(pl));
} // End DoProcessLogic.
} //End GetProcCommand
This example shows how to invoke a binary cmdlet that derives from
[System.Management.Automation.Cmdlet] directly from within another binary cmdlet,
PowerShell
) Important
You can invoke only those cmdlets that derive directly from the
System.Management.Automation.Cmdlet class. You can't invoke a cmdlet that
derives from the
System.Management.Automation.PSCmdlet class. For an
example, see
How to invoke a PSCmdlet from within a PSCmdlet.
C#
using System.Diagnostics;
2. In the input processing method of the cmdlet, create a new instance of the cmdlet
to be invoked.
In this example, an object of type
Microsoft.PowerShell.Commands.GetProcessCommand is
created along with the
string that contains the arguments that are used when the cmdlet is
invoked.
C#
C#
Console.WriteLine(p.ToString());
Example
In this example, the Get-Process cmdlet is invoked from within the
System.Management.Automation.Cmdlet.BeginProcessing method of a cmdlet.
C#
using System;
using System.Diagnostics;
namespace SendGreeting
[Cmdlet(VerbsCommunications.Send, "GreetingInvoke")]
[Parameter(Mandatory = true)]
WriteVerbose(p.ToString());
// method.
See Also
Writing a Windows PowerShell Cmdlet
How to invoke a PSCmdlet from within a
PSCmdlet
Article • 10/20/2022
This example shows how to invoke a script based cmdlet or binary cmdlet inheriting
from
[System.Management.Automation.PSCmdlet] from within a binary cmdlet. In this
example, the new
cmdlet Get-ClipboardReverse calls Get-Clipboard to get the contents
of the clipboard. The
Get-ClipboardReverse reverses the order of the characters and
returns the reversed string.
7 Note
The [PSCmdlet] class differs from the [Cmdlet] class. [PSCmdlet] implementations
use
runspace context information so you must invoke another cmdlet using the
PowerShell pipeline API.
In [Cmdlet] implementations you can call the cmdlet's
.NET API directly. For an example, see
How to invoke a Cmdlet from within a
Cmdlet.
C#
using System.Text;
2. To invoke a command from within another binary cmdlet you must use the
[PowerShell] API to
construct a new pipeline and add the cmdlet to be invoked.
Call the
System.Management.Automation.PowerShell.Invoke<T>() method to
invoke the pipeline.
C#
ps.AddCommand("Get-Clipboard").AddParameter("Raw");
Example
To invoke a script based cmdlet or binary cmdlet inheriting from [PSCmdlet] you must
build a
PowerShell pipeline with the command and parameters you want to execute,
then invoke the pipeline.
C#
using System;
using System.Text;
namespace ClipboardReverse
[Cmdlet(VerbsCommon.Get,"ClipboardReverse")]
[OutputType(typeof(string))]
ps.AddCommand("Get-Clipboard").AddParameter("Raw");
if (ps.HadErrors)
WriteError(new ErrorRecord(ps.Streams.Error[0].Exception,
"Get-Clipboard Error",
ErrorCategory.NotSpecified, null));
else
sb.Append(text);
Array.Reverse(reversed);
WriteObject(new string(reversed));
See Also
Writing a Windows PowerShell Cmdlet
Tutorials for Writing Cmdlets
Article • 09/17/2021
This section contains tutorials for writing cmdlets. These tutorials include the code
needed to write the cmdlets, plus an explanation of why the code is needed. These
topics will be very helpful for those who are just starting to write cmdlets.
) Important
For those who want code examples with less description, see Cmdlet Samples.
In This Section
GetProc Tutorial -
This tutorial describes how to define a cmdlet class and add basic
functionality such as adding parameters and reporting errors. The cmdlet described in
this tutorial is very similar to the Get-Process cmdlet provided by Windows PowerShell.
StopProc Tutorial -
This tutorial describes how to define a cmdlet and add functionality
such as user prompts, wildcard support, and the use of parameter sets. The cmdlet
described here performs the same task as the Stop-Process cmdlet provided by
Windows PowerShell.
SelectStr Tutorial -
This tutorial describes how to define a cmdlet that accesses a data
store. The cmdlet described here performs the same task as the Select-String cmdlet
provided by Windows PowerShell.
See Also
GetProc Tutorial
StopProc Tutorial
SelectStr Tutorial
This section provides a tutorial for creating a Get-Proc cmdlet that is very similar to the
Get-Process cmdlet provided by Windows PowerShell. This tutorial provides fragments
of code that illustrate how cmdlets are implemented, and an explanation of the code.
See Also
Creating a Cmdlet without Parameters
This section describes how to create a cmdlet that retrieves information from the local
computer without the use of parameters, and then writes the information to the
pipeline. The cmdlet described here is a Get-Proc cmdlet that retrieves information
about the processes of the local computer, and then displays that information at the
command line.
7 Note
When naming cmdlets, do not use any of the following characters: # , () {} [] & - /\ $ ; : "
'<> | ? @ ` .
Choosing a Noun
You should choose a noun that is specific. It is best to use a singular noun prefixed with
a shortened version of the product name. An example cmdlet name of this type is " Get-
SQLServer ".
Choosing a Verb
You should use a verb from the set of approved cmdlet verb names. For more
information about the approved cmdlet verbs, see Cmdlet Verb Names.
Defining the Cmdlet Class
Once you have chosen a cmdlet name, define a .NET class to implement the cmdlet.
Here is the class definition for this sample Get-Proc cmdlet:
C#
[Cmdlet(VerbsCommon.Get, "Proc")]
VB
<Cmdlet(VerbsCommon.Get, "Proc")> _
Inherits Cmdlet
7 Note
For all Windows PowerShell attribute classes, the keywords that you can set
correspond to properties of the attribute class.
When naming the class of the cmdlet, it is a good practice to reflect the cmdlet name in
the class name. To do this, use the form "VerbNounCommand" and replace "Verb" and
"Noun" with the verb and noun used in the cmdlet name. As is shown in the previous
class definition, the sample Get-Proc cmdlet defines a class called GetProcCommand,
which derives from the System.Management.Automation.Cmdlet base class.
) Important
If you want to define a cmdlet that accesses the Windows PowerShell runtime
directly, your .NET class should derive from
the
System.Management.Automation.PSCmdlet
base class. For more information
about this class, see Creating a Cmdlet that Defines Parameter Sets.
7 Note
The class for a cmdlet must be explicitly marked as public. Classes that are not
marked as public will default to internal and will not be found by the Windows
PowerShell runtime.
7 Note
Windows PowerShell uses the term "record" to describe the set of parameter values
supplied when a cmdlet is called.
If your cmdlet does not take pipeline input, it should override the
System.Management.Automation.Cmdlet.EndProcessing method. Be aware that this
method is frequently used in place of
System.Management.Automation.Cmdlet.BeginProcessing when the cmdlet cannot
operate on one element at a time, as is the case for a sorting cmdlet.
Because this sample Get-Proc cmdlet must receive pipeline input, it overrides the
System.Management.Automation.Cmdlet.ProcessRecord method and uses the default
implementations for System.Management.Automation.Cmdlet.BeginProcessing and
System.Management.Automation.Cmdlet.EndProcessing. The
System.Management.Automation.Cmdlet.ProcessRecord override retrieves processes
and writes them to the command line using the
System.Management.Automation.Cmdlet.WriteObject method.
C#
WriteObject(processes, true);
VB
processes = Process.GetProcesses()
'/ to the next cmdlet. The second parameter of this call tells
'/ PowerShell to enumerate the array, and send one process at a
WriteObject(processes, True)
An input processing method can also receive input from the output object of an
upstream cmdlet on the pipeline. For more information, see Creating a Cmdlet to
Process Pipeline Input. Be aware that your cmdlet can receive input from a
combination of command-line and pipeline sources.
The downstream cmdlet might not return for a long time, or not at all. For that
reason, the input processing method in your cmdlet should not hold locks during
calls to System.Management.Automation.Cmdlet.WriteObject, especially locks for
which the scope extends beyond the cmdlet instance.
) Important
Your cmdlet might have object variables to clean up when it is finished processing
(for example, if it opens a file handle in the
System.Management.Automation.Cmdlet.BeginProcessing method and keeps the
handle open for use by System.Management.Automation.Cmdlet.ProcessRecord). It
is important to remember that the Windows PowerShell runtime does not always
call the System.Management.Automation.Cmdlet.EndProcessing method, which
should perform object cleanup.
Code Sample
For the complete C# sample code, see GetProcessSample01 Sample.
1. Start Windows PowerShell, and get the current processes running on the
computer.
PowerShell
get-proc
Output
...
PowerShell
$p=get-proc
PowerShell
$p.length
Output
63
PowerShell
$p[6]
Output
PowerShell
$p[6].starttime
Output
PowerShell
$p[6].starttime.dayofyear
Output
207
6. Get the processes for which the handle count is greater than 500, and sort the
result.
PowerShell
Output
...
7. Use the Get-Member cmdlet to list the properties available for each process.
PowerShell
Output
TypeName: System.Diagnostics.Process
Output
...
See Also
Creating a Cmdlet to Process Command Line Input
Cmdlet Samples
Adding Parameters That Process
Command-Line Input
Article • 09/17/2021
One source of input for a cmdlet is the command line. This topic describes how to add a
parameter to
the Get-Proc cmdlet (which is described in
Creating Your First Cmdlet) so
that the cmdlet can
process input from the local computer based on explicit objects
passed to the cmdlet. The
Get-Proc cmdlet described here retrieves processes based on
their names, and then displays
information about the processes at a command prompt.
Here's the class declaration for the Get-Proc cmdlet. Details about this definition are
provided
in Creating Your First Cmdlet.
C#
[Cmdlet(VerbsCommon.Get, "proc")]
VB
<Cmdlet(VerbsCommon.Get, "Proc")> _
Inherits Cmdlet
Declaring Parameters
A cmdlet parameter enables the user to provide input to the cmdlet. In the following
example,
Get-Proc and Get-Member are the names of pipelined cmdlets, and MemberType
is a parameter
for the Get-Member cmdlet. The parameter has the argument "property."
Here's the parameter declaration for the Name parameter of the Get-Proc cmdlet.
C#
/// <summary>
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
#endregion Parameters
VB
<Parameter(Position:=0), ValidateNotNullOrEmpty()> _
Get
Return processNames
End Get
processNames = value
End Set
End Property
To inform the Windows PowerShell runtime that this property is the Name parameter, a
System.Management.Automation.Parameterattribute
attribute is added to the property
definition. The basic syntax for declaring this attribute is
[Parameter()] .
7 Note
A parameter must be explicitly marked as public. Parameters that are not marked as
public default
to internal and are not found by the Windows PowerShell runtime.
This cmdlet uses an array of strings for the Name parameter. If possible, your cmdlet
should also
define a parameter as an array, because this allows the cmdlet to accept
more than one item.
Name is a simple and common parameter name, recommended for use in your
cmdlets. It is better to
choose a parameter name like this than a complex name
that is unique to a specific cmdlet and hard
to remember.
7 Note
Unless parameters must be named, we recommend that you make the most-used
parameters positional so
that users will not have to type the parameter name.
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
C#
if (processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
VB
'/ If no process names are passed to the cmdlet, get all processes.
processes = Process.GetProcesses()
End If
'/ pipeline to display them or make them available to the next cmdlet.
WriteObject(Process.GetProcessesByName(name), True)
Next
Code Sample
For the complete C# sample code, see GetProcessSample02 Sample.
At the Windows PowerShell prompt, use the following command to list the
Internet Explorer process,
which is named "IEXPLORE."
PowerShell
To list the Internet Explorer, Outlook, and Notepad processes named "IEXPLORE,"
"OUTLOOK," and
"NOTEPAD," use the following command. If there are multiple
processes, all of them are displayed.
PowerShell
See Also
Adding Parameters that Process Pipeline Input
Cmdlet Samples
Adding Parameters that Process Pipeline
Input
Article • 09/17/2021
One source of input for a cmdlet is an object on the pipeline that originates from an
upstream
cmdlet. This section describes how to add a parameter to the Get-Proc cmdlet
(described in
Creating Your First Cmdlet) so that the cmdlet can
process pipeline objects.
This Get-Proc cmdlet uses a Name parameter that accepts input from a pipeline object,
retrieves
process information from the local computer based on the supplied names,
and then displays
information about the processes at the command line.
The following is the definition for this Get-Proc cmdlet. Details of this definition are
given in
Creating Your First Cmdlet.
C#
[Cmdlet(VerbsCommon.Get, "proc")]
VB
<Cmdlet(VerbsCommon.Get, "Proc")> _
Inherits Cmdlet
System.Management.Automation.Parameterattribute
attribute declaration. Specify the
ValueFromPipeline keyword if the cmdlet accesses the complete
input object. Specify
Here is the parameter declaration for the Name parameter of this Get-Proc cmdlet that
accepts pipeline input.
C#
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
VB
<Parameter(Position:=0, ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True), ValidateNotNullOrEmpty()> _
Get
Return processNames
End Get
processNames = value
End Set
End Property
The previous declaration sets the ValueFromPipeline keyword to true so that the
Windows
PowerShell runtime will bind the parameter to the incoming object if the
object is the same type as
the parameter, or if it can be coerced to the same type. The
ValueFromPipelineByPropertyName
keyword is also set to true so that the Windows
C#
if (processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
VB
'/ If no process names are passed to the cmdlet, get all processes.
processes = Process.GetProcesses()
Else
WriteObject(Process.GetProcessesByName(name), True)
Next
End If
Code Sample
For the complete C# sample code, see GetProcessSample03 Sample.
At the Windows PowerShell prompt, enter the following commands to retrieve the
process names
through the pipeline.
PowerShell
Enter the following lines to get the process objects that have a Name property from
the
processes called "IEXPLORE". This example uses the Get-Process cmdlet
(provided by Windows
PowerShell) as an upstream command to retrieve the
"IEXPLORE" processes.
PowerShell
See Also
Adding Parameters that Process Command Line Input
Cmdlet Samples
Adding Non-Terminating Error
Reporting to Your Cmdlet
Article • 09/17/2021
For nonterminating errors (as well as terminating errors), the cmdlet must pass an
System.Management.Automation.ErrorRecord object identifying the error. Each error
record is identified by a unique string called the "error identifier". In addition to the
identifier, the category of each error is specified by constants defined by a
System.Management.Automation.ErrorCategory enumeration. The user can view errors
based on their category by setting the $ErrorView variable to "CategoryView".
The following is the definition for this Get-Proc cmdlet. Details of this definition are
given in
Creating Your First Cmdlet.
C#
[Cmdlet(VerbsCommon.Get, "proc")]
VB
<Cmdlet(VerbsCommon.Get, "Proc")> _
Inherits Cmdlet
Defining Parameters
If necessary, your cmdlet must define parameters for processing input. This Get-Proc
cmdlet defines
a Name parameter as described in
Adding Parameters that Process
Command-Line Input.
Here is the parameter declaration for the Name parameter of this Get-Proc cmdlet.
C#
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
[ValidateNotNullOrEmpty]
VB
<Parameter(Position:=0, ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True), ValidateNotNullOrEmpty()> _
Get
Return processNames
End Get
processNames = value
End Set
End Property
7 Note
Your cmdlet should handle each record as independently as possible.
Use strings that are targeted for diagnostic purposes so that when inspecting the
fully qualified
identifier you can determine what the error is and where the error
came from.
CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand
Notice that in the previous example, the error identifier (the first token) designates what
the
error is and the remaining part indicates where the error came from.
For more complex scenarios, the error identifier can be a dot separated token that
can be parsed
on inspection. This allows you too branch on the parts of the error
identifier as well as the
error identifier and error category.
The cmdlet should assign specific error identifiers to different code paths. Keep the
following
information in mind for assignment of error identifiers:
An error identifier should remain constant throughout the cmdlet life cycle. Do not
change the
semantics of an error identifier between cmdlet versions.
Use text for an error identifier that tersely corresponds to the error being reported.
Do not use
white space or punctuation.
Have your cmdlet generate only error identifiers that are reproducible. For
example, it should not
generate an identifier that includes a process identifier.
Error identifiers are useful to a user
only when they correspond to identifiers that
are seen by other users experiencing the same
problem.
If a cmdlet creates a new thread and code running in that thread throws an
unhandled exception,
PowerShell will not catch the error and will terminate the
process.
If an object has code in its destructor or Dispose methods that causes an
unhandled exception,
PowerShell will not catch the error and will terminate the
process.
Here is a code example from this Get-Proc cmdlet that illustrates the call to
System.Management.Automation.Cmdlet.WriteError from within the override of the
System.Management.Automation.Cmdlet.ProcessRecord method. In this case, the call is
made if the cmdlet cannot find a process for a specified process identifier.
C#
if (processNames == null)
WriteObject(Process.GetProcesses(), true);
else
// a process.
Process[] processes;
try
processes = Process.GetProcessesByName(name);
WriteError(new ErrorRecord(
ex,
"NameNotFound",
ErrorCategory.InvalidOperation,
name));
continue;
WriteObject(processes, true);
} // foreach (...
} // else
The cmdlet can save nonterminating errors to a variable using the ErrorVariable
parameter, which
is not affected by the setting of ErrorAction . Failures can be
appended to an existing error
variable by adding a plus sign (+) to the front of the
variable name.
Code Sample
For the complete C# sample code, see GetProcessSample04 Sample.
Start PowerShell, and use the Get-Proc cmdlet to retrieve the processes named
"TEST".
PowerShell
At line:1 char:9
See Also
Adding Parameters that Process Pipeline Input
Cmdlet Samples
StopProc Tutorial
Article • 09/17/2021
This section provides a tutorial for creating the Stop-Proc cmdlet, which is very similar to
the Stop-Process cmdlet provided by Windows PowerShell. This tutorial provides
fragments of code that illustrate how cmdlets are implemented, and an explanation of
the code.
See Also
Creating a Cmdlet that Modifies the System
Sometimes a cmdlet must modify the running state of the system, not just the state of
the Windows
PowerShell runtime. In these cases, the cmdlet should allow the user a
chance to confirm whether or
not to make the change.
Declare that the cmdlet supports confirmation when you specify the
System.Management.Automation.CmdletAttribute
attribute by setting the
SupportsShouldProcess keyword to true .
Call
System.Management.Automation.Cmdlet.ShouldProcess
during the execution
of the cmdlet (as shown in the following example).
By supporting confirmation, a cmdlet exposes the Confirm and WhatIf parameters that
are provided
by Windows PowerShell, and also meets the development guidelines for
cmdlets (For more information
about cmdlet development guidelines, see
Cmdlet
Development Guidelines.).
7 Note
C#
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
confirmation requests where the user has asked to confirm only medium-impact and
high-impact operations.
The Stop-Proc cmdlet defines three parameters: Name , Force , and PassThru .
The Name parameter corresponds to the Name property of the process input object. Be
aware that
the Name parameter in this sample is mandatory, as the cmdlet will fail if it
does not have a
named process to stop.
The PassThru parameter allows the user to indicate whether the cmdlet passes an
output object
through the pipeline, in this case, after a process is stopped. Be aware that
this parameter is tied
to the cmdlet itself instead of to a property of the input object.
C#
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
/// <summary>
/// Specify the Force parameter that allows the user to override
/// </summary>
[Parameter]
/// <summary>
/// Specify the PassThru parameter that allows the user to specify
/// that the cmdlet should pass the process object down the pipeline
/// </summary>
[Parameter]
C#
// For every process name passed to the cmdlet, get the associated
Process[] processes;
try
processes = Process.GetProcessesByName(name);
ErrorCategory.InvalidOperation, name));
continue;
// Try to stop the process(es) that have been retrieved for a name
string processName;
try
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.ReadError, process));
continue;
process.Id)))
continue;
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower());
if (criticalProcess &&!force)
processName);
if (!ShouldContinue(message, "Warning!",
ref yesToAll,
ref noToAll))
continue;
} // if (criticalProcess...
try
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a non-terminating error.
"\".");
ErrorCategory.CloseError, process));
continue;
} // if ((e is...
else throw;
} // catch
if (passThru)
WriteObject(process);
} // foreach (Process...
} // foreach (string...
} // ProcessRecord
7 Note
If a cmdlet states that it supports should process and fails to make the
System.Management.Automation.Cmdlet.ShouldProcess
call, the user might
modify the system unexpectedly.
The call to
System.Management.Automation.Cmdlet.ShouldProcess
sends the name of
the resource to be changed to the user, with the Windows PowerShell runtime taking
into account any command-line settings or preference variables in determining what
should be
displayed to the user.
C#
process.Id)))
continue;
C#
if (criticalProcess &&!force)
processName);
if (!ShouldContinue(message, "Warning!",
ref yesToAll,
ref noToAll))
continue;
} // if (criticalProcess...
Code Sample
For the complete C# sample code, see StopProcessSample01 Sample.
Start Windows PowerShell and use the Stop-Proc cmdlet to stop processing as
shown below. Because
the cmdlet specifies the Name parameter as mandatory, the
cmdlet queries for the parameter.
PowerShell
PS> stop-proc
Name[0]:
Now let's use the cmdlet to stop the process named "NOTEPAD". The cmdlet asks
you to confirm the
action.
PowerShell
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
Use Stop-Proc as shown to stop the critical process named "WINLOGON". You are
prompted and warned
about performing this action because it will cause the
operating system to reboot.
PowerShell
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
Warning!
The process " winlogon " is a critical process and should not be
stopped. Are you sure you wish to stop the process?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N
Let's now try to stop the WINLOGON process without receiving a warning. Be
aware that this command
entry uses the Force parameter to override the warning.
PowerShell
Output
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N
See Also
Adding Parameters that Process Command-Line Input
Cmdlets can write several kinds of messages that can be displayed to the user by the
Windows PowerShell runtime. These messages include the following types:
Warning messages that contain a notification that the cmdlet is about to perform
an operation that can have unexpected results.
Progress report messages that contain information about how much work the
cmdlet has completed when performing an operation that takes a long time.
There are no limits to the number of messages that your cmdlet can write or the type of
messages that your cmdlet writes. Each message is written by making a specific call from
within the input processing method of your cmdlet.
The following code is the definition for this Stop-Proc cmdlet class. For more
information about this definition, see Creating a Cmdlet that Modifies the System.
C#
[Cmdlet(VerbsLifecycle.Stop, "proc",
SupportsShouldProcess = true)]
C#
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
/// <summary>
/// Specify the Force parameter that allows the user to override
/// </summary>
[Parameter]
/// <summary>
/// Specify the PassThru parameter that allows the user to specify
/// that the cmdlet should pass the process object down the pipeline
/// </summary>
[Parameter]
7 Note
The following code from this Stop-Proc cmdlet shows two calls to the
System.Management.Automation.Cmdlet.WriteVerbose method from the override of the
System.Management.Automation.Cmdlet.ProcessRecord method.
C#
WriteVerbose(message);
C#
processName, process.Id);
WriteVerbose(message);
Windows PowerShell also defines a Debug parameter that presents both verbose
and debug information. If your cmdlet supports this parameter, it does not need to
call System.Management.Automation.Cmdlet.WriteDebug in the same code that
calls System.Management.Automation.Cmdlet.WriteVerbose.
The following two sections of code from the sample Stop-Proc cmdlet show calls to the
System.Management.Automation.Cmdlet.WriteDebug method from the override of the
System.Management.Automation.Cmdlet.ProcessRecord method.
C#
message =
process.Id, processName);
WriteDebug(message);
C#
message =
processName);
WriteDebug(message);
WriteObject(process);
The following code from the sample Stop-Proc cmdlet shows the call to the
System.Management.Automation.Cmdlet.WriteWarning method from the override of
the System.Management.Automation.Cmdlet.ProcessRecord method.
C#
if (criticalProcess)
message =
processName);
WriteWarning(message);
} // if (criticalProcess...
7 Note
C#
int myId = 0;
WriteProgress(pr);
pr.RecordType = ProgressRecordType.Completed;
WriteProgress(pr);
Code Sample
For the complete C# sample code, see StopProcessSample02 Sample.
The following command-line entry uses Stop-Proc to stop the process named
"NOTEPAD", provide verbose notifications, and print debug information.
PowerShell
Confirm
[Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help
(default is "Y"): Y
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
See Also
Create a Cmdlet that Modifies the System
This section describes how to add aliases, wildcard expansion, and Help messages to the
parameters
of the Stop-Proc cmdlet (described in
Creating a Cmdlet that Modifies the
System).
This Stop-Proc cmdlet attempts to stop processes that are retrieved using the Get-Proc
cmdlet
(described in Creating Your First Cmdlet).
The following code is the class definition for this Stop-Proc cmdlet.
C#
[Cmdlet(VerbsLifecycle.Stop, "proc",
SupportsShouldProcess = true)]
The following code shows how an alias is added to the Name parameter.
C#
/// <summary>
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
)]
[Alias("ProcessName")]
The following code from this Stop-Proc cmdlet defines the HelpMessage attribute
keyword for
the Name parameter.
C#
/// <summary>
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
)]
Wildcard expansions of file and path names are examples of common scenarios where
the cmdlet may
want to allow support for path inputs when the selection of multiple
objects is required. A common
case is in the file system, where a user wants to see all
files residing in the current folder.
You should need a customized wildcard pattern matching implementation only rarely. In
this case,
your cmdlet should support either the full POSIX 1003.2, 3.13 specification for
wildcard expansion
or the following simplified subset:
7 Note
The following code shows how to set wildcard options and define the wildcard pattern
used for
resolving the Name parameter for this cmdlet.
C#
WildcardOptions.Compiled;
The following code shows how to test whether the process name matches the defined
wildcard pattern.
Notice that, in this case, if the process name does not match the
pattern, the cmdlet continues on
to get the next process name.
C#
if (!wildcard.IsMatch(processName))
continue;
Code Sample
For the complete C# sample code, see StopProcessSample03 Sample.
Start Windows PowerShell and use Stop-Proc to stop a process using the
ProcessName alias for
the Name parameter.
PowerShell
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
Make the following entry on the command line. Because the Name parameter is
mandatory, you are
prompted for it. Entering !? brings up the help text associated
with the parameter.
PowerShell
PS> Stop-Proc
Name[0]: !?
Name[0]: notepad
Now make the following entry to stop all processes that match the wildcard
pattern *note* . You
are prompted before stopping each process that matches the
pattern.
PowerShell
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N
See Also
Create a Cmdlet that Modifies the System
How to Create a Windows PowerShell Cmdlet
Extending Object Types and Formatting
How to Register Cmdlets, Providers, and Host Applications
Supporting Wildcards in Cmdlet Parameters
Windows PowerShell SDK
Adding Parameter Sets to a Cmdlet
Article • 09/17/2021
An example of a cmdlet that uses two parameter sets to define different functionalities
is the
Get-EventLog cmdlet that is provided by Windows PowerShell. This cmdlet returns
different
information when the user specifies the List or LogName parameter. If the
LogName parameter is
specified, the cmdlet returns information about the events in a
given event log. If the List
parameter is specified, the cmdlet returns information about
the log files themselves (not the event
information they contain). In this case, the List
and LogName parameters identify two separate
parameter sets.
Two important things to remember about parameter sets is that the Windows
PowerShell runtime uses
only one parameter set for a particular input, and that each
parameter set must have at least one
parameter that is unique for that parameter set.
To illustrate that last point, this Stop-Proc cmdlet uses three parameter sets:
ProcessName ,
ProcessId , and InputObject . Each of these parameter sets has one
parameter that is not in the
other parameter sets. The parameter sets could share other
parameters, but the cmdlet uses the
unique parameters ProcessName , ProcessId , and
InputObject to identify which set of parameters
that the Windows PowerShell runtime
should use.
7 Note
For more information about approved cmdlet verb names, see
Cmdlet Verb
Names.
The following code is the class definition for this Stop-Proc cmdlet.
C#
[Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName = "ProcessId",
SupportsShouldProcess = true)]
VB
SupportsShouldProcess:=True)> _
Inherits PSCmdlet
C#
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
)]
[Alias("ProcessName")]
VB
<Parameter(Position:=0, ParameterSetName:="ProcessName", _
Mandatory:=True, _
ValueFromPipeline:=True, ValueFromPipelineByPropertyName:=True, _
Get
Return processNames
End Get
processNames = value
End Set
End Property
C#
[Parameter(
ParameterSetName = "ProcessId",
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ValueFromPipeline = true
)]
[Alias("ProcessId")]
public int[] Id
VB
<Parameter(ParameterSetName:="ProcessId", _
Mandatory:=True, _
ValueFromPipelineByPropertyName:=True, _
ValueFromPipeline:=True), [Alias]("ProcessId")> _
Get
Return processIds
End Get
processIds = value
End Set
End Property
C#
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
VB
<Parameter(ParameterSetName:="InputObject", _
Mandatory:=True, ValueFromPipeline:=True)> _
Get
Return myInputObject
End Get
myInputObject = value
End Set
End Property
C#
switch (ParameterSetName)
case "ProcessName":
ProcessByName();
break;
case "ProcessId":
ProcessById();
break;
case "InputObject":
foreach (Process process in inputObject)
SafeStopProcess(process);
break;
default:
} // switch (ParameterSetName...
} // ProcessRecord
VB
Case "ProcessName"
ProcessByName()
Case "ProcessId"
ProcessById()
Case "InputObject"
SafeStopProcess(process)
Next process
Case Else
End Select
The Helper methods called by the Select statement are not described here, but you can
see their
implementation in the complete code sample in the next section.
Code Sample
For the complete C# sample code, see StopProcessSample04 Sample.
With Windows PowerShell started, run the Stop-Proc cmdlet with the ProcessId
parameter set to
stop a process based on its identifier. In this case, the cmdlet is
using the ProcessId
parameter set to stop the process.
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
With Windows PowerShell started, run the Stop-Proc cmdlet with the InputObject
parameter set to
stop processes on the Notepad object retrieved by the Get-
Process command.
Confirm
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N
See Also
Creating a Cmdlet that Modifies the System
This section provides a tutorial for creating the Select-Str cmdlet, which is very similar to
the Select-String cmdlet provided by Windows PowerShell. This tutorial provides
fragments of code that illustrate how cmdlets are implemented, and an explanation of
the code.
See Also
Creating a Cmdlet to Access a Data Store
This section describes how to create a cmdlet that accesses stored data by way of a
Windows PowerShell provider. This type of cmdlet uses the Windows PowerShell
provider infrastructure of the Windows PowerShell runtime and, therefore, the cmdlet
class must derive from the System.Management.Automation.PSCmdlet base class.
The Select-Str cmdlet described here can locate and select strings in a file or object. The
patterns used to identify the string can be specified explicitly through the Path
parameter of the cmdlet or implicitly through the Script parameter.
The cmdlet is designed to use any Windows PowerShell provider that derives from
System.Management.Automation.Provider.Icontentcmdletprovider. For example, the
cmdlet can specify the FileSystem provider or the Variable provider that is provided by
Windows PowerShell. For more information aboutWindows PowerShell providers, see
Designing Your Windows PowerShell provider.
The .NET class for this cmdlet must derive from the
System.Management.Automation.PSCmdlet base class, because it provides the support
needed by the Windows PowerShell runtime to expose the Windows PowerShell
provider infrastructure. Note that this cmdlet also makes use of the .NET Framework
regular expressions classes, such as System.Text.Regularexpressions.Regex.
The following code is the class definition for this Select-Str cmdlet.
C#
[Cmdlet(VerbsCommon.Select, "Str",
DefaultParameterSetName="PatternParameterSet")]
information about this parameter set, see the Pattern and Script parameter discussion
in the following section.
7 Note
For more information about the basics of defining parameters, see Adding
Parameters that Process Command Line Input.
C#
[Parameter(
Position = 0,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
[Parameter(
Position = 0,
ParameterSetName = "PatternParameterSet",
ValueFromPipeline = true,
Mandatory = true)]
[Alias("PSPath")]
more information about parameter sets, see Adding Parameter Sets to a Cmdlet.
C#
[Parameter(
Position = 1,
ParameterSetName = "PatternParameterSet",
Mandatory = true)]
When this parameter is specified, the cmdlet uses the default parameter set
PatternParameterSet . In this case, the cmdlet uses the patterns specified here to select
strings. In contrast, the Script parameter could also be used to provide a script that
contains the patterns. The Script and Pattern parameters define two separate
parameter sets, so they are mutually exclusive.
The Script parameter specifies a script block that can be used to provide an alternate
search mechanism for the cmdlet. The script must contain the patterns used for
matching and return a System.Management.Automation.PSObject object. Note that this
parameter is also the unique parameter that identifies the ScriptParameterSet
parameter set. When the Windows PowerShell runtime sees this parameter, it uses only
parameters that belong to the ScriptParameterSet parameter set.
C#
[Parameter(
Position = 1,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
ScriptBlock script;
The SimpleMatch parameter is a switch parameter that indicates whether the cmdlet is to
explicitly match the patterns as they are supplied. When the user specifies the parameter
at the command line ( true ), the cmdlet uses the patterns as they are supplied. If the
parameter is not specified ( false ), the cmdlet uses regular expressions. The default for
this parameter is false .
C#
[Parameter]
[Parameter]
The Exclude and Include parameters identify items that are explicitly excluded from or
included in the search. By default, the cmdlet will search all items in the data store.
However, to limit the search performed by the cmdlet, these parameters can be used to
explicitly indicate items to be included in the search or omitted.
C#
[Parameter]
C#
[Parameter]
[ValidateNotNullOrEmpty]
get
return includeStrings;
set
includeStrings = value;
C#
WriteDebug("Validating patterns.");
if (patterns != null)
{
if (pattern == null)
ThrowTerminatingError(new ErrorRecord(
new ArgumentNullException(
"NullSearchPattern",
ErrorCategory.InvalidArgument,
pattern)
);
if (!simpleMatch)
if (!caseSensitive)
regexOptions |= RegexOptions.Compiled;
try
ThrowTerminatingError(new ErrorRecord(
ex,
"InvalidRegularExpression",
ErrorCategory.InvalidArgument,
patterns[i]
));
else
if (!caseSensitive)
wildcardOptions |= WildcardOptions.IgnoreCase;
wildcardPattern[i] =
C#
UInt64 lineNumber = 0;
MatchInfo result;
// Once the filepaths are expanded, we may have more than one
foreach(PathInfo path in
SessionState.Path.GetResolvedPSPathFromPSPath(psPath)
if (!MeetsIncludeExcludeCriteria(path.ProviderPath))
continue;
// specified path.
try
readerCollection =
this.InvokeProvider.Content.GetReader(path.Path);
WriteError(new ErrorRecord(ex,
"ContentAccessNotSupported",
ErrorCategory.NotImplemented,
path.Path)
);
return;
lineNumber = 0;
// processed.
lineNumber++;
WriteDebug(message);
result = SelectString(items[0]);
if (result != null)
result.Path = path.Path;
result.LineNumber = lineNumber;
WriteObject(result);
else
nonMatches.Add(items[0]);
items = reader.Read(1);
try
this.SessionState.PSVariable.Set("NonMatches", nonMatches);
WriteError(new ErrorRecord(ex,
"CannotWriteVariableNonMatches",
ErrorCategory.InvalidOperation,
nonMatches)
);
Accessing Content
Your cmdlet must open the provider indicated by the Windows PowerShell path so that
it can access the data. The System.Management.Automation.Sessionstate object for the
runspace is used for access to the provider, while the
System.Management.Automation.PSCmdlet.Invokeprovider* property of the cmdlet is
used to open the provider. Access to content is provided by retrieval of the
System.Management.Automation.Providerintrinsics object for the provider opened.
Code Sample
The following code shows the implementation of this version of this Select-Str cmdlet.
Note that this code includes the cmdlet class, private methods used by the cmdlet, and
the Windows PowerShell snap-in code used to register the cmdlet. For more information
about registering the cmdlet, see Building the Cmdlet.
C#
//
//
// PARTICULAR PURPOSE.
//
using System;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Commands
#region SelectStringCommand
/// <summary>
/// </summary>
/// <remarks>
/// This cmdlet can be used to search any object, such as a file or a
/// variable, whose provider exposes methods for reading and writing
/// content.
/// </remarks>
[Cmdlet(VerbsCommon.Select, "Str",
DefaultParameterSetName="PatternParameterSet")]
#region Parameters
/// <summary>
/// Declare a Path parameter that specifies where the data is stored.
/// searched for matching patterns. This parameter should also have
/// a PSPath alias to provide consistency with other cmdlets that use
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
[Parameter(
Position = 0,
ParameterSetName = "PatternParameterSet",
ValueFromPipeline = true,
Mandatory = true)]
[Alias("PSPath")]
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[Parameter(
Position = 1,
ParameterSetName = "PatternParameterSet",
Mandatory = true)]
public string[] Pattern
/// <summary>
/// </summary>
[Parameter(
Position = 1,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
public ScriptBlock Script
ScriptBlock script;
/// <summary>
/// Declare a switch parameter that specifies if the pattern(s) are used
/// </summary>
[Parameter]
/// <summary>
/// is performed.
/// </summary>
[Parameter]
/// <summary>
/// is used, items that are not listed here are omitted
/// </summary>
[Parameter]
[ValidateNotNullOrEmpty]
get
return includeStrings;
set
includeStrings = value;
/// <summary>
/// </summary>
///
[Parameter]
[ValidateNotNullOrEmpty]
get
return excludeStrings;
set
excludeStrings = value;
#endregion Parameters
#region Overrides
/// <summary>
/// </summary>
WriteDebug("Validating patterns.");
if (patterns != null)
if (pattern == null)
ThrowTerminatingError(new ErrorRecord(
new ArgumentNullException(
"NullSearchPattern",
ErrorCategory.InvalidArgument,
pattern)
);
if (!simpleMatch)
if (!caseSensitive)
regexOptions |= RegexOptions.Compiled;
try
ThrowTerminatingError(new ErrorRecord(
ex,
"InvalidRegularExpression",
ErrorCategory.InvalidArgument,
patterns[i]
));
else
if (!caseSensitive)
wildcardOptions |= WildcardOptions.IgnoreCase;
wildcardPattern[i] =
/// <summary>
/// Process the input and search for the specified patterns.
/// </summary>
UInt64 lineNumber = 0;
MatchInfo result;
// Once the filepaths are expanded, we may have more than one
foreach(PathInfo path in
SessionState.Path.GetResolvedPSPathFromPSPath(psPath)
if (!MeetsIncludeExcludeCriteria(path.ProviderPath))
continue;
// specified path.
try
readerCollection =
this.InvokeProvider.Content.GetReader(path.Path);
WriteError(new ErrorRecord(ex,
"ContentAccessNotSupported",
ErrorCategory.NotImplemented,
path.Path)
);
return;
lineNumber = 0;
// processed.
lineNumber++;
lineNumber, items[0]);
WriteDebug(message);
result = SelectString(items[0]);
if (result != null)
result.Path = path.Path;
result.LineNumber = lineNumber;
WriteObject(result);
else
nonMatches.Add(items[0]);
items = reader.Read(1);
try
this.SessionState.PSVariable.Set("NonMatches", nonMatches);
WriteError(new ErrorRecord(ex,
"CannotWriteVariableNonMatches",
ErrorCategory.InvalidOperation,
nonMatches)
);
#endregion Overrides
#region PrivateMethods
/// <summary>
/// Check for a match using the input string and the pattern(s)
/// specified.
/// </summary>
try
line = (string)LanguagePrimitives.ConvertTo(
input,
typeof(string)
);
WriteError(new ErrorRecord(
ex,
"CannotCastObjectToString",
ErrorCategory.InvalidOperation,
input)
);
return null;
// one object.
if (script != null)
Collection<PSObject> psObjects =
script.Invoke(
line,
simpleMatch,
caseSensitive
);
if (LanguagePrimitives.IsTrue(psObject))
result.Line = line;
result.IgnoreCase = !caseSensitive;
break;
} //End of If.
else
int patternIndex = 0;
if ((simpleMatch &&
wildcardPattern[patternIndex].IsMatch(line))
|| (regexPattern != null
&& regexPattern[patternIndex].IsMatch(line))
result.IgnoreCase = !caseSensitive;
result.Line = line;
result.Pattern = patterns[patternIndex];
break;
patternIndex++;
return result;
/// <summary>
/// Check whether the supplied name meets the include/exclude criteria.
/// That is - it's on the include list if the include list was
/// specified, and not on the exclude list if the exclude list was
specified.
/// </summary>
bool ok = false;
if (this.include != null)
if (patternItem.IsMatch(path))
ok = true;
break;
else
ok = true;
if (!ok)
return false;
if (this.exclude != null)
if (patternItem.IsMatch(path))
ok = false;
break;
return ok;
} //MeetsIncludeExcludeCriteria
#endregion SelectStringCommand
#region MatchInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <remarks>
/// stream.
/// </remarks>
set
pathSet = true;
path = value;
/// <summary>
/// </summary>
/// <summary>
/// depends on whether a path has been set for this object or
/// not.
/// </summary>
/// <remarks>
/// number and line text. If path is not set, then just the
/// </remarks>
if (pathSet)
return String.Format(
System.Threading.Thread.CurrentThread.CurrentCulture,
MatchFormat,
this.path,
this.lineNumber,
this.line
);
else
return this.line;
#endregion
/// <summary>
/// </summary>
[RunInstaller(true)]
/// <summary>
/// </summary>
public SelectStringPSSnapIn()
: base()
/// <summary>
/// </summary>
get
return "SelectStrPSSnapIn";
/// <summary>
/// </summary>
get
return "Microsoft";
/// <summary>
/// </summary>
get
return "SelectStrSnapIn,Microsoft";
/// <summary>
/// </summary>
get
/// <summary>
/// </summary>
get
} //namespace Microsoft.Samples.PowerShell.Commands;
1. Start Windows PowerShell, and search the Notes file for occurrences of lines with
the expression ".NET". Note that the quotation marks around the name of the path
are required only if the path consists of more than one word.
PowerShell
select-str -Path "notes" -Pattern ".NET" -SimpleMatch=$false
Output
IgnoreCase : True
LineNumber : 8
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : .NET
IgnoreCase : True
LineNumber : 21
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : .NET
2. Search the Notes file for occurrences of lines with the word "over", followed by any
other text. The SimpleMatch parameter is using the default value of false . The
search is case-insensitive because the CaseSensitive parameter is set to false .
PowerShell
Output
IgnoreCase : True
LineNumber : 45
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : over*
IgnoreCase : True
LineNumber : 49
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : over*
3. Search the Notes file using a regular expression as the pattern. The cmdlet
searches for alphabetical characters and blank spaces enclosed in parentheses.
PowerShell
Output
IgnoreCase : True
LineNumber : 1
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : \([A-Za-z:blank:]
IgnoreCase : True
LineNumber : 53
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : \([A-Za-z:blank:]
4. Perform a case-sensitive search of the Notes file for occurrences of the word
"Parameter".
PowerShell
Output
IgnoreCase : False
LineNumber : 6
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : Parameter
IgnoreCase : False
LineNumber : 30
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : Parameter
5. Search the variable provider shipped with Windows PowerShell for variables that
have numerical values from 0 through 9.
PowerShell
select-str -Path * -Pattern "[0-9]"
Output
IgnoreCase : True
LineNumber : 1
Line : 64
Path : Variable:\MaximumHistoryCount
Pattern : [0-9]
6. Use a script block to search the file SelectStrCommandSample.cs for the string
"Pos". The cmatch function for the script performs a case-insensitive pattern
match.
PowerShell
Output
IgnoreCase : True
LineNumber : 37
Line : Position = 0.
Path : C:\PowerShell-
Progs\workspace\Samples\SelectStr\SelectStrCommandSample.cs
Pattern :
See Also
How to Create a Windows PowerShell Cmdlet
This section describes sample code that is provided in the Windows PowerShell 2.0 SDK.
In This Section
GetProcessSample01 Sample This sample shows how to write a cmdlet
that retrieves the
processes on the local computer.
Events01 Sample This sample shows how to create a cmdlet that allows the
user to
register for events raised by
System.IO.Filesystemwatcher. With this cmdlet users can,
for
example, register an action to execute when a file is created under a specific directory.
This
sample derives from the
Microsoft.PowerShell.Commands.Objecteventregistrationbase
base class.
See Also
Writing a Windows PowerShell Cmdlet
GetProcessSample01 Sample
Article • 09/17/2021
This sample shows how to implement a cmdlet that retrieves the processes on the local
computer. This cmdlet is a simplified version of the Get-Process cmdlet that is provided
by Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Microsoft Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
Add-PSSnapin GetProcPSSnapIn01
get-proc
PowerShell
Output
Requirements
This sample requires Windows PowerShell 1.0 or later.
Demonstrates
This sample demonstrates the following.
Creating a snap-in that works with both Windows PowerShell 1.0 and Windows
PowerShell 2.0. Subsequent samples use modules instead of snap-ins so they
require Windows PowerShell 2.0.
Example
This sample shows how to create a simple cmdlet and its snap-in.
C#
using System;
using System.Diagnostics;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Commands
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
/// <summary>
/// </summary>
WriteObject(processes, true);
#endregion Overrides
} //GetProcCommand
#endregion GetProcCommand
/// <summary>
/// </summary>
[RunInstaller(true)]
/// <summary>
/// </summary>
public GetProcPSSnapIn01()
: base()
/// <summary>
/// Get a name for this PowerShell snap-in. This name will be used in
registering
/// </summary>
get
return "GetProcPSSnapIn01";
/// <summary>
/// </summary>
get
return "Microsoft";
/// <summary>
/// resourceBaseName,resourceName.
/// </summary>
get
return "GetProcPSSnapIn01,Microsoft";
/// <summary>
/// </summary>
get
See Also
Writing a Windows PowerShell Cmdlet
GetProcessSample02 Sample
Article • 09/17/2021
This sample shows how to write a cmdlet that retrieves the processes on the local
computer. It provides a Name parameter that can be used to specify the processes to be
retrieved. This cmdlet is a simplified version of the Get-Process cmdlet provided by
Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/GetProcessSample02
4. Run the following command to load the assembly into Windows PowerShell:
import-module getprossessample02
get-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample shows an implementation of the Get-Proc cmdlet that includes a Name
parameter.
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Diagnostics;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
} // End if (processNames...).
} // End ProcessRecord.
#endregion GetProcCommand
See Also
Writing a Windows PowerShell Cmdlet
GetProcessSample03 Sample
Article • 09/17/2021
This sample shows how to implement a cmdlet that retrieves the processes on the local
computer. It provides a Name parameter that can accept an object from the pipeline or a
value from a property of an object whose property name is the same as the parameter
name. This cmdlet is a simplified version of the Get-Process cmdlet provided by
Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/GetProcessSample03
4. Run the following command to load the assembly into Windows PowerShell:
Import-module getprossessample03
get-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Specifying that the parameter takes input from the pipeline. The input can be
taken from an object or a value from a property of an object whose property name
is the same as the parameter name.
Example
This sample shows an implementation of the Get-Proc cmdlet that includes a Name
parameter that accepts input from the pipeline.
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Diagnostics;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
} // End ProcessRecord.
#endregion Overrides
} // End GetProcCommand.
#endregion GetProcCommand
See Also
Writing a Windows PowerShell Cmdlet
GetProcessSample04 Sample
Article • 09/17/2021
This sample shows how to implement a cmdlet that retrieves the processes on the local
computer. It generates a nonterminating error if an error occurs while retrieving a
process. This cmdlet is a simplified version of the Get-Process cmdlet provided by
Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/GetProcessSample04
4. Run the following command to load the assembly into Windows PowerShell:
Import-module getprossessample04
get-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Specifying that the parameter takes input from the pipeline. The input can be
taken from an object or a value from a property of an object whose property name
is the same as the parameter name.
Trapping a nonterminating error and writing an error message to the error stream.
Example
This sample shows how to create a cmdlet that handles nonterminating errors and
writes error messages to the error stream.
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Diagnostics;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
// error stream.
Process[] processes;
try
processes = Process.GetProcessesByName(name);
WriteError(new ErrorRecord(
ex,
"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation,
name));
continue;
WriteObject(processes, true);
} // else
} // ProcessRecord
#endregion Overrides
#endregion GetProcCommand
See Also
Writing a Windows PowerShell Cmdlet
GetProcessSample05 Sample
Article • 09/17/2021
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug directories.
[user]/documents/windowspowershell/modules/GetProcessSample05
4. Run the following command to load the assembly into Windows PowerShell:
Import-module getprossessample05
get-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Specifying that parameters can take input from the pipeline. The input can be
taken from an object or a value from a property of an object whose property name
is the same as the parameter name.
Example
This sample shows how to create a cmdlet that displays a list of specified processes.
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Permissions;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc",
DefaultParameterSetName = "ProcessName")]
#region Fields
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
#endregion Fields
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
/// <summary>
/// </summary>
[Parameter(
ParameterSetName = "Id",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
public int[] Id
/// <summary>
/// stream of [collection of] Process objects, the cmdlet bypasses the
/// directly. This allows the cmdlet to deal with processes that have
/// </summary>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
#endregion Parameters
/// <summary>
/// </summary>
List<Process> matchingProcesses;
switch (ParameterSetName)
case "Id":
matchingProcesses = this.GetMatchingProcessesById();
break;
case "ProcessName":
matchingProcesses = this.GetMatchingProcessesByName();
break;
case "InputObject":
matchingProcesses = this.GetProcessesByInput();
break;
default:
ThrowTerminatingError(
new ErrorRecord(
"UnableToAccessProcessList",
ErrorCategory.InvalidOperation,
null));
return;
} // switch (ParameterSetName)
matchingProcesses.Sort(ProcessComparison);
WriteObject(process);
}
} // ProcessRecord
#endregion Overrides
/// <summary>
/// specified process name which is not found even though the name
/// </summary>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();
List<Process> allProcesses =
new List<Process>(Process.GetProcesses());
if (null == this.processNames)
matchingProcesses.AddRange(allProcesses);
else
+ pattern + "\".");
WildcardPattern wildcard =
new WildcardPattern(
pattern,
WildcardOptions.IgnoreCase);
if (!keys.ContainsKey(process.Id))
if (processName.Length == 0)
allProcesses.Remove(process);
// pattern specified.
if (!wildcard.IsMatch(processName))
continue;
+ process.Id + ".");
// A match is found.
found = true;
keys.Add(process.Id, 0);
} // foreach (Process...
if (!found &&
!WildcardPattern.ContainsWildcardCharacters(pattern))
WriteError(new ErrorRecord(
"ProcessNameNotFound",
ErrorCategory.ObjectNotFound,
pattern));
} // foreach (string...
} // if (null...
return matchingProcesses;
} // GetMatchingProcessesByName
/// <summary>
/// </summary>
/// returned.</param>
[EnvironmentPermissionAttribute(
new EnvironmentPermission(PermissionState.Unrestricted).Assert();
if (process != null)
try
return process.ProcessName;
catch (Win32Exception)
catch (InvalidOperationException)
return name;
} // SafeGetProcessName
/// <summary>
/// </summary>
/// </returns>
SafeGetProcessName(x),
SafeGetProcessName(y),
StringComparison.CurrentCultureIgnoreCase);
if (0 != diff)
{
return diff;
else
return x.Id.CompareTo(y.Id);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();
if (null != this.processIds)
+ processId + ".");
if (!keys.ContainsKey(processId))
Process process;
try
process = Process.GetProcessById(processId);
WriteError(new ErrorRecord(
ex,
"ProcessIdNotFound",
ErrorCategory.ObjectNotFound,
processId));
continue;
matchingProcesses.Add(process);
keys.Add(processId, 0);
return matchingProcesses;
} // GetMatchingProcessesById
/// <summary>
/// parameter.
/// </summary>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();
if (null != this.Input)
if (!keys.ContainsKey(process.Id))
try
process.Refresh();
catch (Win32Exception)
catch (InvalidOperationException)
matchingProcesses.Add(process);
return matchingProcesses;
} // GetProcessesByInput
#endregion GetProcCommand
See Also
Writing a Windows PowerShell Cmdlet
StopProcessSample01 Sample
Article • 09/17/2021
This sample shows how to write a cmdlet that requests feedback from the user before it
attempts to stop a process, and how to implement a PassThru parameter indicating that
the user wants the cmdlet to return an object. This cmdlet is similar to the Stop-Process
cmdlet provided by Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Microsoft Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/StopProcessSample01
4. Run the following command to load the assembly into Windows PowerShell:
import-module stopprossessample01
stop-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Implementing a PassThru parameter that indicates if the user wants the cmdlet to
return an object. By default, this cmdlet does not return an object to the pipeline.
Example
This sample shows how to implement a PassThru parameter that indicates that the user
wants the cmdlet to return an object, and how to request user feedback by calls to the
ShouldProcess and ShouldContinue methods.
C#
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Commands
#region StopProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
/// <summary>
/// the cmdlet to stop its operation. This parameter should always
/// </summary>
[Parameter]
/// <summary>
/// </summary>
[Parameter]
#endregion Parameters
/// <summary>
/// The ProcessRecord method does the following for each of the
/// </summary>
// processes.
// a process.
Process[] processes;
try
processes = Process.GetProcessesByName(name);
WriteError(new
ErrorRecord(ioe,"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation, name));
continue;
string processName;
try
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.ReadError,
process));
continue;
if
(!ShouldProcess(string.Format(CultureInfo.CurrentCulture,"{0} ({1})",
processName,
process.Id)))
continue;
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));
if (criticalProcess &&!force)
(CultureInfo.CurrentCulture,
processName);
if (!ShouldContinue(message, "Warning!",
continue;
} // if (criticalProcess...
try
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a nonterminating error.
WriteError(new ErrorRecord(e,
"CouldNotStopProcess",
ErrorCategory.CloseError,
process));
continue;
} // if ((e is...
else throw;
} // catch
if (passThru)
WriteObject(process);
} // foreach (Process...
} // foreach (string...
} // ProcessRecord
/// <summary>
/// </summary>
);
} // StopProcCommand
#endregion StopProcCommand
See Also
Writing a Windows PowerShell Cmdlet
StopProcessSample02 Sample
Article • 09/17/2021
This sample shows how to write a cmdlet that writes debug (WriteDebug), verbose
(WriteVerbose), and warning (WriteWarning) messages while stopping processes on the
local computer. This cmdlet is similar to the Stop-Process cmdlet provided by Windows
PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Microsoft Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/StopProcessSample02
4. Run the following command to load the assembly into Windows PowerShell:
import-module stopprossessample02
stop-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Writing verbose messages. For more information about the method used to write
verbose messages, see System.Management.Automation.Cmdlet.WriteVerbose.
Writing error messages. For more information about the method used to write
error messages, see System.Management.Automation.Cmdlet.WriteError.
Writing warning messages. For more information about the method used to write
warning messages, see System.Management.Automation.Cmdlet.WriteWarning.
Example
This sample shows how to write debug, verbose, and warning messages by using the
WriteDebug , WriteVerbose , and WriteWarning methods.
C#
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Commands
#region StopProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
/// <summary>
/// the cmdlet to stop its operation. This parameter should always
/// </summary>
[Parameter]
/// <summary>
/// </summary>
[Parameter]
#endregion Parameters
/// <summary>
/// The ProcessRecord method does the following for each of the
/// </summary>
// processes.
// a process.
message = String.Format(CultureInfo.CurrentCulture,
WriteVerbose(message);
Process[] processes;
try
processes = Process.GetProcessesByName(name);
WriteError(new ErrorRecord(ioe,
"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation,
name));
continue;
string processName;
try
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.ObjectNotFound,
process));
continue;
message = String.Format(CultureInfo.CurrentCulture,
process.Id, processName);
WriteDebug(message);
if
(!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
"{0} ({1})",
processName, process.Id)))
continue;
message = String.Format(CultureInfo.CurrentCulture,
processName);
if (!ShouldContinue(message, "Warning!",
continue;
} // if (criticalProcess...
// critical process.
if (criticalProcess)
message = String.Format(CultureInfo.CurrentCulture,
processName);
WriteWarning(message);
} // if (criticalProcess...
try
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a nonterminating error.
WriteError(new ErrorRecord(
e,
"CouldNotStopProcess",
ErrorCategory.CloseError,
process)
);
continue;
} // if ((e is...
else throw;
} // catch
message = String.Format(CultureInfo.CurrentCulture,
processName, process.Id);
WriteVerbose(message);
if (passThru)
message = String.Format(CultureInfo.CurrentCulture,
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru...
} // foreach (Process...
} // foreach (string...
} // ProcessRecord
/// <summary>
/// </summary>
);
} // StopProcCommand
#endregion StopProcCommand
See Also
Writing a Windows PowerShell Cmdlet
StopProcessSample03 Sample
Article • 09/17/2021
This sample shows how to write a cmdlet whose parameters have aliases and whose
parameters support wildcard characters. This cmdlet is similar to the Stop-Process
cmdlet provided by Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Microsoft Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/StopProcessSample03
4. Run the following command to load the assembly into Windows PowerShell:
import-module stopprossessample03
stop-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample shows how to declare parameter aliases and support wildcards.
C#
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Commands
#region StopProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
)]
[Alias("ProcessName")]
/// <summary>
/// the cmdlet to stop its operation. This parameter should always
/// </summary>
[Parameter]
/// <summary>
/// </summary>
[Parameter(
ValueFromPipelineByPropertyName = true,
)]
#endregion Parameters
/// <summary>
/// The ProcessRecord method does the following for each of the
/// </summary>
try
processes = Process.GetProcesses();
base.ThrowTerminatingError(new ErrorRecord(ioe,
"UnableToAccessProcessList",
ErrorCategory.InvalidOperation,
null));
// processes.
WriteVerbose(message);
WildcardOptions.Compiled;
string processName;
try
processName = process.ProcessName;
catch (Win32Exception e)
WriteError(new ErrorRecord(
e, "ProcessNameNotFound",
ErrorCategory.ObjectNotFound,
process)
);
continue;
message = String.Format(CultureInfo.CurrentCulture,
process.Id, processName);
WriteDebug(message);
if (!wildcard.IsMatch(processName))
continue;
SafeStopProcess(process);
} // foreach (Process...
} // foreach (string...
} // ProcessRecord
/// <summary>
/// </summary>
try
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.ObjectNotFound, process));
return;
if (!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
return;
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));
message = String.Format(CultureInfo.CurrentCulture,
processName);
// Cmdlet.
if (!ShouldContinue(message, "Warning!",
return;
} // if (criticalProcess...
// process.
if (criticalProcess)
message = String.Format(CultureInfo.CurrentCulture,
processName);
WriteWarning(message);
} // if (criticalProcess...
try
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a non-terminating error.
ErrorCategory.CloseError,
process)
);
return;
} // if ((e is...
else throw;
} // catch
message = String.Format(CultureInfo.CurrentCulture,
processName, process.Id);
WriteVerbose(message);
if (passThru)
message = String.Format(CultureInfo.CurrentCulture,
WriteDebug(message);
WriteObject(process);
} // if (passThru...
} // SafeStopProcess
/// <summary>
/// </summary>
);
} // StopProcCommand
#endregion StopProcCommand
} // namespace Microsoft.Samples.PowerShell.Commands
See Also
Writing a Windows PowerShell Cmdlet
StopProcessSample04 Sample
Article • 09/17/2021
This sample shows how to write a cmdlet that declares parameter sets, specifies the
default parameter set, and can accept an input object. This cmdlet is similar to the Stop-
Process cmdlet provided by Windows PowerShell 2.0.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Microsoft Visual Studio.
The library for the sample will be built in the default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/StopProcessSample04
4. Run the following command to load the assembly into Windows PowerShell:
import-module stopprossessample04
stop-proc
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
The following code shows an implementation of the Stop-Proc cmdlet that declare
parameter sets, specifies the default parameter set, and can accept an input object.
This sample shows the input object, how to declare parameter sets, and how to specify
the default parameter set to use.
C#
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Commands
#region StopProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName = "ProcessId",
SupportsShouldProcess = true)]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
)]
[Alias("ProcessName")]
/// <summary>
/// the cmdlet to stop its operation. This parameter should always
/// </summary>
[Parameter]
/// <summary>
/// </summary>
[Parameter(
)]
[Parameter(
ParameterSetName = "ProcessId",
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ValueFromPipeline = true
)]
[Alias("ProcessId")]
public int[] Id
/// <summary>
/// </summary>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
#endregion Parameters
#region CmdletOverrides
/// <summary>
/// The ProcessRecord method does the following for each of the
/// </summary>
switch (ParameterSetName)
case "ProcessName":
ProcessByName();
break;
case "ProcessId":
ProcessById();
break;
case "InputObject":
SafeStopProcess(process);
break;
default:
} // switch (ParameterSetName...
} // ProcessRecord
/// <summary>
/// </summary>
/// </param>
WildcardOptions.Compiled;
try
processNameToMatch = process.ProcessName;
catch (Win32Exception e)
// checked again.
allProcesses.Remove(process);
string message =
String.Format(CultureInfo.CurrentCulture, "The
process \"{0}\" could not be found",
processName);
WriteVerbose(message);
ErrorCategory.ObjectNotFound,
processName));
continue;
if (!wildcard.IsMatch(processNameToMatch))
continue;
matchingProcesses.Add(process);
} // foreach(Process...
return matchingProcesses;
} // SafeGetProcessesByName
/// <summary>
/// </summary>
try
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.OpenError, processName));
return;
if (!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
return;
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));
message = String.Format(CultureInfo.CurrentCulture,
processName);
if (!ShouldContinue(message, "Warning!",
return;
} // if (criticalProcess...
// process.
if (criticalProcess)
message =
String.Format(CultureInfo.CurrentCulture,
processName);
WriteWarning(message);
} // if (criticalProcess...
try
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a non-terminating error.
ErrorCategory.CloseError,
process)
);
return;
} // if ((e is...
else throw;
} // catch
message = String.Format(CultureInfo.CurrentCulture,
processName, process.Id);
WriteVerbose(message);
if (passThru)
message =
String.Format(CultureInfo.CurrentCulture,
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru..
} // SafeStopProcess
/// <summary>
/// </summary>
try
base.ThrowTerminatingError(new ErrorRecord(
ioe, "UnableToAccessProcessList",
ErrorCategory.InvalidOperation, null));
// retrieve a process.
// from the list so that its not compared the next time.
ArrayList processes =
// terminating error.
if (processes.Count == 0)
WriteError(new ErrorRecord(
"ProcessNotFound",
ErrorCategory.ObjectNotFound,
name));
} // if (processes...
else
SafeStopProcess(process);
} // foreach (Process...
} // else
} // foreach (string...
} // ProcessByName
/// <summary>
/// </summary>
try
process = Process.GetProcessById(processId);
string message =
String.Format(CultureInfo.CurrentCulture,
process.Id);
WriteDebug(message);
string
message = String.Format(CultureInfo.CurrentCulture,
processId);
WriteVerbose(message);
ErrorCategory.ObjectNotFound,
processId));
continue;
SafeStopProcess(process);
} // foreach (int...
} // ProcessById
/// <summary>
/// </summary>
);
} // StopProcCommand
#endregion StopProcCommand
See Also
Writing a Windows PowerShell Cmdlet
Events01 Sample
Article • 09/17/2021
This sample shows how to create a cmdlet that allows the user to register for events that
are raised
by System.IO.FileSystemWatcher. With this cmdlet, users
can register an action
to execute when a file is created under a specific directory. This sample
derives from the
Microsoft.PowerShell.Commands.ObjectEventRegistrationBase
base class.
2. Double-click the icon for the solution (.sln) file. This opens the sample project in
Microsoft
Visual Studio.
3. In the Build menu, select Build Solution. The library for the sample will be built in
the
default \bin or \bin\debug folders.
[user]/documents/windowspowershell/modules/events01
2. Copy the library file for the sample to the module folder.
4. Run the following command to load the cmdlet into Windows PowerShell:
PowerShell
import-module events01
PowerShell
Register-FileSystemEvent $env:temp Created -filter "*.txt" -action {
Write-Host "A file was created in the TEMP directory" }
6. Create a file under the TEMP directory and note that the action is executed (the
message is
displayed).
Output
PowerShell
Output
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
C#
namespace Sample
using System;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell.Commands;
[Cmdlet(VerbsLifecycle.Register, "FileSystemEvent")]
/// <summary>
/// </summary>
get
return this.fileSystemWatcher.Path;
set
this.fileSystemWatcher.Path = value;
/// <summary>
/// Gets or sets the name of the event to which the cmdlet
registers.
/// <para>
/// </para>
/// </summary>
get
return this.eventName;
set
this.eventName = value;
/// <summary>
/// </summary>
[Parameter(Mandatory = false)]
get
return this.fileSystemWatcher.Filter;
set
this.fileSystemWatcher.Filter = value;
/// <summary>
/// Derived classes must implement this method to return the object
that generates
/// </summary>
return this.fileSystemWatcher;
/// <summary>
/// Derived classes must implement this method to return the name of
the event to
/// </summary>
/// <returns> This sample returns the event specified by the user
with the -EventName parameter.</returns>
return this.eventName;
See Also
Writing a Windows PowerShell Cmdlet
Writing a Windows PowerShell Module
Article • 09/17/2021
This document is written for administrators, script developers, and cmdlet developers
who need to
package and distribute their Windows PowerShell cmdlets. By using
Windows PowerShell modules, you
can package and distribute your Windows
PowerShell solutions without using a compiled language.
Windows PowerShell modules enable you to partition, organize, and abstract your
Windows PowerShell
code into self-contained, reusable units. With these reusable units,
you can easily share your
modules directly with others. If you are a script developer, you
can also repackage third-party
modules to create custom script-based applications.
Modules, similar to modules in other scripting
languages such as Perl and Python,
enable production-ready scripting solutions that use reusable,
redistributable
components, with the added benefit of enabling you to repackage and abstract
multiple
components to create custom solutions.
At their most basic, Windows PowerShell will treat any valid Windows PowerShell script
code saved in
a .psm1 file as a module. PowerShell will also automatically treat any
binary cmdlet assembly as a
module. However, you can also use a module (or more
specifically, a module manifest) to bundle an
entire solution together. The following
scenarios describe typical uses for Windows PowerShell
modules.
Libraries
Modules can be used to package and distribute cohesive libraries of functions that
perform common
tasks. Typically, the names of these functions share one or more
nouns that reflect the common task
that they are used for. These functions can also be
similar to .NET Framework classes in that they
can have public and private members. For
example, a library can contain a set of functions for file
transfers. In this case, the noun
reflecting the common task might be "file."
Configuration
Modules can be used to customize your environment by adding specific cmdlets,
providers, functions,
and variables.
See Also
Understanding a Windows PowerShell Module
about_PSModulePath
The main purpose of a module is to allow the modularization (ie, reuse and abstraction)
of Windows
PowerShell code. For example, the most basic way of creating a module is
to simply save a Windows
PowerShell script as a .psm1 file. Doing so allows you to
control (ie, make public or private) the
functions and variables contained in the script.
Saving the script as a .psm1 file also allows you
to control the scope of certain variables.
Finally, you can also use cmdlets such as Install-Module
to organize, install, and use your
script as building blocks for larger solutions.
1. Some sort of code file - usually either a PowerShell script or a managed cmdlet
assembly.
2. Anything else that the above code file may need, such as additional assemblies,
help files, or
scripts.
3. A manifest file that describes the above files, as well as stores metadata such as
author and
versioning information.
4. A directory that contains all of the above content, and is located where PowerShell
can
reasonably find it.
7 Note
Script Modules
As the name implies, a script module is a file ( .psm1 ) that contains any valid Windows
PowerShell code. Script developers and administrators can use this type of module to
create modules
whose members include functions, variables, and more. At heart, a script
module is simply a Windows
PowerShell script with a different extension, which allows
administrators to use import, export, and
management functions on it.
In addition, you can use a manifest file to include other resources in your module, such
as data
files, other dependent modules, or runtime scripts. Manifest files are also useful
for tracking
metadata such as authoring and versioning information.
Finally, a script module, like any other module that isn't dynamically created, needs to
be saved in
a folder that PowerShell can reasonably discover. Usually, this is on the
PowerShell module path;
but if necessary you can explicitly describe where your module
is installed. For more information,
see How to Write a PowerShell Script Module.
Binary Modules
A binary module is a .NET Framework assembly ( .dll ) that contains compiled code,
such as C#.
Cmdlet developers can use this type of module to share cmdlets, providers,
and more. (Existing
snap-ins can also be used as binary modules.) Compared to a script
module, a binary module allows
you to create cmdlets that are faster or use features
(such as multithreading) that are not as easy
to code in Windows PowerShell scripts.
As with script modules, you can include a manifest file to describe additional resources
that your
module uses, and to track metadata about your module. Similarly, you
probably should install your
binary module in a folder somewhere along the PowerShell
module path. For more information, see How
to How to Write a PowerShell Binary
Module.
Manifest Modules
A manifest module is a module that uses a manifest file to describe all of its
components, but
doesn't have any sort of core assembly or script. (Formally, a manifest
module leaves the
ModuleToProcess or RootModule element of the manifest empty.)
However, you can still use the
other features of a module, such as the ability to load up
dependent assemblies or automatically run
certain pre-processing scripts. You can also
use a manifest module as a convenient way to package up
resources that other modules
will use, such as nested modules, assemblies, types, or formats. For
more information,
see How to Write a PowerShell Module Manifest.
Dynamic Modules
A dynamic module is a module that is not loaded from, or saved to, a file. Instead, they
are
created dynamically by a script, using the New-Module
cmdlet. This type of module
enables a script to create a module on demand that does not need to be
loaded or
saved to persistent storage. By its nature, a dynamic module is intended to be
short-
lived, and therefore cannot be accessed by the Get-Module cmdlet. Similarly, they usually
do
not need module manifests, nor do they likely need permanent folders to store their
related
assemblies.
Module Manifests
A module manifest is a .psd1 file that contains a hash table. The keys and values in the
hash
table do the following things:
Manifests are not required for a module. Modules can reference script files ( .ps1 ),
script
module files ( .psm1 ), manifest files ( .psd1 ), formatting and type files
( .ps1xml ), cmdlet
and provider assemblies ( .dll ), resource files, Help files,
localization files, or any other
type of file or resource that is bundled as part of the
module. For an internationalized script,
the module folder also contains a set of
message catalog files. If you add a manifest file to the
module folder, you can
reference the multiple files as a single unit by referencing the manifest.
Metadata about the module, such as the module version number, the author, and
the description.
Generally speaking, you can determine where you should install your module by using
one of the paths
stored in the $ENV:PSModulePath variable. Using one of these paths
means that PowerShell can
automatically find and load your module when a user makes
a call to it in their code. If you store
your module somewhere else, you can explicitly let
PowerShell know by passing in the location of
your module as a parameter when you
call Install-Module .
Regardless, the path of the folder is referred to as the base of the module (ModuleBase),
and
the name of the script, binary, or manifest module file should be the same as the
module folder
name, with the following exceptions:
Dynamic modules that are created by the New-Module cmdlet can be named using
the Name
parameter of the cmdlet.
$PSScriptRoot This variable contains the directory from which the script module is being
executed.
It enables scripts to use the module path to access other resources.
See Also
Writing a Windows PowerShell Module
How to Write a PowerShell Script
Module
Article • 06/09/2022
A script module is any valid PowerShell script saved in a .psm1 extension. This extension
allows
the PowerShell engine to use rules and module cmdlets on your file. Most of
these capabilities are
there to help you install your code on other systems, as well as
manage scoping. You can also use a
module manifest file, which describes more
complex installations and solutions.
1. Save a PowerShell script with a .psm1 extension. Use the same name for the script
and the
directory where the script is saved.
Saving a script with the .psm1 extension means that you can use the module
cmdlets, such as
Import-Module. The module cmdlets
exist primarily so that you
can import and export your code onto other user's systems. The
alternate solution
would be to load your code on other systems and then dot-source it into active
memory, which isn't a scalable solution. For more information, see
Understanding
a Windows PowerShell Module.
By default, when users import your .psm1 file, all
functions in your script are accessible, but
variables aren't.
PowerShell
function Show-Calendar {
param(
$firstDayOfWeek,
[int[]] $highlightDay,
#actual code for the function goes here see the end of the topic
for the complete code sample
The example code at the bottom of the article has only one function, which by
default would be
exposed. However, it's recommended you explicitly call out which
functions you wish to expose, as
described in the following code:
PowerShell
function Show-Calendar {
You can restrict what's imported using a module manifest. For more information,
see
Importing a PowerShell Module and
How to Write a PowerShell Module
Manifest.
3. If you have modules that your own module needs to load, you can use Import-
Module , at the top
of your module.
The Import-Module cmdlet imports a targeted module onto a system, and can be
used at a later
point in the procedure to install your own module. The sample code
at the bottom of this article
doesn't use any import modules. But if it did, they
would be listed at the top of the file, as
shown in the following code:
PowerShell
Import-Module GenericModule
4. To describe your module to the PowerShell Help system, you can either use
standard help comments
inside the file, or create an additional Help file.
The code sample at the bottom of this article includes the help information in the
comments. You
could also write expanded XML files that contain additional help
content. For more information,
see
Writing Help for Windows PowerShell Modules.
5. If you have additional modules, XML files, or other content you want to package
with your module,
you can use a module manifest.
A module manifest is a file that contains the names of other modules, directory
layouts,
versioning numbers, author data, and other pieces of information.
PowerShell uses the module
manifest file to organize and deploy your solution. For
more information, see
How to write a PowerShell module manifest.
6. To install and run your module, save the module to one of the appropriate
PowerShell paths, and
use Import-Module .
The paths where you can install your module are located in the $env:PSModulePath
global
variable. For example, a common path to save a module on a system would
be
%SystemRoot%/users/<user>/Documents/PowerShell/Modules/<moduleName> . Be
sure to create a
directory for your module that uses the same name as the script
module, even if it's only a
single .psm1 file. If you didn't save your module to one
of these paths, you would have to
specify the module's location in the Import-
Module command. Otherwise, PowerShell wouldn't be
able to find the module.
7 Note
Starting with PowerShell 3.0, if you've placed your module in one of the
PowerShell module paths,
you don't need to explicitly import it. Your module
is automatically loaded when a user calls
your function. For more information
about the module path, see
Importing a PowerShell Module and
about_PSModulePath.
7. To remove a module from active service in the current PowerShell session, use
Remove-Module.
7 Note
PowerShell
<#
.Synopsis
.Description
.Parameter Start
.Parameter End
.Parameter FirstDayOfWeek
.Parameter HighlightDay
Specific days (numbered) to highlight. Used for date ranges like (25..31).
Date ranges are specified by the Windows PowerShell range syntax. These
dates are
.Parameter HighlightDate
.Example
Show-Calendar
.Example
.Example
#>
function Show-Calendar {
param(
$firstDayOfWeek,
[int[]] $highlightDay,
$dateTimeFormat = (Get-Culture).DateTimeFormat
if($firstDayOfWeek)
$dateTimeFormat.FirstDayOfWeek = $firstDayOfWeek
$currentDay = $start
$currentDay = $currentDay.AddDays(-1)
$dayNames = @()
$weeks = @()
## Continue processing dates until the function reaches the end of the
month.
$dayNames += $dayName
if($highlightDate)
$currentDay.Month,$currentDay.Day
$null,$highlightDay = $highlightDay
## Add the day of the week and the day of the month as note
properties.
$currentDay = $currentDay.AddDays(1)
## If the function reaches the next week, store the current week
$weeks += $currentWeek
$displayCalendar.TrimEnd()
$start = $start.AddMonths(1)
A binary module can be any assembly (.dll) that contains cmdlet classes. By default, all
the cmdlets
in the assembly are imported when the binary module is imported.
However, you can restrict the
cmdlets that are imported by creating a module manifest
whose root module is the assembly. (For
example, the CmdletsToExport key of the
manifest can be used to export only those cmdlets that are
needed.) In addition, a
binary module can contain additional files, a directory structure, and other
pieces of
useful management information that a single cmdlet cannot.
The following procedure describes how to create and install a PowerShell binary
module.
From a code perspective, the core of a binary module is simply a cmdlet assembly.
In fact,
PowerShell will treat a single cmdlet assembly as a module, in terms of
loading and unloading,
with no additional effort on the part of the developer. For
more information about writing a
cmdlet, see Writing a Windows PowerShell
Cmdlet.
2. If necessary, create the rest of your solution: (additional cmdlets, XML files, and so
on) and
describe them with a module manifest.
C#
namespace ModuleCmdlets
[Cmdlet(VerbsDiagnostic.Test,"BinaryModuleCmdlet1")]
[Cmdlet(VerbsDiagnostic.Test, "BinaryModuleCmdlet2")]
[Cmdlet(VerbsDiagnostic.Test, "BinaryModuleCmdlet3")]
3. Package your solution, and save the package to somewhere in the PowerShell
module path.
The PSModulePath global environment variable describes the default paths that
PowerShell will
use to locate your module. For example, a common path to save a
module on a system would be
%SystemRoot%\users\
<user>\Documents\WindowsPowerShell\Modules\<moduleName> . If you do not use
the
default paths, you will need to explicitly state the location of your module during
installation. Be sure to create a folder to save your module in, as you may need the
folder to
store multiple assemblies and files for your solution.
Note that technically you do not need to install your module anywhere on the
PSModulePath -
those are simply the default locations that PowerShell will look for
your module. However, it is
considered best practice to do so, unless you have a
good reason for storing your module
somewhere else. For more information, see
Installing a PowerShell Module
and about_PSModulePath.
In addition, any formatting or types files that are referenced by the snap-in cannot be
imported as
part of a binary module. To import the formatting and types files you must
create a module manifest.
See, How to Write a PowerShell Module Manifest.
See Also
Writing a Windows PowerShell Module
How to write a PowerShell module
manifest
Article • 03/06/2023
After you've written your PowerShell module, you can add an optional module manifest
that includes
information about the module. For example, you can describe the author,
specify files in the module
(such as nested modules), run scripts to customize the user's
environment, load type and formatting
files, define system requirements, and limit the
members that the module exports.
For simple modules that contain only a single .psm1 or binary assembly, a module
manifest is
optional. But, the recommendation is to use a module manifest whenever
possible, as they're useful
to help you organize your code and maintain versioning
information. And, a module manifest is
required to export an assembly that is installed
in the
Global Assembly Cache. A module manifest is also required for
modules that
support the Updatable Help feature. Updatable Help uses the HelpInfoUri key in the
module manifest to find the Help information (HelpInfo XML) file that contains the
location of the
updated help files for the module. For more information about
Updatable Help, see
Supporting Updatable Help.
your different modules. For an example of a default module manifest, see the
Sample module manifest.
New-ModuleManifest -Path C:\myModuleName.psd1 -ModuleVersion "2.0" -Author
"YourNameHere"
An alternative is to manually create the module manifest's hash table using the
minimal
information required, the ModuleVersion. You save the file with the same
name as your module
and use the .psd1 file extension. You can then edit the file
and add the appropriate keys and
values.
2. Add any additional elements that you want in the manifest file.
To edit the manifest file, use any text editor you prefer. But, the manifest file is a
script
file that contains code, so you may wish to edit it in a scripting or
development environment,
such as Visual Studio Code. All elements of a manifest
file are optional, except for the
ModuleVersion number.
For descriptions of the keys and values you can include in a module manifest, see
the
Module manifest elements table. For more information, see the
parameter
descriptions in the
New-ModuleManifest cmdlet.
3. To address any scenarios that might not be covered by the base module manifest
elements, you have
the option to add additional code to your module manifest.
For security concerns, PowerShell only runs a small subset of the available
operations in a
module manifest file. Generally, you can use the if statement,
arithmetic and comparison
operators, and the basic PowerShell data types.
4. After you've created your module manifest, you can test it to confirm that any
paths described in
the manifest are correct. To test your module manifest, use
Test-
ModuleManifest.
Test-ModuleManifest myModuleName.psd1
5. Be sure that your module manifest is located in the top level of the directory that
contains your
module.
When you copy your module onto a system and import it, PowerShell uses the
module manifest to
import your module.
6. Optionally, you can directly test your module manifest with a call to
Import-
Module by dot-sourcing the
manifest itself.
Import-Module .\myModuleName.psd1
RootModule
<empty Script module or binary module file associated
Type: String string> with this manifest. Previous versions of PowerShell
called this element the ModuleToProcess.
ModuleVersion
'0.0.1' Version number of this module. If a value isn't
Type: Version specified, New-ModuleManifest uses the default. The
string must be able to convert to the type Version
for example #.#.#.# . Import-Module loads the first
module it finds on the $PSModulePath that
matches the name, and has at least as high a
ModuleVersion, as the MinimumVersion
parameter. To import a specific version, use the
Import-Module cmdlet's RequiredVersion
parameter.
GUID
'<GUID>' ID used to uniquely identify this module. If a value
Type: GUID isn't specified, New-ModuleManifest autogenerates
the value. You can't currently import a module by
GUID.
Author
'<Current Author of this module. If a value isn't specified,
Type: String user>' New-ModuleManifest uses the current user.
CompanyName
'Unknown' Company or vendor of this module. If a value isn't
Type: String specified, New-ModuleManifest uses the default.
Copyright
'(c) Copyright statement for this module. If a value
Type: String <Author>. isn't specified, New-ModuleManifest uses the default
All rights with the current user as the <Author> . To specify an
reserved.' author, use the Author parameter.
Description
<empty Description of the functionality provided by this
Type: String string> module.
PowerShellVersion
<empty Minimum version of the PowerShell engine
Type: Version string> required by this module. Valid values are 1.0, 2.0,
3.0, 4.0, 5.0, 5.1, 6.0, 6.1, 6.2, 7.0 and 7.1.
PowerShellHostName
<empty Name of the PowerShell host required by this
Type: String string> module. This name is provided by PowerShell. To
find the name of a host program, in the program,
type: $host.name .
PowerShellHostVersion
<empty Minimum version of the PowerShell host required
Type: Version string> by this module.
DotNetFrameworkVersion
<empty Minimum version of Microsoft .NET Framework
Type: Version string> required by this module. This prerequisite is valid
for the PowerShell Desktop edition only, such as
Windows PowerShell 5.1, and only applies to .NET
Framework versions lower than 4.5.
CLRVersion
<empty Minimum version of the common language
Type: Version string> runtime (CLR) required by this module. This
prerequisite is valid for the PowerShell Desktop
edition only, such as Windows PowerShell 5.1, and
only applies to .NET Framework versions lower
than 4.5.
ProcessorArchitecture
<empty Processor architecture (None, X86, Amd64)
Type: ProcessorArchitecture string> required by this module. Valid values are x86,
AMD64, Arm, IA64, MSIL, and None (unknown or
unspecified).
RequiredAssemblies
@() Assemblies that must be loaded prior to importing
Type: String[] this module. Specifies the assembly ( .dll ) file
names that the module requires.
Example: RequiredAssemblies =
@("assembly1.dll", "assembly2.dll",
"assembly3.dll")
ScriptsToProcess
@() Script ( .ps1 ) files that are run in the caller's session
Type: String[] state when the module is imported. This could be
the global session state or, for nested modules, the
session state of another module. You can use these
scripts to prepare an environment just as you
might use a log in script.
TypesToProcess
@() Type files ( .ps1xml ) to be loaded when importing
Type: String[] this module.
FormatsToProcess
@() Format files ( .ps1xml ) to be loaded when
Type: String[] importing this module.
NestedModules
@() Modules to import as nested modules of the
Type: Object[] module specified in RootModule
(alias:ModuleToProcess).
FunctionsToExport
@() Specifies the functions to export from this module,
Type: String[] for best performance, do not use wildcards and do
not delete the entry, use an empty array if there
are no functions to export. By default, no functions
are exported. You can use this key to list the
functions that are exported by the module.
CmdletsToExport
@() Specifies the cmdlets to export from this module,
Type: String[] for best performance, do not use wildcards and do
not delete the entry, use an empty array if there
are no cmdlets to export. By default, no cmdlets
are exported. You can use this key to list the
cmdlets that are exported by the module.
VariablesToExport
'*' Specifies the variables that the module exports to
Type: String[] the caller's session state. Wildcard characters are
permitted. By default, all variables ( '*' ) are
exported. You can use this key to restrict the
variables that are exported by the module.
AliasesToExport
@() Specifies the aliases to export from this module,
Type: String[] for best performance, do not use wildcards and do
not delete the entry, use an empty array if there
are no aliases to export. By default, no aliases are
exported. You can use this key to list the aliases
that are exported by the module.
DscResourcesToExport
@() Specifies DSC resources to export from this
Type: String[] module. Wildcards are permitted.
Example: DscResourcesToExport =
@("DscResource1", "DscResource2",
"DscResource3")
Element Default Description
ModuleList
@() Specifies all the modules that are packaged with
Type: Object[] this module. These modules can be entered by
name, using a comma-separated string, or as a
hash table with ModuleName and GUID keys. The
hash table can also have an optional
ModuleVersion key. The ModuleList key is
designed to act as a module inventory. These
modules are not automatically processed.
FileList
@() List of all files packaged with this module. As with
Type: String[] ModuleList, FileList is an inventory list, and isn't
otherwise processed.
PrivateData
@{...} Specifies any private data that needs to be passed
Type: Object to the root module specified by the RootModule
(alias: ModuleToProcess) key. PrivateData is a hash
table that comprises several elements: Tags,
LicenseUri, ProjectURI, IconUri, ReleaseNotes,
Prerelease, RequireLicenseAcceptance, and
ExternalModuleDependencies.
Tags
@() Tags help with module discovery in online galleries.
Type: String[] Example: Tags = "PackageManagement",
"PowerShell", "Manifest"
LicenseUri
<empty A URL to the license for this module.
ProjectUri
<empty A URL to the main website for this project.
IconUri
<empty A URL to an icon representing this module.
ReleaseNotes
<empty Specifies the module's release notes.
PreRelease
<empty This parameter was added in PowerShellGet 1.6.6.
Type: String string> A PreRelease string that identifies the module as a
prerelease version in online galleries.
RequireLicenseAcceptance
$true This parameter was added in PowerShellGet 1.5.
Type: Boolean Flag to indicate whether the module requires
explicit user acceptance for install, update, or save.
ExternalModuleDependencies
@() This parameter was added in PowerShellGet v2. A
Type: String[] list of external modules that this module is
dependent upon.
Example: ExternalModuleDependencies =
@("ExtModule1", "ExtModule2", "ExtModule3")
HelpInfoURI
<empty HelpInfo URI of this module.
DefaultCommandPrefix
<empty Default prefix for commands exported from this
Type: String string> module. Override the default prefix using Import-
Module -Prefix .
PowerShell
@{
# RootModule = ''
ModuleVersion = '0.0.1'
# Supported PSEditions
# CompatiblePSEditions = @()
GUID = 'b632e90c-df3d-4340-9f6c-3b832646bf87'
Author = 'User01'
CompanyName = 'Unknown'
# Description = ''
# PowerShellVersion = ''
# PowerShellHostName = ''
# PowerShellHostVersion = ''
# DotNetFrameworkVersion = ''
# CLRVersion = ''
# ProcessorArchitecture = ''
# RequiredModules = @()
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to
importing this module.
# ScriptsToProcess = @()
# TypesToProcess = @()
# FormatsToProcess = @()
# NestedModules = @()
# Functions to export from this module, for best performance, do not use
wildcards and do not delete the entry, use an empty array if there are no
functions to export.
FunctionsToExport = @()
# Cmdlets to export from this module, for best performance, do not use
wildcards and do not delete the entry, use an empty array if there are no
cmdlets to export.
CmdletsToExport = @()
VariablesToExport = '*'
# Aliases to export from this module, for best performance, do not use
wildcards and do not delete the entry, use an empty array if there are no
aliases to export.
AliasesToExport = @()
# DscResourcesToExport = @()
# ModuleList = @()
# FileList = @()
PrivateData = @{
PSData = @{
# Tags = @()
# LicenseUri = ''
# ProjectUri = ''
# IconUri = ''
# ReleaseNotes = ''
# Prerelease = ''
RequireLicenseAcceptance = $true
# ExternalModuleDependencies = @()
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the
default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
See also
about_Comparison_Operators
about_If
Import-Module
New-ModuleManifest
Test-ModuleManifest
Update-ModuleManifest
After you have created your PowerShell module, you will likely want to install the
module on a
system, so that you or others may use it. Generally speaking, this consists
of copying the module
files (ie, the .psm1, or the binary assembly, the module manifest,
and any other associated files)
onto a directory on that computer. For a very small
project, this may be as simple as copying and
pasting the files with Windows Explorer
onto a single remote computer; however, for larger solutions
you may wish to use a
more sophisticated installation process. Regardless of how you get your module
onto
the system, PowerShell can use a number of techniques that will let users find and use
your
modules. Therefore, the main issue for installation is ensuring that PowerShell will
be able to find
your module. For more information, see
Importing a PowerShell Module.
By default, the PSModulePath environment variable value contains the following system
and user
module directories, but you can add to and edit the value.
$PSHome\Modules ( %Windir%\System32\WindowsPowerShell\v1.0\Modules )
2 Warning
This location is reserved for modules that ship with Windows. Do not install
modules to this
location.
$HOME\Documents\WindowsPowerShell\Modules
( %HOMEDRIVE%%HOMEPATH%\Documents\WindowsPowerShell\Modules )
$Env:ProgramFiles\WindowsPowerShell\Modules
( %ProgramFiles%\WindowsPowerShell\Modules )
To get the value of the PSModulePath environment variable, use either of the
following
commands.
PowerShell
$Env:PSModulePath
[Environment]::GetEnvironmentVariable("PSModulePath")
PowerShell
$p = [Environment]::GetEnvironmentVariable("PSModulePath")
[Environment]::SetEnvironmentVariable("PSModulePath",$p)
) Important
Once you have added the path to PSModulePath, you should broadcast an
environment message
about the change. Broadcasting the change allows
other applications, such as the shell, to pick
up the change. To broadcast the
change, have your product installation code send a
WM_SETTINGCHANGE
message with lParam set to the string "Environment". Be sure to send the
message after your module installation code has updated PSModulePath.
The "base name" of a file is the name without the file name extension. In a well-formed
module, the
name of the directory that contains the module files must match the base
name of at least one file
in the module.
For example, in the sample Fabrikam module, the directory that contains the module
files is named
"Fabrikam" and at least one file has the "Fabrikam" base name. In this
case, both Fabrikam.psd1 and
Fabrikam.dll have the "Fabrikam" base name.
C:\Program Files
Fabrikam Technologies
Fabrikam Manager
Modules
Fabrikam
Additional features, such as the following, do not work unless the module is
imported into the
session. In well-formed modules in the PSModulePath
environment variable, these features work
even when the module is not imported
into the session.
The commands in the module are missing from the Show-Command window in
Windows PowerShell
Integrated Scripting Environment (ISE).
7 Note
The Program Files location is added to the value of the PSModulePath environment
variable by
default in Windows PowerShell 4.0 and later. For earlier versions of
Windows PowerShell, you can
manually create the Program Files location
(%ProgramFiles%\WindowsPowerShell\Modules) and add
this path to your
PSModulePath environment variable as described above.
C:\Program Files
Fabrikam Technologies
Fabrikam Manager
Modules
Fabrikam
To enable the Windows PowerShell module discovery features to find the Fabrikam
module, the Fabrikam
module installer adds the module location to the value of the
PSModulePath environment variable.
PowerShell
$p = [Environment]::GetEnvironmentVariable("PSModulePath")
[Environment]::SetEnvironmentVariable("PSModulePath",$p)
C:\Program Files
Common Files
Modules
Fabrikam
Then, the installer assures the value of the PSModulePath environment variable includes
the path
of the common files modules subdirectory.
PowerShell
$p = [Environment]::GetEnvironmentVariable("PSModulePath")
$q = $p -split ';'
$q += ";$m"
$p = $q -join ';'
[Environment]::SetEnvironmentVariable("PSModulePath", $p)
1. Create a directory for each version of the module. Include the version number in
the directory
name.
2. Create a module manifest for each version of the module. In the value of the
ModuleVersion
key in the manifest, enter the module version number. Save the
manifest file (.psd1) in the
version-specific directory for the module.
3. Add the module root folder path to the value of the PSModulePath environment
variable, as
shown in the following examples.
To import a particular version of the module, the end-user can use the MinimumVersion
or
RequiredVersion parameters of the
Import-Module cmdlet.
For example, if the Fabrikam module is available in versions 8.0 and 9.0, the Fabrikam
module
directory structure might resemble the following.
C:\Program Files
Fabrikam Manager
Fabrikam8
Fabrikam
Fabrikam9
Fabrikam
The installer adds both of the module paths to the PSModulePath environment variable
value.
PowerShell
$p = [Environment]::GetEnvironmentVariable("PSModulePath")
$p += ";C:\Program Files\Fabrikam\Fabrikam8;C:\Program
Files\Fabrikam\Fabrikam9"
[Environment]::SetEnvironmentVariable("PSModulePath",$p)
When these steps are complete, the ListAvailable parameter of the Get-Module
cmdlet
gets both of the Fabrikam modules. To import a particular module, use the
MinimumVersion or
RequiredVersion parameters of the Import-Module
cmdlet.
If both modules are imported into the same session, and the modules contain cmdlets
with the same
names, the cmdlets that are imported last are effective in the session.
When a session contains two commands that have the same name, Windows PowerShell
runs the command
type that takes precedence. When a session contains two commands
that have the same name and the
same type, Windows PowerShell runs the command
that was added to the session most recently. To run a
command that is not run by
default, users can qualify the command name with the module name.
For example, if the session contains a Get-Date function and the Get-Date cmdlet,
Windows
PowerShell runs the function by default. To run the cmdlet, preface the
command with the module
name, such as:
PowerShell
Microsoft.PowerShell.Utility\Get-Date
To prevent name conflicts, module authors can use the DefaultCommandPrefix key in
the module
manifest to specify a noun prefix for all commands exported from the
module.
Users can use the Prefix parameter of the Import-Module cmdlet to use an alternate
prefix. The
value of the Prefix parameter takes precedence over the value of the
DefaultCommandPrefix
key.
separate directory
names with a path for the host platform
Use these static properties to in place of the ; and \ characters when you are
constructing path
strings.
See Also
about_Command_Precedence
The topics in this section describe modules and snap-ins and how to use modules and
snap-ins to make cmdlets available in a Windows PowerShell session.
In This Section
Modules and Snap-ins
Describes the differences between registering cmdlets through
modules and through snap-ins.
See Also
Writing a Windows PowerShell Cmdlet
Modules and Snap-ins
Article • 09/17/2021
We recommend that you use modules as the delivery method for adding cmdlets to a
session for the following reasons:
Modules allow you to add cmdlets by loading the assembly where the cmdlet is
defined. There is no need to implement a snap-in class.
Modules allow you to add other resources, such as variables, functions, scripts,
types and formatting files, and more.
Snap-ins can be used only to add cmdlets and providers to the session.
See Also
Writing a Windows PowerShell Module
This article describes how to import cmdlets to a PowerShell session by using a binary
module.
7 Note
%SystemRoot%\system32\WindowsPowerShell\v1.0\Modules\mymodule
2. Make sure that the PSModulePath environment variable includes the path to your
new module
folder. By default, the system folder is already added to the
PSModulePath environment
variable. To view the PSModulePath , type:
$env:PSModulePath .
4. Add a module manifest file ( .psd1 ) in the module's root folder. PowerShell uses
the module
manifest to import your module. For more information, see How to
Write a PowerShell Module Manifest.
Import-Module [Module_Name]
This procedure can be used to test your cmdlets. It adds all the cmdlets in the
assembly to the
session. For more information about modules, see Writing a
Windows PowerShell Module.
See also
How to Write a PowerShell Module Manifest
Import-Module
Installing Modules
about_PSModulePath
Examples
Writing a Windows PowerShell Snap-in: This example shows how to create a snap-in
that is used to register all the cmdlets and providers in an assembly.
Writing a Custom Windows PowerShell Snap-in: This example shows how to create a
custom snap-in that is used to register a specific set of cmdlets and providers that might
or might not exist in a single assembly.
See Also
System.Management.Automation.PSSnapIn
System.Management.Automation.Custompssnapin
Registering Cmdlets
This example shows how to write a Windows PowerShell snap-in that can be used to
register all the
cmdlets and Windows PowerShell providers in an assembly.
With this type of snap-in, you do not select which cmdlets and providers you want to
register. To
write a snap-in that allows you to select what is registered, see
Writing a
Custom Windows PowerShell Snap-in.
3. Add a public property for the name of the snap-in (required). When naming snap-
ins, do not use
any of the following characters: # , . , , , ( , ) , { , } , [ , ] , & , - , / ,
\ ,
$ , ; , : , " , ' , < , > , | , ? , @ , ` , *
5. Add a public property for the vendor resource of the snap-in (optional).
7. Add a public property for the description resource of the snap-in (optional).
C#
[RunInstaller(true)]
/// <summary>
/// </summary>
public GetProcPSSnapIn01()
: base()
/// <summary>
/// </summary>
get
return "GetProcPSSnapIn01";
/// <summary>
/// </summary>
get
return "Microsoft";
/// <summary>
/// </summary>
get
return "GetProcPSSnapIn01,Microsoft";
/// <summary>
/// </summary>
get
/// <summary>
/// </summary>
get
See Also
How to Register Cmdlets, Providers, and Host Applications
This example shows how to write a Windows PowerShell snap-in that registers specific
cmdlets.
With this type of snap-in, you specify which cmdlets, providers, types, or formats to
register. For
more information about how to write a snap-in that registers all the
cmdlets and providers in an
assembly, see Writing a Windows PowerShell Snap-in.
3. Add a public property for the name of the snap-in (required). When naming snap-
ins, do not use
any of the following characters: # , . , , , ( , ) , { , } , [ , ] , & , - , / ,
\ ,
$ , ; , : , " , ' , < , > , | , ? , @ , ` , *
5. Add a public property for the vendor resource of the snap-in (optional).
In this example, the description is: "This is a custom Windows PowerShell snap-in
that includes
the Test-HelloWorld and Test-CustomSnapinTest cmdlets".
7. Add a public property for the description resource of the snap-in (optional).
8. Specify the cmdlets that belong to the custom snap-in (optional) using the
System.Management.Automation.Runspaces.Cmdletconfigurationentry
class. The
information added here includes the name of the cmdlet, its .NET type, and the
cmdlet
Help file name (the format of the cmdlet Help file name should be
name.dll-help.xml ).
10. Specify the types that belong to the custom snap-in (optional).
11. Specify the formats that belong to the custom snap-in (optional).
Example
This example shows how to write a Custom Windows PowerShell snap-in that can be
used to register the
Test-HelloWorld and Test-CustomSnapinTest cmdlets. Be aware that
in this example, the complete
assembly could contain other cmdlets and providers that
would not be registered by this snap-in.
C#
[RunInstaller(true)]
/// <summary>
/// </summary>
public CustomPSSnapinTest()
: base()
/// <summary>
/// </summary>
get
return "CustomPSSnapInTest";
/// <summary>
/// </summary>
get
return "Microsoft";
/// <summary>
/// </summary>
get
return "CustomPSSnapInTest,Microsoft";
/// <summary>
/// </summary>
get
/// <summary>
/// </summary>
get
/// <summary>
/// Specify the cmdlets that belong to this custom PowerShell snap-in.
/// </summary>
get
if (_cmdlets == null)
_cmdlets.Add(new CmdletConfigurationEntry("test-customsnapintest",
typeof(TestCustomSnapinTest), "TestCmdletHelp.dll-help.xml"));
_cmdlets.Add(new CmdletConfigurationEntry("test-helloworld",
typeof(TestHelloWorld), "HelloWorldHelp.dll-help.xml"));
return _cmdlets;
/// <summary>
/// Specify the providers that belong to this custom PowerShell snap-in.
/// </summary>
get
if (_providers == null)
return _providers;
/// <summary>
/// Specify the types that belong to this custom PowerShell snap-in.
/// </summary>
get
if (_types == null)
return _types;
/// <summary>
/// Specify the formats that belong to this custom PowerShell snap-in.
/// </summary>
get
if (_formats == null)
return _formats;
See Also
How to Register Cmdlets, Providers, and Host Applications
Once you have installed a module on a system, you will likely want to import the
module. Importing
is the process that loads the module into active memory, so that a
user can access that module in
their PowerShell session. In PowerShell 2.0, you can
import a newly-installed PowerShell module with
a call to Import-Module cmdlet. In
PowerShell 3.0, PowerShell is able to implicitly import a module when one of the
functions or
cmdlets in the module is called by a user. Note that both versions assume
that you install your
module in a location where PowerShell is able to find it; for more
information, see
Installing a PowerShell Module. You can use a module manifest
to
restrict what parts of your module are exported, and you can use parameters of the
Import-Module call to restrict what parts are imported.
PowerShell
Import-Module myModule
Assuming that myModule was located in the PSModulePath , PowerShell would load
myModule into active
memory. If myModule was not located on a PSModulePath path,
you could still explicitly tell
PowerShell where to find it:
PowerShell
You can also use the -Verbose parameter to identify what is being exported out of the
module, and
what is being imported into active memory. Both exports and imports
restrict what is exposed to the
user: the difference is who is controlling the visibility.
Essentially, exports are controlled by
code within the module. In contrast, imports are
controlled by the Import-Module call. For more
information, see Restricting Members
That Are Imported, below.
The following actions trigger automatic importing of a module, also known as "module
auto-loading."
To support automatic importing of modules, the Get-Command cmdlet gets all cmdlets
and functions
in all installed modules, even if the module is not imported into the
session. For more information,
see the help topic for the Get-Command
cmdlet.
The Importing Process
When a module is imported, a new session state is created for the module, and a
System.Management.Automation.PSModuleInfo
object is created in memory. A session-
state is created for each module that is imported (this
includes the root module and any
nested modules). The members that are exported from the root
module, including any
members that were exported to the root module by any nested modules, are then
imported into the caller's session state.
The metadata of members that are exported from a module have a ModuleName
property. This property is
populated with the name of the module that exported them.
2 Warning
If the name of an exported member uses an unapproved verb or if the name of the
member uses
restricted characters, a warning is displayed when the
Import-
Module cmdlet is run.
Function: This parameter restricts the functions that are exported. (If you are using
a module
manifest, see the FunctionsToExport key.)
`Cmdlet: This parameter restricts the cmdlets that are exported (If you are using a
module
manifest, see the CmdletsToExport key.)
Variable: This parameter restricts the variables that are exported (If you are using a
module
manifest, see the VariablesToExport key.)
Alias: This parameter restricts the aliases that are exported (If you are using a
module
manifest, see the AliasesToExport key.)
See Also
Writing a Windows PowerShell Module
Windows PowerShell Provider
Quickstart
Article • 09/17/2021
This topic explains how to create a Windows PowerShell provider that has basic
functionality of creating a new drive. For general information about providers, see
Windows PowerShell Provider Overview. For examples of providers with more complete
functionality, see Provider Samples.
When you write a provider, you can specify default drives-drives that are created
automatically when the provider is available. You also define a method to create new
drives that use that provider.
C#
namespace Microsoft.Samples.PowerShell.Providers
using System;
using System.Data;
using System.Data.Odbc;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Provider;
#region AccessDBProvider
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
Implementing NewDrive
The System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* method
is called by the Windows PowerShell engine when a user calls the
Microsoft.PowerShell.Commands.NewPSDriveCommand cmdlet specifying the name of
your provider. The PSDriveInfo parameter is passed by the Windows PowerShell engine,
and the method returns the new drive to the Windows PowerShell engine. This method
must be declared within the class created above.
The method first checks to make sure both the drive object and the drive root that were
passed in exist, returning null if either of them do not. It then uses a constructor of the
internal class AccessDBPSDriveInfo to create a new drive and a connection to the Access
database the drive represents.
C#
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null));
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root) ==
false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive));
return null;
// Create a new drive and create an ODBC connection to the new drive.
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
The following is the AccessDBPSDriveInfo internal class that includes the constructor
used to create a new drive, and contains the state information for the drive.
C#
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
/// <summary>
/// </summary>
Implementing RemoveDrive
The System.Management.Automation.Provider.Drivecmdletprovider.Removedrive*
method is called by the Windows PowerShell engine when a user calls the
Microsoft.PowerShell.Commands.RemovePSDriveCommand cmdlet. The method in this
provider closes the connection to the Access database.
C#
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive));
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
A Windows PowerShell provider allows any data store to be exposed like a file system as
if it were a
mounted drive. For example, the built-in Registry provider allows you to
navigate the registry like
you would navigate the c drive of your computer. A provider
can also override the Item cmdlets
(for example, Get-Item , Set-Item , etc.) such that the
data in your data store can be treated
like files and directories are treated when
navigating a file system. For more information about
providers and drives, and the built-
in providers in Windows PowerShell, see
about_Providers.
When you write a provider, you can specify default drives-drives that are created
automatically when
the provider is available. You also define a method to create new
drives that use that provider.
Type of Providers
There are several types of providers, each of which provides a different level of
functionality. A
provider is implemented as a class that derives from one of the
descendants of the
System.Management.Automation.SessionStateCategory
CmdletProvider class. For information about the different types of providers, see
Provider types.
Provider cmdlets
Providers can implement methods that correspond to cmdlets, creating custom
behaviors for those
cmdlets when used in a drive for that provider. Depending on the
type of provider, different sets of
cmdlets are available. For a complete list of the
cmdlets available for customization in providers,
see Provider cmdlets.
Provider paths
Users navigate provider drives like file systems. Because of this, they expect the syntax
of paths
to correspond to the paths used in file system navigation. When a user runs a
provider cmdlet, they
specify a path to the item to be accessed. The path that is
specified can be interpreted in several
ways. A provider should support one or more of
the following path types.
Drive-qualified paths
A drive-qualified path is a combination of the item name, the container and
subcontainers in which
the item is located, and the Windows PowerShell drive through
which the item is accessed. (Drives
are defined by the provider that is used to access the
data store. This path starts with the drive
name followed by a colon (:). For example:
get-childitem C:
Provider-qualified paths
To allow the Windows PowerShell engine to initialize and uninitialize your provider, the
provider
must support a provider-qualified path. For example, the user can initialize and
uninitialize the
FileSystem provider because it defines the following provider-qualified
path:
FileSystem::\\uncshare\abc\bar .
Provider-direct paths
To allow remote access to your Windows PowerShell provider, it should support a
provider-direct path
to pass directly to the Windows PowerShell provider for the current
location. For example, the
registry Windows PowerShell provider can use
\\server\regkeypath as a provider-direct path.
Provider-internal paths
To allow the provider cmdlet to access data using non-Windows PowerShell application
programming
interfaces (APIs), your Windows PowerShell provider should support a
provider-internal path. This
path is indicated after the "::" in the provider-qualified path.
For example, the provider-internal
path for the filesystem Windows PowerShell provider
is \\uncshare\abc\bar .
Dynamic parameters
Providers can define dynamic parameters that are added to a provider cmdlet when the
user specifies
a certain value for one of the static parameters of the cmdlet. A provider
does this by implementing
one or more dynamic parameter methods. For a list of
cmdlet parameters that can be used to add
dynamic parameter, and the methods used
to implement them, see
Provider cmdlet dynamic parameters.
Provider capabilities
The
System.Management.Automation.Provider.Providercapabilities
enumeration defines
a number of capabilities that providers can support. These include the ability
to use
wildcards, filter items, and support transactions. To specify capabilities for a provider,
add a list of values of the
System.Management.Automation.Provider.Providercapabilities
enumeration, combined with a logical OR operation, as the
System.Management.Automation.Provider.Cmdletproviderattribute.Providercapabilities*
property (the second parameter of the attribute) of the
System.Management.Automation.Provider.Cmdletproviderattribute
attribute for your
provider class. For example, the following attribute specifies that the provider
supports
the
System.Management.Automation.Provider.Providercapabilities
ShouldProcess and
System.Management.Automation.Provider.ProviderCapabilities
Transactions capabilities.
C#
[CmdletProvider(RegistryProvider.ProviderName,
ProviderCapabilities.ShouldProcess | ProviderCapabilities.Transactions)]
The content for the Help file is written using PSMAML XML. This is the same XML
schema that is used
for writing Help content for stand-alone cmdlets. Add the content
for your custom cmdlet Help to the
Help file for your provider under the
CmdletHelpPaths element. The following example shows the
command element for a
single provider cmdlet, and it shows how you specify the name of the
provider cmdlet
that your provider. supports
XML
<CmdletHelpPaths>
<command:command>
<command:details>
<command:name>ProviderCmdletName</command:name>
<command:verb>Verb</command:verb>
<command:noun>Noun</command:noun>
<command:details>
</command:command>
<CmdletHelpPath>
See Also
Windows PowerShell Provider Functionality
Provider Cmdlets
Providers define their basic functionality by changing how the provider cmdlets,
provided by
PowerShell, perform their actions. For example, providers can use the
default functionality of the
Get-Item cmdlet, or they can change how that cmdlet
operates when retrieving items from the data
store. The provider functionality described
in this document includes functionality defined by
overwriting methods from specific
provider base classes and interfaces.
7 Note
Drive-enabled providers
Drive-enabled providers specify the default drives available to the user and allow the
user to add
or remove drives. In most cases, providers are drive-enabled providers
because they require some
default drive to access the data store. However, when writing
your own provider you might or might
not want to allow the user to create and remove
drives.
To create a drive-enabled provider, your provider class must derive from the
System.Management.Automation.Provider.DriveCmdletProvider
class or another class
that derives from that class. The
DriveCmdletProvider class defines the following
methods
for implementing the default drives of the provider and supporting the New-
PSDrive and
Remove-PSDrive cmdlets. In most cases, to support a provider cmdlet you
must overwrite the method
that the PowerShell engine calls to invoke the cmdlet, such
as the NewDrive method for the
New-PSDrive cmdlet, and optionally you can overwrite a
second method, such as
NewDriveDynamicParameters , for adding dynamic parameters to
the cmdlet.
The
InitializeDefaultDrives
method defines the default drives that are available to
the user whenever the provider is used.
The
NewDrive
and
NewDriveDynamicParameters
methods defines how your
provider supports the New-PSDrive provider cmdlet. This cmdlet allows
the user to
create drives to access the data store.
The
RemoveDrive
method defines how your provider supports the Remove-PSDrive
provider cmdlet. This cmdlet allows
the user to remove drives from the data store.
Item-enabled providers
Item-enabled providers allow the user to get, set, or clear the items in the data store. An
"item"
is an element of the data store that the user can access or manage
independently. To create an
item-enabled provider, your provider class must derive from
the
System.Management.Automation.Provider.ItemCmdletProvider
class or another class
that derives from that class.
The
ClearItem
and
ClearItemDynamicParameters
methods define how your
provider supports the Clear-Item provider cmdlet. This cmdlet allows the
user to
remove of the value of an item in the data store.
The
GetItem
and
GetItemDynamicParameters
methods define how your provider
supports the Get-Item provider cmdlet. This cmdlet allows the
user to retrieve data
from the data store.
The
SetItem
and
SetItemDynamicParameters
methods define how your provider
supports the Set-Item provider cmdlet. This cmdlet allows the
user to update the
values of items in the data store.
The
InvokeDefaultAction
and
InvokeDefaultActionDynamicParameters
methods
define how your provider supports the Invoke-Item provider cmdlet. This cmdlet
allows
the user to perform the default action specified by the item.
The
ItemExists
and
ItemExistsDynamicParameters
methods define how your
provider supports the Test-Path provider cmdlet. This cmdlet allows the
user to
determine if all the elements of a path exist.
The
ExpandPath
method allows the user to use wildcards when specifying the
provider path.
The
IsValidPath
is used to determine if a path is syntactically and semantically valid
for the provider.
Container-enabled providers
Container-enabled providers allow the user to manage items that are containers. A
container is a
group of child items under a common parent item. To create a container-
enabled provider, your
provider class must derive from the
System.Management.Automation.Provider.ContainerCmdletProvider
class or another
class that derives from that class.
) Important
The
CopyItem
and
CopyItemDynamicParameters
methods define how your
provider supports the Copy-Item provider cmdlet. This cmdlet allows the
user to
copy an item from one location to another.
The
GetChildItems
and
GetChildItemsDynamicParameters
methods define how
your provider supports the Get-ChildItem provider cmdlet. This cmdlet allows
the
user to retrieve the child items of the parent item.
The
GetChildNames
and
GetChildNamesDynamicParameters
methods define how
your provider supports the Get-ChildItem provider cmdlet if its Name
parameter is
specified.
The
NewItem
and
NewItemDynamicParameters
methods define how your provider
supports the New-Item provider cmdlet. This cmdlet allows the
user to create new
items in the data store.
The
RemoveItem
and
RemoveItemDynamicParameters
methods define how your
provider supports the Remove-Item provider cmdlet. This cmdlet allows
the user to
remove items from the data store.
The
RenameItem
and
RenameItemDynamicParameters
methods define how your
provider supports the Rename-Item provider cmdlet. This cmdlet allows
the user to
rename items in the data store.
The
HasChildItems
method can be used by the provider class to determine
whether an item has child items.
The
ConvertPath
method can be used by the provider class to create a new
provider-specific path from a specified
path.
Navigation-enabled providers
Navigation-enabled providers allow the user to move items in the data store. To create a
navigation-enabled provider, your provider class must derive from the
System.Management.Automation.Provider.NavigationCmdletProvider
class.
method, such
as MoveItemDynamicParameters , for adding dynamic parameters to the
cmdlet.
The
MoveItem
and
MoveItemDynamicParameters
methods define how your
provider supports the Move-Item provider cmdlet. This cmdlet allows the
user to
move an item from one location in the store to another location.
The
MakePath
method defines how your provider supports the Join-Path provider
cmdlet. This cmdlet allows the
user to combine a parent and child path segment to
create a provider-internal path.
The
GetChildName
method extracts the name of the child node of a path.
The
GetParentPath
method extracts the parent part of a path.
The
IsItemContainer
method determines whether the item is a container item. In
this context, a container is a group of
child items under a common parent item.
The
NormalizeRelativePath
method returns a path to an item that's relative to a
specified base path.
Content-enabled providers
Content-enabled providers allow the user to clear, get, or set the content of items in a
data store.
For example, the FileSystem provider allows you to clear, get, and set the
content of files in the
file system. To create a content enabled provider, your provider
class must implement the methods of
the
System.Management.Automation.Provider.IContentCmdletProvider
interface.
second
method, such as ClearContentDynamicParameters , for adding dynamic
parameters to the cmdlet.
The
ClearContent
and
ClearContentDynamicParameters
methods define how your
provider supports the Clear-Content provider cmdlet. This cmdlet allows
the user
to delete the content of an item without deleting the item.
The
GetContentReader
and
GetContentReaderDynamicParameters
methods define
how your provider supports the Get-Content provider cmdlet. This cmdlet allows
the user to retrieve the content of an item. The
GetContentReader method returns
an
System.Management.Automation.Provider.IContentReader
interface that defines
the methods used to read the content.
The
GetContentWriter
and
GetContentWriterDynamicParameters
methods define
how your provider supports the Set-Content provider cmdlet. This cmdlet allows
the user to update the content of an item. The
GetContentWriter method returns
an
System.Management.Automation.Provider.IContentWriter
interface that defines
the methods used to write the content.
Property-enabled providers
Property-enabled providers allow the user to manage the properties of the items in the
data store.
To create a property-enabled provider, your provider class must implement
the methods of the
System.Management.Automation.Provider.IPropertyCmdletProvider
and
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider
interfaces. In most cases, to support a provider cmdlet you must overwrite the method
that the
PowerShell engine calls to invoke the cmdlet, such as the ClearProperty
method for the
Clear-Property cmdlet, and optionally you can overwrite a second
method, such as
ClearPropertyDynamicParameters , for adding dynamic parameters to
the cmdlet.
The
ClearProperty
and
ClearPropertyDynamicParameters
methods define how your
provider supports the Clear-ItemProperty provider cmdlet. This cmdlet
allows the
user to delete the value of a property.
The
GetProperty
and
GetPropertyDynamicParameters
methods define how your
provider supports the Get-ItemProperty provider cmdlet. This cmdlet
allows the
user to retrieve the property of an item.
The
SetProperty
and
SetPropertyDynamicParameters
methods define how your
provider supports the Set-ItemProperty provider cmdlet. This cmdlet
allows the
user to update the properties of an item.
The
CopyProperty
and
CopyPropertyDynamicParameters
methods define how your
provider supports the Copy-ItemProperty provider cmdlet. This cmdlet
allows the
user to copy a property and its value from one location to another.
The
MoveProperty
and
MovePropertyDynamicParameters
methods define how
your provider supports the Move-ItemProperty provider cmdlet. This cmdlet
allows
the user to move a property and its value from one location to another.
The
NewProperty
and
NewPropertyDynamicParameters
methods define how your
provider supports the New-ItemProperty provider cmdlet. This cmdlet
allows the
user to create a new property and set its value.
The
RemoveProperty
and
RemovePropertyDynamicParameters
methods define
how your provider supports the Remove-ItemProperty cmdlet. This cmdlet allows
the
user to delete a property and its value.
The
RenameProperty
and
RenamePropertyDynamicParameters
methods define
how your provider supports the Rename-ItemProperty cmdlet. This cmdlet allows
the
user to change the name of a property.
See also
about_Providers
The cmdlets that the user can run to manage a data store are referred to as provider
cmdlets.
To support these cmdlets, you need to overwrite some of the methods defined
by the base provider classes and interfaces.
Here are the provider cmdlets that can be run by the user:
PSDrive cmdlets
Get-PSDrive
New-PSDrive
This cmdlet allows the user to create PowerShell drives to access the data store.
To
support this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.DriveCmdletProvider class:
Newdrive
NewDriveDynamicParameters
Remove-PSDrive
This cmdlet allows the user to remove PowerShell drives that access the data store.
To
support this cmdlet, overwrite the
System.Management.Automation.Provider.DriveCmdletProvider.Removedrive method.
Item cmdlets
Clear-Item
This cmdlet allows the user to remove the value of an item in the data store.
To support
this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.ItemCmdletProvider class:
Clearitem
ClearItemDynamicParameters
Copy-Item
This cmdlet allows the user to copy an item from one location to another.
To support
this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.ContainerCmdletProvider class:
Copyitem
CopyItemDynamicParameters
Get-Item
This cmdlet allows the user to retrieve data from the data store.
To support this cmdlet,
overwrite the following methods of
System.Management.Automation.Provider.ItemCmdletProvider class:
Getitem
GetItemDynamicParameters
Get-ChildItem
This cmdlet allows the user to retrieve the child items of the parent item.
To support this
cmdlet, overwrite the following methods of
System.Management.Automation.Provider.ContainerCmdletProvider class:
GetChildItems
GetChildItemsDynamicParameters
GetChildNames
GetChildNamesDynamicParameters
Invoke-Item
This cmdlet allows the user to perform the default action specified by the item.
To
support this cmdlet, overwrite the
System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultAction
method.
Move-Item
This cmdlet allows the user to move an item from one location to another location.
To
support this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.Navigationcmdletprovider class:
MoveItem
MoveItemDynamicParameters
New-ItemProperty
This cmdlet allows the user to create a new item in the data store.
Remove-Item
This cmdlet allows the user to remove items from the data store.
To support this cmdlet,
overwrite the following methods of
System.Management.Automation.Provider.ContainerCmdletProvider class:
RemoveItem
RemoveItemDynamicParameters
Rename-Item
This cmdlet allows the user to rename items in the data store.
To support this cmdlet,
overwrite the following methods of
System.Management.Automation.Provider.ContainerCmdletProvider class:
RenameItem
RenameItemDynamicParameters
Set-Item
This cmdlet allows the user to update the values of items in the data store.
To support
this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.ItemCmdletProvider class:
SetItem
SetItemDynamicParameters
Clear-Content
This cmdlet allows the user to delete content from an item without deleting the item.
To
support this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.IContentCmdletProvider interface:
ClearContent
ClearContentDynamicParameters
Get-Content
GetContentReader
GetContentReaderDynamicParameters
Set-Content
GetContentWriter
GetContentWriterDynamicParameters
ClearProperty
ClearPropertyDynamicParameters
Copy-ItemProperty
This cmdlet allows the user to copy a property and its value from one location to
another.
To support this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider interface:
CopyProperty
CopyPropertyDynamicParameters
Get-ItemProperty
GetProperty
GetPropertyDynamicParameters
Move-ItemProperty
This cmdlet allows the user to move a property and its value from one location to
another.
To support this cmdlet, overwrite the following methods of
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider interface:
MoveProperty
MovePropertyDynamicParameters
New-ItemProperty
This cmdlet allows the user to create a new property and set its value.
To support this
cmdlet, overwrite the following methods of
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider interface:
NewProperty
NewPropertyDynamicParameters
Remove-ItemProperty
This cmdlet allows the user to delete a property and its value.
To support this cmdlet,
overwrite the following methods of
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider interface:
RemoveProperty
RemovePropertyDynamicParameters
Rename-ItemProperty
RenameProperty
RenamePropertyDynamicParameters
Set-ItemProperty
SetProperty
SetPropertyDynamicParameters
Location cmdlets
Get-Location
Pop-Location
This cmdlet changes the current location to the location most recently pushed onto the
stack.
You do not need to overwrite any methods to support this cmdlet.
Push-Location
This cmdlet adds the current location to the top of a list of locations (a "stack").
You do
not need to overwrite any methods to support this cmdlet.
Set-Location
Path cmdlets
Join-Path
This cmdlet allows the user to combine a parent and child path segment to create a
provider-internal path.
To support this cmdlet, overwrite the
System.Management.Automation.Provider.NavigationCmdletProvider.MakePath method.
Convert-Path
This cmdlet converts a path from a PowerShell path to a PowerShell provider path.
Split-Path
Resolve-Path
Resolves the wildcard characters in a path, and displays the path contents.
Test-Path
PSProvider cmdlets
Get-PSProvider
This cmdlet returns information about the providers available in the session.
You do not
need to overwrite any methods to support this cmdlet.
Provider cmdlet parameters
Article • 09/17/2021
Provider cmdlets come with a set of static parameters that are available to all providers
that support the cmdlet, as well as dynamic parameters that are added when the user
specifies a certain value for certain static parameters of the provider cmdlet.
Clear-Content cmdlet
You can define how your provider will use the values passed to
the Path parameter of the Clear-Content cmdlet by implementing the
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
method.
Clear-Item cmdlet
You can define how your provider will use the values passed to the
Clear-ItemProperty cmdlet
You can define how your provider will use the values passed
to the Path and Name parameters of the Clear-ItemProperty cmdlet by implementing
the System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
method.
Copy-Item cmdlet
You can define how your provider will use the values passed to the
Get-ChildItems cmdlet
You can define how your provider will use the values passed to
the Path and Recurse parameters of the Get-ChildItem cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems* and
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames*
methods.
Get-Content cmdlet
You can define how your provider will use the values passed to the
Get-Item cmdlet
You can define how your provider will use the values passed to the
Path parameter of the Get-Item cmdlet by implementing the
System.Management.Automation.Provider.Itemcmdletprovider.Getitem* method.
Get-ItemProperty cmdlet
You can define how your provider will use the values passed to
the Path and Name parameters of the Get-ItemProperty cmdlet by implementing the
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty*
method.
Invoke-Item cmdlet
You can define how your provider will use the values passed to the
Path parameter of the Invoke-Item cmdlet by implementing the
System.Management.Automation.Provider.Itemcmdletprovider.Invokedefaultaction*
method.
Move-Item cmdlet
You can define how your provider will use the values passed to the
New-Item cmdlet
You can define how your provider will use the values passed to the
Path , ItemType , and Value parameters of the New-Item cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Newitem* method.
New-ItemProperty cmdlet
You can define how your provider will use the values passed to
the Path , Name , PropertyType , and Value parameters of the New-ItemProperty cmdlet
by implementing the Microsoft.PowerShell.Commands.Registryprovider.Newproperty*
method.
Remove-Item
You can define how your provider will use the values passed to the Path
and Recurse parameters of the Remove-Item cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
method.
Remove-ItemProperty
You can define how your provider will use the values passed to the
Rename-Item cmdlet
You can define how your provider will use the values passed to the
System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
method.
Rename-ItemProperty
You can define how your provider will use the values passed to the
Path , NewName , and Name parameters of the Rename-ItemProperty cmdlet by
implementing the
System.Management.Automation.Provider.Idynamicpropertycmdletprovider.Renamepro
perty* method.
Set-Content cmdlet
You can define how your provider will use the values passed to the
Path parameter of the Set-Content cmdlet by implementing the
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*
method.
Set-Item cmdlet
You can define how your provider will use the values passed to the
Set-ItemProperty cmdlet
You can define how your provider will use the values passed to
the Path and Value parameters of the Set-Item cmdlet by implementing the
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
method.
Test-Path cmdlet
You can define how your provider will use the values passed to the
In addition, you cannot specify the characteristics of these parameters, such as whether
they are optional or required, nor can you give these parameters an alias or specify any
of the validation attributes. In contrast, you can specify parameter characteristics in
stand-alone cmdlets by using attributes such as the Parameters attribute.
See Also
Provider Cmdlet Dynamic Parameters
Providers can define dynamic parameters that are added to a provider cmdlet when the
user specifies a certain value for one of the static parameters of the cmdlet. For example,
a provider can add different dynamic parameters based on what path the user specifies
when they call the Get-Item or Set-Item provider cmdlets.
C#
Unlike the static parameters of provider cmdlets, you can specify the characteristics of
these parameters in the same way that parameters are defined in stand-alone cmdlets.
Here is an example of a dynamic parameter class taken from the Certificate provider:
C#
/// <summary>
/// </summary>
[Parameter()]
get
return codeSigningCert;
set
codeSigningCert = value;
Dynamic Parameters
Here is a list of the static parameters that can be used to add dynamic parameters.
Clear-Content cmdlet
You can define dynamic parameters that are triggered by the
Path parameter of the Clear-Clear cmdlet by implementing the
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontentdynamic
parameters* method.
Clear-Item cmdlet
You can define dynamic parameters that are triggered by the Path
Clear-ItemProperty cmdlet
You can define dynamic parameters that are triggered by
the Path parameter of the Clear-ItemProperty cmdlet by implementing the
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearpropertydynam
icparameters* method.
Copy-Item cmdlet
You can define dynamic parameters that are triggered by the Path ,
Get-ChildItems cmdlet
You can define dynamic parameters that are triggered by the
Path and Recurse parameters of the Get-ChildItem cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditemsdyna
micparameters* and
System.Management.Automation.Provider.Containercmdletprovider.Getchildnamesdyna
micparameters* methods.
Get-Content cmdlet
You can define dynamic parameters that are triggered by the Path
parameter of the Get-Content cmdlet by implementing the
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreaderdyn
amicparameters* method.
Get-Item cmdlet
You can define dynamic parameters that are triggered by the Path
Get-ItemProperty cmdlet
You can define dynamic parameters that are triggered by the
Path and Name parameters of the Get-ItemProperty cmdlet by implementing the
System.Management.Automation.Provider.Ipropertycmdletprovider.Getpropertydynamic
parameters* method.
Invoke-Item cmdlet
You can define dynamic parameters that are triggered by the Path
Move-Item cmdlet
You can define dynamic parameters that are triggered by the Path
New-Item cmdlet
You can define dynamic parameters that are triggered by the Path ,
ItemType , and Value parameters of the New-Item cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Newitemdynamicpa
rameters* method.
New-ItemProperty cmdlet
You can define dynamic parameters that are triggered by the
New-PSDrive cmdlet
You can define dynamic parameters that are triggered by the
Remove-Item
You can define dynamic parameters that are triggered by the Path and
Recurse parameters of the Remove-Item cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Removeitemdynami
cparameters* method.
Remove-ItemProperty
You can define dynamic parameters that are triggered by the Path
Rename-Item cmdlet
You can define dynamic parameters that are triggered by the Path
and NewName parameters of the Rename-Item cmdlet by implementing the
System.Management.Automation.Provider.Containercmdletprovider.Renameitemdynami
cparameters* method.
Rename-ItemProperty
You can define dynamic parameters that are triggered by the Path ,
Set-Content cmdlet
You can define dynamic parameters that are triggered by the Path
Set-Item cmdlet
You can define dynamic parameters that are triggered by the Path and
Value parameters of the Set-Item cmdlet by implementing the
System.Management.Automation.Provider.Itemcmdletprovider.Setitemdynamicparamete
rs* method.
Set-ItemProperty cmdlet
You can define dynamic parameters that are triggered by the
Test-Path cmdlet
You can define dynamic parameters that are triggered by the Path
See Also
Writing a Windows PowerShell Provider
Writing an item provider
Article • 09/17/2021
This topic describes how to implement the methods of a Windows PowerShell provider
that access and
manipulate items in the data store. To be able to access items, a
provider must derive from the
System.Management.Automation.Provider.Itemcmdletprovider
class.
The provider in the examples in this topic uses an Access database as its data store.
There are
several helper methods and classes that are used to interact with the
database. For the complete
sample that includes the helper methods, see
AccessDBProviderSample03
7 Note
C#
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
Implementing GetItem
The
System.Management.Automation.Provider.Itemcmdletprovider.Getitem*
is called by
the PowerShell engine when a user calls the
Microsoft.PowerShell.Commands.GetItemCommand
cmdlet on your provider. The
method returns the item at the specified path. In the Access database
example, the
method checks whether the item is the drive itself, a table in the database, or a row
in
the database. The method sends the item to the PowerShell engine by calling the
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*
method.
C#
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
Implementing SetItem
The
System.Management.Automation.Provider.Itemcmdletprovider.Setitem*
method is
called by the PowerShell engine calls when a user calls the
Microsoft.PowerShell.Commands.SetItemCommand
cmdlet. It sets the value of the item
at the specified path.
In the Access database example, it makes sense to set the value of an item only if that
item is a
row, so the method throws
NotSupportedException when the
item is not a row.
C#
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
Implementing ItemExists
The
System.Management.Automation.Provider.Itemcmdletprovider.Itemexists*
method
is called by the PowerShell engine when a user calls the
Microsoft.PowerShell.Commands.TestPathCommand
cmdlet. The method determines
whether there is an item at the specified path. If the item does
exist, the method passes
it back to the PowerShell engine by calling
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*.
C#
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
Implementing IsValidPath
The
System.Management.Automation.Provider.Itemcmdletprovider.Isvalidpath*
method
checks whether the specified path is syntactically valid for the current provider. It does
not check whether an item exists at the path.
C#
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
Next steps
A typical real-world provider is capable of supporting items that contain other items,
and of moving
items from one path to another within the drive. For an example of a
provider that supports
containers, see Writing a container provider. For an example of
a
provider that supports moving items, see
Writing a navigation provider.
See Also
Writing a container provider
This topic describes how to implement the methods of a Windows PowerShell provider
that support
items that contain other items, such as folders in the file system provider.
To be able to support
containers, a provider must derive from the
System.Management.Automation.Provider.Containercmdletprovider
class.
The provider in the examples in this topic uses an Access database as its data store.
There are
several helper methods and classes that are used to interact with the
database. For the complete
sample that includes the helper methods, see
AccessDBProviderSample04.
7 Note
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
Implementing GetChildItems
The PowerShell engine calls the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method when a user calls the
Microsoft.PowerShell.Commands.GetChildItemCommand
cmdlet. This method gets the items that are the children of the item at the specified
path.
C#
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
Implementing GetChildNames
The
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames*
method is similar to the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method, except that it returns only the name property of the items, and not the items
themselves.
C#
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
Implementing NewItem
The
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
method creates a new item of the specified type at the specified path. The PowerShell
engine calls
this method when a user calls the
Microsoft.PowerShell.Commands.NewItemCommand
cmdlet.
In this example, the method implements logic to determine that the path and type
match. That is,
only a table can be created directly under the drive (the database), and
only a row can be created
under a table. If the specified path and item type don't match
in this way, the method throws an
exception.
C#
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// is specified, then a row can be created under it. For the sake
of
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
if (!TableNameIsValid(newTableName))
return;
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
Implementing CopyItem
The
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
copies the specified item to the specified path. The PowerShell engine calls this method
when a user
calls the
Microsoft.PowerShell.Commands.CopyItemCommand
cmdlet. This
method can also be recursive, copying all of the items children in addition to the item
itself.
Similarly to the
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
method,
this method performs logic to make sure that the specified item is of the correct type for
the path to which it is being copied. For example, if the destination path is a table, the
item to
be copied must be a row.
C#
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
if (!Force && GetTable(copyTableName) != null)
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
Implementing RemoveItem
The
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
method removes the item at the specified path. The PowerShell engine calls this method
when a user
calls the
Microsoft.PowerShell.Commands.RemoveItemCommand
cmdlet.
C#
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
Next steps
A typical real-world provider is capable of moving items from one path to another
within the drive.
For an example of a provider that supports moving items, see
Writing a
navigation provider.
See Also
Writing a navigation provider
This topic describes how to implement the methods of a Windows PowerShell provider
that support
nested containers (multi-level data stores), moving items, and relative
paths. A navigation provider
must derive from the
System.Management.Automation.Provider.Navigationcmdletprovider
class.
The provider in the examples in this topic uses an Access database as its data store.
There are
several helper methods and classes that are used to interact with the
database. For the complete
sample that includes the helper methods, see
AccessDBProviderSample05.
For more information about Windows PowerShell providers, see Windows PowerShell
Provider Overview.
7 Note
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
Implementing IsItemContainer
The
System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontainer*
method checks whether the item at the specified path is a container.
C#
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
return true;
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
Implementing GetChildName
The System.Management.Automation.Provider.Navigationcmdletprovider.Getchildname*
method gets the name property of the child item at the specified path. If the item at the
specified path is not a child of a container, then this method should return the path.
C#
if (PathIsDrive(path))
return path;
string tableName;
int rowNumber;
if (type == PathType.Table)
return tableName;
return rowNumber.ToString(CultureInfo.CurrentCulture);
else
ThrowTerminatingInvalidPathException(path);
return null;
Implementing GetParentPath
The
System.Management.Automation.Provider.Navigationcmdletprovider.Getparentpath*
method gets the path of the parent of the item at the specified path. If the item at the
specified path is the root of the data store (so it has no parent), then this method should
return the root path.
C#
if (!String.IsNullOrEmpty(root))
if (!path.Contains(root))
return null;
Implementing MakePath
The System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
method joins a specified parent path and a specified child path to create a provider-
internal path (for information about path types that providers can support, see Windows
PowerShell Provider Overview. The PowerShell engine calls this method when a user
calls the Microsoft.PowerShell.Commands.JoinPathCommand cmdlet.
C#
string result;
normalParent = RemoveDriveFromPath(normalParent);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
result = String.Empty;
result = normalChild;
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result = normalParent;
else
} // else if (!String...
else
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
else
result = normalParent;
if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result += normalChild.Substring(1);
else
result += normalChild;
} // else
return result;
Implementing NormalizeRelativePath
The
System.Management.Automation.Provider.Navigationcmdletprovider.Normalizerelativep
ath* method takes path and basepath parameters, and returns a normalized path that is
equivalent to the path parameter and relative to the basepath parameter.
C#
string basepath)
normalPath = RemoveDriveFromPath(normalPath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
return normalPath;
else
if (!normalPath.Contains(normalBasePath))
return null;
return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
Implementing MoveItem
The System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*
method moves an item from the specified path to the specified destination path. The
PowerShell engine calls this method when a user calls the
Microsoft.PowerShell.Commands.MoveItemCommand cmdlet.
C#
out destRowNumber);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (destType == PathType.Invalid)
ThrowTerminatingInvalidPathException(destination);
if (type == PathType.Table)
ErrorCategory.InvalidArgument, path));
throw e;
else
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (dda == null)
return;
if (destType == PathType.Table)
destRow.ItemArray = row.ItemArray;
else
destRow.ItemArray = row.ItemArray;
if (ShouldProcess(path, "MoveItem"))
dda.Update(dds, destTableName);
See Also
Writing a container provider
Windows PowerShell Provider Overview
Provider Samples
Article • 09/17/2021
This section includes samples of providers that access a Microsoft Access database.
These samples include provider classes that derive from all the base provider classes.
In This Section
This section includes the following topics:
AccessDBProviderSample01 Sample
This sample shows how to declare the provider
class that derives directly from the
System.Management.Automation.Provider.Cmdletprovider class. It is included here only
for completeness.
AccessDBProviderSample02
This sample shows how to overwrite the
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* and
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* methods
to support calls to the New-PSDrive and Remove-PSDrive cmdlets. The provider class in
this sample derives from the
System.Management.Automation.Provider.Drivecmdletprovider class.
AccessDBProviderSample03
This sample shows how to overwrite the
System.Management.Automation.Provider.Itemcmdletprovider.Getitem* and
System.Management.Automation.Provider.Itemcmdletprovider.Setitem* methods to
support calls to the Get-Item and Set-Item cmdlets. The provider class in this sample
derives from the System.Management.Automation.Provider.Itemcmdletprovider class.
AccessDBProviderSample04
This sample shows how to overwrite container methods to
support calls to the Copy-Item , Get-ChildItem , New-Item , and Remove-Item cmdlets.
These methods should be implemented when the data store contains items that are
containers. A container is a group of child items under a common parent item. The
provider class in this sample derives from the
System.Management.Automation.Provider.Containercmdletprovider class.
AccessDBProviderSample05
This sample shows how to overwrite container methods to
support calls to the Move-Item and Join-Path cmdlets. These methods should be
implemented when the user needs to move items within a container and if the data
store contains nested containers. The provider class in this sample derives from the
System.Management.Automation.Provider.Navigationcmdletprovider class.
AccessDBProviderSample06
This sample shows how to overwrite content methods to
support calls to the Clear-Content , Get-Content , and Set-Content cmdlets. These
methods should be implemented when the user needs to manage the content of the
items in the data store. The provider class in this sample derives from the
System.Management.Automation.Provider.Navigationcmdletprovider class, and it
implements the System.Management.Automation.Provider.Icontentcmdletprovider
interface.
See Also
Writing a Windows PowerShell Provider
AccessDBProviderSample01
Article • 09/17/2021
This sample shows how to declare a provider class that derives directly from the
System.Management.Automation.Provider.Cmdletprovider
class. It is included here only
for completeness.
Demonstrates
) Important
Your provider class will most likely derive from one of the following classes and
possibly
implement other provider interfaces:
For more information about choosing which provider class to derive from based on
provider
features, see Designing Your Windows PowerShell Provider.
Example
This sample shows how to define a provider class and how to declare the
CmdletProvider attribute.
C#
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
#endregion AccessDBProvider
See Also
System.Management.Automation.Provider.Itemcmdletprovider
System.Management.Automation.Provider.Containercmdletprovider
System.Management.Automation.Provider.Navigationcmdletprovider
Demonstrates
) Important
Your provider class will most likely derive from one of the following classes and
possibly
implement other provider interfaces:
For more information about choosing which provider class to derive from based on
provider
features, see Designing Your Windows PowerShell Provider.
Overwriting the
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive*
method
to support creating new drives. (This sample does not show how to add dynamic
parameters to
the New-PSDrive cmdlet.)
Overwriting the
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive*
method to support removing existing drives.
Example
This sample shows how to overwrite the
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive*
and
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive*
methods.
For this sample provider, when a drive is created its connection information is stored in
an AccessDBPsDriveInfo object.
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
} // AccessDBProvider
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
See Also
System.Management.Automation.Provider.Itemcmdletprovider
System.Management.Automation.Provider.Containercmdletprovider
System.Management.Automation.Provider.Navigationcmdletprovider
Demonstrates
) Important
Your provider class will most likely derive from one of the following classes and
possibly
implement other provider interfaces:
System.Management.Automation.Provider.Itemcmdletprovider class.
System.Management.Automation.Provider.Containercmdletprovider class.
See AccessDBProviderSample04.
System.Management.Automation.Provider.Navigationcmdletprovider class.
See AccessDBProviderSample05.
For more information about choosing which provider class to derive from based on
provider
features, see Designing Your Windows PowerShell Provider.
Example
This sample shows how to overwrite the methods needed to get and set items in a
Microsoft Access
data base.
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Collections.ObjectModel;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Chunks the path and returns the table name and the row number
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
/// <returns>Table information.</returns>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
return null;
try
if (connection.State != ConnectionState.Open)
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
// data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // SafeConvertRowNumber
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
See Also
System.Management.Automation.Provider.Itemcmdletprovider
System.Management.Automation.Provider.Containercmdletprovider
System.Management.Automation.Provider.Navigationcmdletprovider
Designing Your Windows PowerShell Provider
AccessDBProviderSample04
Article • 09/17/2021
This sample shows how to overwrite container methods to support calls to the Copy-
Item ,
Get-ChildItem , New-Item , and Remove-Item cmdlets. These methods should be
Demonstrates
) Important
Example
This sample shows how to overwrite the methods needed to copy, create, and remove
items, as well as
methods for getting the child items of a parent item.
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
/// <remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// </param>
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
/// <summary>
/// </summary>
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (PathIsDrive(path))
return true;
} // HasChildItems
/// <summary>
/// </summary>
///
/// </param>
///
/// Type for the object to create. "Table" for creating a new table
and
/// </param>
///
/// Object for creating new instance of a type at the specified path.
For
/// a "Row" the object must be of type string which will contain
comma
/// </param>
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// is specified, then a row can be created under it. For the sake
of
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
if (!TableNameIsValid(newTableName))
return;
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
} // NewItem
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// </param>
///
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
if (!Force && GetTable(copyTableName) != null)
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
/// <summary>
/// </summary>
///
/// </param>
///
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
} // RemoveItem
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Chunks the path and returns the table name and the row number
/// </summary>
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
return;
try
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
cmd.ExecuteScalar();
ErrorCategory.InvalidOperation, null)
);
} // RemoveTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
return null;
try
// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";
// columnds
da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;
sql += ")";
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;
if (connection.State != ConnectionState.Open)
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // SafeConvertRowNumber
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
/// <summary>
/// </summary>
int big = 0;
int id = 0;
object o = row["ID"];
if (o.GetType().Name.Equals("Int16"))
id = (int)(short)o;
else
id = (int)o;
big = id;
big++;
return big;
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
See Also
System.Management.Automation.Provider.Itemcmdletprovider
System.Management.Automation.Provider.Containercmdletprovider
System.Management.Automation.Provider.Navigationcmdletprovider
This sample shows how to overwrite container methods to support calls to the Move-
Item and
Join-Path cmdlets. These methods should be implemented when the user
Demonstrates
) Important
Your provider class will most likely derive from one of the following classes and
possibly
implement other provider interfaces:
For more information about choosing which provider class to derive from based on
provider
features, see Designing Your Windows PowerShell Provider.
Overwriting the
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*
method to change the behavior of the Move-Item cmdlet, allowing the user to
move items from one
location to another. (This sample does not show how to add
dynamic parameters to the Move-Item
cmdlet.)
Overwriting the
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
method to change the behavior of the Join-Path cmdlet.
Overwriting the
System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontain
er*
method.
Overwriting the
System.Management.Automation.Provider.Navigationcmdletprovider.Getchildnam
e*
method.
Overwriting the
System.Management.Automation.Provider.Navigationcmdletprovider.Getparentpat
h*
method.
Overwriting the
System.Management.Automation.Provider.Navigationcmdletprovider.Normalizerel
ativepath*
method.
Example
This sample shows how to overwrite the methods needed to move items in a Microsoft
Access data base.
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// </param>
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
/// <summary>
/// </summary>
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (PathIsDrive(path))
return true;
} // HasChildItems
/// <summary>
/// </summary>
///
/// </param>
///
/// Type for the object to create. "Table" for creating a new table
and
/// </param>
///
/// Object for creating new instance of a type at the specified path.
For
/// a "Row" the object must be of type string which will contain
comma
/// </param>
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// is specified, then a row can be created under it. For the sake
of
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
} // NewItem
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// </param>
///
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
if (!Force && GetTable(copyTableName) != null)
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
/// <summary>
/// </summary>
///
/// </param>
///
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
} // RemoveItem
#region Navigation
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
return true;
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
} // IsItemContainer
/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// </param>
///
/// <returns>
/// </returns>
if (PathIsDrive(path))
return path;
string tableName;
int rowNumber;
if (type == PathType.Table)
return tableName;
return rowNumber.ToString(CultureInfo.CurrentCulture);
else
ThrowTerminatingInvalidPathException(path);
return null;
/// <summary>
/// Removes the child segment of the path and returns the remaining
/// </summary>
///
/// </param>
///
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// </param>
///
/// <returns></returns>
if (!String.IsNullOrEmpty(root))
if (!path.Contains(root))
return null;
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// </returns>
string result;
normalParent = RemoveDriveFromPath(normalParent);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
result = String.Empty;
result = normalChild;
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result = normalParent;
else
} // else if (!String...
else
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
else
result = normalParent;
if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result += normalChild.Substring(1);
else
result += normalChild;
} // else
return result;
} // MakePath
/// <summary>
/// Normalizes the path that was passed in and returns the normalized
/// </summary>
///
///
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>
string basepath)
normalPath = RemoveDriveFromPath(normalPath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
return normalPath;
else
if (!normalPath.Contains(normalBasePath))
return null;
return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
/// <summary>
/// Moves the item specified by the path to the specified destination
/// </summary>
///
/// </param>
///
/// </param>
out destRowNumber);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (destType == PathType.Invalid)
ThrowTerminatingInvalidPathException(destination);
if (type == PathType.Table)
ErrorCategory.InvalidArgument, path));
throw e;
else
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (dda == null)
return;
if (destType == PathType.Table)
destRow.ItemArray = row.ItemArray;
else
destRow.ItemArray = row.ItemArray;
if (ShouldProcess(path, "MoveItem"))
dda.Update(dds, destTableName);
#endregion Navigation
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
string root;
if (this.PSDriveInfo == null)
root = String.Empty;
else
root = this.PSDriveInfo.Root;
if (result == null)
result = String.Empty;
if (result.Contains(root))
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
return result;
/// <summary>
/// Chunks the path and returns the table name and the row number
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
/// <returns>Table information.</returns>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
return;
try
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
cmd.ExecuteScalar();
ErrorCategory.InvalidOperation, null)
);
} // RemoveTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
return null;
try
// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";
// columnds
da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;
sql += ")";
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;
if (connection.State != ConnectionState.Open)
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
// data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // SafeConvertRowNumber
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
/// <summary>
/// </summary>
int big = 0;
int id = (int)row["ID"];
big = id;
big++;
return big;
} // AccessDBProvider
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
See Also
System.Management.Automation.Provider.Itemcmdletprovider
System.Management.Automation.Provider.Containercmdletprovider
System.Management.Automation.Provider.Navigationcmdletprovider
This sample shows how to overwrite content methods to support calls to the Clear-
Content ,
Get-Content , and Set-Content cmdlets. These methods should be
Demonstrates
) Important
Your provider class will most likely derive from one of the following classes and
possibly
implement other provider interfaces:
For more information about choosing which provider class to derive from based on
provider
features, see Designing Your Windows PowerShell Provider.
Example
This sample shows how to overwrite the methods needed to clear, get, and set the
content of items in
a Microsoft Access data base.
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// </param>
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
/// <summary>
/// </summary>
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (PathIsDrive(path))
return true;
} // HasChildItems
/// <summary>
/// </summary>
///
/// </param>
///
/// Type for the object to create. "Table" for creating a new table
and
/// </param>
///
/// a "Row" the object must be of type string which will contain
comma
/// </param>
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
{
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
} // NewItem
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// </param>
///
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
/// <summary>
/// </summary>
///
/// </param>
///
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
} // RemoveItem
#region Navigation
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
return true;
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
} // IsItemContainer
/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// </param>
///
/// <returns>
/// </returns>
if (PathIsDrive(path))
return path;
string tableName;
int rowNumber;
if (type == PathType.Table)
return tableName;
return rowNumber.ToString(CultureInfo.CurrentCulture);
else
ThrowTerminatingInvalidPathException(path);
return null;
/// <summary>
/// Removes the child segment of the path and returns the remaining
/// </summary>
///
/// </param>
///
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// </param>
///
/// <returns></returns>
if (!String.IsNullOrEmpty(root))
if (!path.Contains(root))
return null;
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// </returns>
string result;
normalParent = RemoveDriveFromPath(normalParent);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
result = String.Empty;
result = normalChild;
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result = normalParent;
else
} // else if (!String...
else
if (!normalParent.Equals(String.Empty,
StringComparison.OrdinalIgnoreCase) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
else
result = normalParent;
if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result += normalChild.Substring(1);
else
result += normalChild;
} // else
return result;
} // MakePath
/// <summary>
/// Normalizes the path that was passed in and returns the
normalized
/// </summary>
///
/// </param>
///
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>
string
basepath)
normalPath = RemoveDriveFromPath(normalPath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
return normalPath;
else
if (!normalPath.Contains(normalBasePath))
return null;
return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
out destRowNumber);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (destType == PathType.Invalid)
ThrowTerminatingInvalidPathException(destination);
if (type == PathType.Table)
ErrorCategory.InvalidArgument, path));
throw e;
else
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (dda == null)
return;
if (destType == PathType.Table)
destRow.ItemArray = row.ItemArray;
else
destRow.ItemArray = row.ItemArray;
if (ShouldProcess(path, "MoveItem"))
dda.Update(dds, destTableName);
#endregion Navigation
/// <summary>
/// </summary>
/// <returns>
/// </returns>
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
// separator character removed, split by the path separator.
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
string root;
if (this.PSDriveInfo == null)
root = String.Empty;
else
root = this.PSDriveInfo.Root;
if (result == null)
result = String.Empty;
if (result.Contains(root))
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
return result;
/// <summary>
/// Chunks the path and returns the table name and the row number
/// </summary>
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
{
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
{
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
return;
try
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
cmd.ExecuteScalar();
ErrorCategory.InvalidOperation, null)
);
} // RemoveTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
return null;
try
// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";
// columnds
ds.Locale = CultureInfo.InvariantCulture;
da.FillSchema(ds, SchemaType.Source);
sql += ")";
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
// data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // 1
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
/// <summary>
/// </summary>
int big = 0;
int id = (int)row["ID"];
big = id;
big++;
return big;
/// <summary>
/// </summary>
string tableName;
int rowNumber;
if (type != PathType.Table)
WriteError(new ErrorRecord(
"NotValidRow", ErrorCategory.InvalidArgument,
path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "ClearContent"))
da.Update(ds, tableName);
} // ClearContent
/// <summary>
/// </summary>
/// <returns></returns>
return null;
/// <summary>
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
} // GetContentReader
/// <summary>
/// </summary>
/// <returns></returns>
return null;
/// <summary>
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
/// <summary>
/// </summary>
/// <returns></returns>
return null;
} // AccessDBProvider
#endregion AccessDBProvider
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Database,
/// <summary>
/// </summary>
Table,
/// <summary>
/// </summary>
Row,
/// <summary>
/// </summary>
Invalid
};
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
#region AccessDBContentReader
/// <summary>
/// </summary>
this.path = path;
this.provider = provider;
/// <summary>
/// </summary>
/// return.</param>
// offset
string tableName;
int rowNumber;
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
return null;
int rowsRead = 0;
results.Add(rows[(int)currentOffset].Data);
rowsRead++;
currentOffset++;
return results;
} // Read
/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
if (type == PathType.Table)
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
throw new
ArgumentException(
);
if (origin == System.IO.SeekOrigin.Begin)
currentOffset = offset - 1;
else
currentOffset += offset;
} // if (type...
else
currentOffset = 0;
} // Seek
/// <summary>
/// </summary>
Dispose();
} // Close
/// <summary>
/// </summary>
Seek(0, System.IO.SeekOrigin.Begin);
GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentReader
#endregion AccessDBContentReader
#region AccessDBContentWriter
/// <summary>
/// </summary>
this.path = path;
this.provider = provider;
/// <summary>
/// </summary>
/// </param>
///
if (content == null)
return null;
// the end
string tableName;
int rowNumber;
if (type == PathType.Table)
OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
if (da == null)
return null;
if (!String.IsNullOrEmpty(colValues[i]))
row[i] = colValues[i];
//table.Rows.InsertAt(row, rowNumber);
table.Rows.Add(row);
da.Update(ds, tableName);
else
return null;
} // Write
/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
throw new
ArgumentException(
);
if (origin == System.IO.SeekOrigin.Begin)
currentOffset = offset - 1;
else
currentOffset += offset;
} // Seek
/// <summary>
/// </summary>
Dispose();
} // Close
/// <summary>
/// </summary>
Seek(0, System.IO.SeekOrigin.Begin);
GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentWriter
#endregion AccessDBContentWriter
} // namespace Microsoft.Samples.PowerShell.Providers
See Also
System.Management.Automation.Provider.Itemcmdletprovider
System.Management.Automation.Provider.Containercmdletprovider
System.Management.Automation.Provider.Navigationcmdletprovider
AddCommand
You use the
System.Management.Automation.PowerShell.AddCommand
method to add
commands to the pipeline. For example, suppose you want to get the list of running
processes on the machine. The way to run this command is as follows.
1. Create a
System.Management.Automation.PowerShell
object.
C#
PowerShell ps = PowerShell.Create();
C#
ps.AddCommand("Get-Process");
C#
ps.Invoke();
If you call the AddCommand method more than once before you call the
System.Management.Automation.PowerShell.Invoke
method, the result of the first
command is piped to the second, and so on. If you do not want to
pipe the result of a
previous command to a command, add it by calling the
System.Management.Automation.PowerShell.AddStatement
instead.
AddParameter
The previous example executes a single command without any parameters. You can add
parameters to the
command by using the
System.Management.Automation.PSCommand.AddParameter
method. For example, the
following code gets a list of all of the processes that are named
PowerShell running on
the machine.
C#
PowerShell.Create().AddCommand("Get-Process")
.AddParameter("Name", "PowerShell")
.Invoke();
You can add additional parameters by calling the AddParameter method repeatedly.
C#
PowerShell.Create().AddCommand("Get-ChildItem")
.AddParameter("Path", @"c:\Windows")
.AddParameter("Filter", "*.exe")
.Invoke();
You can also add a dictionary of parameter names and values by calling the
System.Management.Automation.PowerShell.AddParameters
method.
C#
parameters.Add("Path", @"c:\Windows");
parameters.Add("Filter", "*.exe");
PowerShell.Create().AddCommand("Get-Process")
.AddParameters(parameters)
.Invoke()
AddStatement
You can simulate batching by using the
System.Management.Automation.PowerShell.AddStatement
method, which adds an
additional statement to the end of the pipeline. The following code gets a
list of running
processes with the name PowerShell , and then gets the list of running services.
C#
PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-Process").AddParameter("Name", "PowerShell");
ps.AddStatement().AddCommand("Get-Service");
ps.Invoke();
AddScript
You can run an existing script by calling the
System.Management.Automation.PowerShell.AddScript
method. The following example
adds a script to the pipeline and runs it. This example assumes there
is already a script
named MyScript.ps1 in a folder named D:\PSScripts .
C#
PowerShell ps = PowerShell.Create();
ps.AddScript("D:\PSScripts\MyScript.ps1").Invoke();
There is also a version of the AddScript method that takes a boolean parameter named
useLocalScope . If this parameter is set to true , then the script is run in the local scope.
The
following code will run the script in the local scope.
C#
PowerShell ps = PowerShell.Create();
ps.AddScript(@"D:\PSScripts\MyScript.ps1", true).Invoke();
C#
Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Command");
ps.Invoke();
rs.Close();
Using a runspace that loads only the commands that you specify provides significantly
improved
performance.
C#
C#
"Get-Command", typeof(Microsoft.PowerShell.Commands.GetCommandCommand),
"");
"Import-Module",
typeof(Microsoft.PowerShell.Commands.ImportModuleCommand), "");
iss.Commands.Add(getCommand);
iss.Commands.Add(importModule);
C#
Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();
C#
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Command");
Console.WriteLine(entry.Name);
C#
rs.Close();
Get-Command
Import-Module
Creating Runspaces
Article • 09/17/2021
A runspace is the operating environment for the commands that are invoked by a host
application. This environment includes the commands and data that are currently
present, and any language restrictions that currently apply.
Host applications can use the default runspace that is provided by Windows PowerShell,
which includes all available core commands, or create a custom runspace that includes
only a subset of the available commands. To create a customized runspace, you create
an System.Management.Automation.Runspaces.Initialsessionstate object and assign it to
your runspace.
Runspace tasks
1. Creating an InitialSessionState
See Also
Creating an InitialSessionState
Article • 10/04/2022
If you want to further limit the commands available in your host application you need to
create a constrained runspace.
For information, see Creating a constrained runspace.
C#
namespace SampleHost
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
class HostP4b
SessionStateVariableEntry var1 =
new SessionStateVariableEntry("test1",
"MyVar1",
iss.Variables.Add(var1);
SessionStateVariableEntry var2 =
new SessionStateVariableEntry("test2",
"MyVar2",
iss.Variables.Add(var2);
// Call RunspaceFactory.CreateRunspace(InitialSessionState) to
Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Variable");
ps.AddArgument("test*");
Console.WriteLine("Variable Value");
Console.WriteLine("--------------------------");
Console.WriteLine("{0,-20}{1}",
result.Members["Name"].Value,
result.Members["Value"].Value);
} // End foreach.
rs.Close();
} // End Main.
} // End SampleHost.
See Also
Creating a constrained runspace
For performance or security reasons, you might want to restrict the Windows PowerShell
commands available to your host application. To do this you create an empty
System.Management.Automation.Runspaces.Initialsessionstate by calling the
System.Management.Automation.Runspaces.Initialsessionstate.Create* method, and
then add only the commands you want available.
Using a runspace that loads only the commands that you specify provides significantly
improved performance.
You can also make commands private. Private commands can be used by the host
application, but not by users of the application.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell.Commands;
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
/// <summary>
/// This sample shows how to create an empty initial session state,
/// how to add commands to the session state, and then how to create a
/// runspace that has only those two commands. A PowerShell object
/// is used to run the Get-Command cmdlet to show that only two commands
/// </summary>
"get-process",
typeof(GetProcessCommand),
null);
iss.Commands.Add(ssce1);
"get-command",
typeof(GetCommandCommand),
null);
iss.Commands.Add(ssce2);
// Create a runspace.
myRunSpace.Open();
powershell.Runspace = myRunSpace;
powershell.AddCommand("get-command");
Console.WriteLine("Verb Noun");
Console.WriteLine("----------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["verb"].Value,
result.Members["Noun"].Value);
myRunSpace.Close();
System.Console.ReadKey();
C#
defaultSessionState = InitialSessionState.CreateDefault();
defaultSessionState.Commands[commandIndex].Visibility =
SessionStateEntryVisibility.Private;
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
See Also
Creating an InitialSessionState
Creating multiple runspaces
Article • 09/17/2021
If you create a large number of runspaces, you might consider creating a runspace pool.
Using a System.Management.Automation.Runspaces.Runspacepool object, rather than
creating a large number of individual runspaces with the same characteristics, can
improve performance.
C#
namespace HostRunspacePool
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class provides the Main entry point for the Host application.
/// </summary>
/// <summary>
/// </summary>
rsp.Open();
// get-process wmi*
gpc.RunspacePool = rsp;
gpc.AddCommand("Get-Process").AddArgument("wmi*");
PSDataCollection<PSObject> gpcOutput =
gpc.EndInvoke(gpcAsyncResult);
Console.WriteLine(
gpcOutput[i].Properties["ProcessName"].Value,
gpcOutput[i].Properties["Id"].Value);
} // End using.
See Also
Creating an InitialSessionState
Adding and invoking commands
Article • 10/03/2022
After creating a runspace, you can add Windows PowerShell commands and scripts to a
pipeline, and
then invoke the pipeline synchronously or asynchronously.
Creating a pipeline
The System.Management.Automation.Powershell
class provides several methods to add
commands, parameters, and scripts to the pipeline. You can
invoke the pipeline
synchronously by calling an overload of the
System.Management.Automation.Powershell.Invoke*
method, or asynchronously by
calling an overload of the
System.Management.Automation.Powershell.Begininvoke*
and then the
System.Management.Automation.Powershell.Endinvoke*
method.
AddCommand
1. Create a System.Management.Automation.Powershell object.
C#
PowerShell ps = PowerShell.Create();
C#
ps.AddCommand("Get-Process");
C#
ps.Invoke();
C#
PowerShell.Create().AddCommand("Get-Process")
.AddParameter("Name", "PowerShell")
.Invoke();
C#
PowerShell.Create().AddCommand("Get-Command")
.AddParameter("Name", "Get-VM")
.AddParameter("Module", "Hyper-V")
.Invoke();
You can also add a dictionary of parameter names and values by calling the
System.Management.Automation.Powershell.Addparameters*
method.
C#
parameters.Add("Name", "Get-VM");
parameters.Add("Module", "Hyper-V");
PowerShell.Create().AddCommand("Get-Command")
.AddParameters(parameters)
.Invoke()
AddStatement
You can simulate batching by using the
System.Management.Automation.Powershell.Addstatement*
method, which adds an
additional statement to the end of the pipeline The following code gets a list
of running
processes with the name PowerShell , and then gets the list of running services.
C#
PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-Process").AddParameter("Name", "PowerShell");
ps.AddStatement().AddCommand("Get-Service");
ps.Invoke();
AddScript
You can run an existing script by calling the
System.Management.Automation.Powershell.Addscript*
method. The following example
adds a script to the pipeline and runs it. This example assumes there
is already a script
named MyScript.ps1 in a folder named D:\PSScripts .
C#
PowerShell ps = PowerShell.Create();
ps.AddScript(File.ReadAllText(@"D:\PSScripts\MyScript.ps1")).Invoke();
C#
PowerShell ps = PowerShell.Create();
ps.AddScript(File.ReadAllText(@"D:\PSScripts\MyScript.ps1"), true).Invoke();
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
namespace HostPS1e
class HostPS1e
Console.WriteLine("{0}", result);
} // End foreach.
} // End Main.
} // End HostPS1e.
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
namespace HostPS3
class HostPS3
PowerShell ps = PowerShell.Create().AddCommand("Get-Process");
Console.WriteLine("{0,-20}{1}",
result.Members["ProcessName"].Value,
result.Members["Id"].Value);
} // End foreach.
System.Console.ReadKey();
} // End Main.
} // End HostPS3.
See Also
Creating an InitialSessionState
The following example shows how to create a runspace that connects to a remote
computer. In the
example, RemoteComputerUri is used as a placeholder for the actual URI
of a remote computer.
C#
namespace Samples
using System;
using System.Collections.ObjectModel;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
remoteRunspace.Open();
powershell.Runspace = remoteRunspace;
powershell.AddCommand("get-process");
powershell.Invoke();
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
// Close the connection. Call the Close() method to close the remote
remoteRunspace.Close();
Windows PowerShell provides abstract classes and interfaces that allow you to create a
custom interactive UI that hosts the Windows PowerShell engine. To create a custom UI,
you must implement the System.Management.Automation.Host.PSHost class.
Optionally, you can also implement the
System.Management.Automation.Host.Pshostrawuserinterface and
System.Management.Automation.Host.Pshostuserinterface classes, and the
System.Management.Automation.Host.Ihostsupportsinteractivesession and
System.Management.Automation.Host.Ihostuisupportsmultiplechoiceselection
interfaces.
Host Application Samples
Article • 09/17/2021
This section includes sample code that is provided in the Windows PowerShell 2.0 SDK.
In This Section
PowerShell API Samples This section includes sample code
that shows how to create
runspaces that restrict functionality, and how to asynchronously run
commands using a
runspace pool to supply the runspaces.
Custom Host Samples Includes sample code for writing a custom host. The
host is the
component of Windows PowerShell that provides communications between the user
and the
Windows PowerShell engine. For more information about custom hosts, see
Custom Host.
Runspace Samples Includes sample code for creating runspaces. For more
information
about how runspaces are used, see
Host Application Runspaces.
See Also
Windows PowerShell API Samples
Article • 09/17/2021
This section includes sample code that shows how to create runspaces that restrict
functionality, and how to asynchronously run commands by using a runspace pool to
supply the runspaces. You can use Microsoft Visual Studio to create a console
application and then copy the code from the topics in this section into your host
application.
In This Section
PowerShell01 Sample
This sample shows how to use an
System.Management.Automation.Runspaces.Initialsessionstate object to limit the
functionality of a runspace. The output of this sample demonstrates how to restrict the
language mode of the runspace, how to mark a cmdlet as private, how to add and
remove cmdlets and providers, how to add a proxy command, and more.
PowerShell02 Sample
This sample shows how to run commands asynchronously by
using the runspaces of a runspace pool. The sample generates a list of commands, and
then runs those commands while the Windows PowerShell engine opens a runspace
from the pool when it is needed.
Windows PowerShell01 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following:
C#
namespace Sample
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <returns>
/// The first index of the entry in <paramref name="entries"/> with the
/// </returns>
InitialSessionStateEntryCollection<T> entries,
int foundIndex = 0;
if (entry.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
return foundIndex;
foundIndex++;
return -1;
/// <summary>
/// </summary>
new PowerShell01().RunCommands();
/// <summary>
/// </summary>
powerShellCommand.AddScript(script);
powerShellCommand.Runspace = this.runspace;
try
Console.WriteLine(result);
Console.WriteLine();
Console.WriteLine("\n-----------------------------\n");
/// <summary>
/// </summary>
this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.Open();
this.runspace.Close();
this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.InitialSessionState.LanguageMode =
PSLanguageMode.RestrictedLanguage;
this.runspace.Open();
this.runspace.Close();
this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.InitialSessionState.LanguageMode =
PSLanguageMode.NoLanguage;
this.runspace.Open();
this.runspace.Close();
this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.Open();
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();
InitialSessionState defaultSessionState =
InitialSessionState.CreateDefault();
defaultSessionState.Commands.Add(new SessionStateAliasEntry("dir2",
"get-childitem"));
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.runspace.Close();
defaultSessionState = InitialSessionState.CreateDefault();
defaultSessionState.Commands.RemoveItem(commandIndex);
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();
defaultSessionState = InitialSessionState.CreateDefault();
defaultSessionState.Providers.Clear();
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.runspace.Close();
// that uses the private command. One reason to define a proxy for
// sample.
defaultSessionState = InitialSessionState.CreateDefault();
defaultSessionState.Commands[commandIndex].Visibility =
SessionStateEntryVisibility.Private;
typeof(Microsoft.PowerShell.Commands.GetChildItemCommand));
getChildItemMetadata.Parameters.Remove("Recurse");
defaultSessionState.Commands.Add(new SessionStateFunctionEntry("get-
childitem2", getChildItemBody));
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.RunScript("get-childitem2", scriptComment);
this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState);
this.runspace.Open();
this.RunScript("10/2", scriptComment);
this.runspace.Close();
cleanSessionState = InitialSessionState.Create();
cleanSessionState.LanguageMode = PSLanguageMode.FullLanguage;
this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState);
this.runspace.Open();
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();
cleanSessionState = InitialSessionState.Create();
cleanSessionState.Commands.Add(
new SessionStateCmdletEntry(
"Get-ChildItem",
typeof(Microsoft.PowerShell.Commands.GetChildItemCommand),
null));
cleanSessionState.Providers.Add(
new SessionStateProviderEntry(
"FileSystem",
typeof(Microsoft.PowerShell.Commands.FileSystemProvider),
null));
cleanSessionState.LanguageMode = PSLanguageMode.FullLanguage;
this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState);
this.runspace.Open();
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();
Console.Write("Done...");
Console.ReadLine();
See Also
Writing a Windows PowerShell Host Application
Windows PowerShell02 Sample
Article • 09/17/2021
This sample shows how to run commands asynchronously using the runspaces of a
runspace pool. The
sample generates a list of commands, and then runs those
commands while the Windows PowerShell
engine opens a runspace from the pool when
it is needed.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following:
Example
This sample shows how to open the runspaces of a runspace pool, and how to
asynchronously run
commands in those runspaces.
C#
namespace Sample
using System;
using System.Collections;
using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
/// <summary>
/// </summary>
runspacePool.Open();
using (runspacePool)
// 5, but we can queue up many more commands that will use the
// runspace pool.
powershell.RunspacePool = runspacePool;
// in the pool.
i,
runspacePool.GetAvailableRunspaces());
// The three lines below look the same running with a runspace or
powershell.AddScript(script);
powerShellCommands.Add(powershell);
powerShellCommandResults.Add(powershell.BeginInvoke());
PSDataCollection<PSObject> results =
powerShellCommands[i].EndInvoke(powerShellCommandResults[i]);
// Print all the results. One PSObject with a plain string is the
expected result.
PowerShell02.PrintCollection(results);
/// <summary>
/// </summary>
See Also
Writing a Windows PowerShell Host Application
Custom Host Samples
Article • 09/17/2021
This section includes sample code for writing a custom host. You can use Microsoft
Visual Studio to create a console application and then copy the code from the topics in
this section into your host application.
In This Section
Host01 Sample
This sample shows how to implement a host application that uses a
basic custom host.
Host02 Sample
This sample shows how to write a host application that uses the
Windows PowerShell runtime along with a custom host implementation. The host
application sets the host culture to German, runs the Get-Process cmdlet and displays
the results as you would see them using pwrsh.exe, and then prints out the current data
and time in German.
Host03 Sample
This sample shows how to build an interactive console-based host
application that reads commands from the command line, executes the commands, and
then displays the results to the console.
Host04 Sample
This sample shows how to build an interactive console-based host
application that reads commands from the command line, executes the commands, and
then displays the results to the console. This host application also supports displaying
prompts that allow the user to specify multiple choices.
Host05 Sample
This sample shows how to build an interactive console-based host
application that reads commands from the command line, executes the commands, and
then displays the results to the console. This host application also supports calls to
remote computers by using the Enter-PsSession and Exit-PsSession cmdlets
Host06 Sample
This sample shows how to build an interactive console-based host
application that reads commands from the command line, executes the commands, and
then displays the results to the console. In addition, this sample uses the Tokenizer APIs
to specify the color of the text that is entered by the user.
See Also
Host01 Sample
Article • 09/17/2021
This sample shows how to implement a host application that uses a custom host. In this
sample a
runspace is created that uses the custom host, and then the
System.Management.Automation.Powershell API
is used to run a script that calls "exit."
The host application then looks at the output of the
script and prints out the results.
This sample uses the default UI features provided by Windows PowerShell. For more
information about
implementing the UI features of a custom host, see Host02 Sample.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a custom host class that derives from the
System.Management.Automation.Host.PSHost
class.
Creating a
System.Management.Automation.Powershell
object that runs a script
that calls exit.
Verifying that the correct exit code was used in the exit process.
Example 1
The following code shows an implementation of a host application that uses a simple
custom host
interface.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
// Create a runspace that uses the host object and run the
myRunSpace.Open();
powershell.Runspace = myRunSpace;
// "exit (2+2)".
powershell.AddScript(script);
powershell.Invoke(script);
Console.WriteLine(
me.ShouldExit,
me.ExitCode);
myRunSpace.Close();
Console.ReadKey();
Example 2
The following code is the implementation of the
System.Management.Automation.Host.PSHost
class that is used by this host application.
Those elements that are not implemented throw an
exception or return nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Globalization;
using System.Management.Automation.Host;
/// <summary>
/// console applications. Not all members are implemented. Those that
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// </param>
this.program = program;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Keep in mind that this string may be used by script writers to
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Return the version object for this application. Typically this
/// </summary>
/// <summary>
/// Not implemented by this example class. The call fails with
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// restore state that has been modified by a child process (after
/// </summary>
return;
/// <summary>
/// </summary>
return;
/// <summary>
/// been requested. Pass the exit code that the host
/// </summary>
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
See Also
Host02 Sample
Article • 09/17/2021
This sample shows how to write a host application that uses the Windows PowerShell
runtime along
with a custom host implementation. The host application sets the host
culture to German, runs the
Get-Process cmdlet and displays
the results as you would
see them by using pwrsh.exe, and then prints out the current data and time
in German.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a custom host whose classes derive from the
System.Management.Automation.Host.PSHost
class, the
System.Management.Automation.Host.PSHostUserInterface
class, and the
System.Management.Automation.Host.PSHostRawUserInterface
class.
Creating a
System.Management.Automation.Powershell
object that runs a script to
retrieve and sort the processes, then retrieves the current date
which is displayed
in German.
Example 1
The following code shows an implementation of a host application that uses the custom
host.
C#
//
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Host
class Host02
/// <summary>
/// </summary>
/// <summary>
/// use to tell the host application what exit code to use
/// </summary>
/// <summary>
/// This sample uses the PowerShell runtime along with a host
/// </summary>
// instance is created...
System.Threading.Thread.CurrentThread.CurrentCulture =
CultureInfo.GetCultureInfo("de-de");
myRunSpace.Open();
// Add the script we want to run. This script does two things.
pipe.Commands.AddScript(@"
get-date | out-string
");
// Add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// application.
pipe.Commands.Add("out-default");
pipe.Commands[0].MergeMyResults(PipelineResultTypes.Error,PipelineResultType
s.Output);
pipe.Invoke();
System.Console.ReadKey();
Example 2
The following code is the implementation of the
System.Management.Automation.Host.PSHost
class that is used by this host application.
Those elements that are not implemented throw an
exception or return nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Globalization;
using System.Management.Automation.Host;
/// <summary>
/// console applications. Not all members are implemented. Those that
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// </param>
this.program = program;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the version object for this application. Typically this
/// </summary>
/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// </summary>
/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// </summary>
/// <summary>
/// can restore state that has been modified by a child process (after
/// </summary>
return;
/// <summary>
/// </summary>
return;
/// <summary>
/// been requested. Pass the exit code that the host
/// </summary>
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
Example 3
The following code is the implementation of the
System.Management.Automation.Host.PSHostUserInterface
class that is used by this
host application.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
/// <summary>
/// console applications. Not all members are implemented. Those that are
/// are implemented include those that map easily to Console APIs.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// application.
/// </summary>
/// <summary>
/// Prompts the user for input. In this example this functionality is
not
/// </summary>
string caption,
string message,
System.Collections.ObjectModel.Collection<FieldDescription> descriptions)
/// <summary>
/// </summary>
/// <summary>
/// Prompts the user for credentials with a specified prompt window
caption,
/// prompt message, user name, and target name. In this example this
/// </summary>
string caption,
string message,
string userName,
string targetName)
/// <summary>
/// Prompts the user for credentials by using a specified prompt window
caption,
/// prompt message, user name and target name, credential types allowed
to be
/// </summary>
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions
options)
/// <summary>
/// Reads characters that are entered by the user until a newline
/// </summary>
return Console.ReadLine();
/// <summary>
/// </summary>
/// <summary>
/// </summary>
System.Console.Write(value);
/// <summary>
/// Writes characters to the output display of the host and specifies
the
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
System.Console.Write(value);
/// <summary>
/// </summary>
Console.WriteLine(String.Format(
CultureInfo.CurrentCulture,
"DEBUG: {0}",
message));
/// <summary>
/// </summary>
Console.WriteLine(String.Format(
CultureInfo.CurrentCulture,
"ERROR: {0}",
value));
/// <summary>
/// </summary>
System.Console.WriteLine();
}
/// <summary>
/// </summary>
System.Console.WriteLine(value);
/// <summary>
/// </summary>
System.Console.WriteLine(value);
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.WriteLine(String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
/// <summary>
/// </summary>
Console.WriteLine(String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
Example 4
The following code is the implementation of the
System.Management.Automation.Host.PSHostRawUserInterface
class that is used by this
host application. Those elements that are not implemented throw an
exception or return
nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Management.Automation.Host;
/// <summary>
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the size of the host buffer. In this example the
/// buffer size is adapted from the Console buffer size members.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the size of the displayed cursor. In this example
/// property.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets a value indicating whether the user has pressed a key. This
maps
/// </summary>
/// <summary>
/// rendered in the current display, if the buffer was at the least
/// </summary>
/// <summary>
/// Gets the dimensions of the largest window size that can be
/// </summary>
/// <summary>
/// Gets or sets the position of the displayed window. This example
/// uses the Console window position APIs to determine the returned
/// </summary>
/// <summary>
/// Gets or sets the size of the displayed window. This example
/// uses the corresponding Console window size APIs to determine the
/// </summary>
/// <summary>
/// Gets or sets the title of the displayed window. The example
/// </summary>
/// <summary>
/// This API resets the input buffer. In this example this
/// </summary>
/// <summary>
/// this example this functionality is not needed so the method throws
/// </summary>
/// <summary>
/// typed that matches the specified keystroke options. In this example
/// </summary>
/// <summary>
/// This API crops a region of the screen buffer. In this example
/// </summary>
/// <summary>
/// This method copies an array of buffer cells into the screen buffer
/// </summary>
BufferCell[,] contents)
{
/// <summary>
See Also
System.Management.Automation.Powershell
System.Management.Automation.Host.PSHost
System.Management.Automation.Host.Pshostuserinterface
System.Management.Automation.Host.Pshostrawuserinterface
Host03 Sample
Article • 09/17/2021
This sample shows how to build an interactive console-based host application that reads
commands
from the command line, executes the commands, and then displays the
results to the console.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a custom host whose classes derive from the
System.Management.Automation.Host.PSHost
class, the
System.Management.Automation.Host.PSHostUserInterface
class, and the
System.Management.Automation.Host.PSHostRawUserInterface
class.
Building a console application that uses these host classes to build an interactive
Windows
PowerShell shell.
Example 1
This example allows the user to enter commands at a command line, processes those
commands, and then
prints out the results.
C#
//
// PARTICULAR PURPOSE.
//
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// This class contains the Main entry point for this host application.
/// The exit code that the host application will use to exit.
private PSListenerConsoleSample()
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();
/// Gets or sets the exit code that the host application will use
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" =====================================");
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;
listener.Run();
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default outputter, this
method()
if (String.IsNullOrEmpty(cmd))
return;
// variable
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
this.currentPowerShell.Runspace = this.myRunSpace;
// to be stopped.
try
this.currentPowerShell.AddScript(cmd);
// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// application.
this.currentPowerShell.AddCommand("out-default");
this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);
if (input != null)
else
this.currentPowerShell.Invoke();
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
if (e != null)
object error;
if (icer != null)
error = icer.ErrorRecord;
else
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
this.currentPowerShell.Runspace = this.myRunSpace;
try
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");
Collection<PSObject> result;
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);
if (result.Count > 0)
if (!string.IsNullOrEmpty(str))
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
try
this.executeHelper(cmd, null);
this.ReportException(rte);
/// Method used to handle control-C's from the user. It calls the
try
lock (this.instanceLock)
this.currentPowerShell.Stop();
e.Cancel = true;
this.myHost.UI.WriteErrorLine(exception.ToString());
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;
while (!this.ShouldExit)
this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black,
"\nPSConsoleSample: ");
this.Execute(cmd);
// Exit with the desired exit code that was set by exit command.
Environment.Exit(this.ExitCode);
Example 2
The following code is the implementation of the
System.Management.Automation.Host.PSHost
class that is used by this host application.
Those elements that are not implemented throw an
exception or return nothing.
C#
//
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
namespace Microsoft.Samples.PowerShell.Host
/// <summary>
/// </summary>
class PSListenerConsoleSample
/// <summary>
/// Define the property that the PSHost implementation will use to tell
the host
/// </summary>
/// <summary>
/// Define the property that the PSHost implementation will use to tell
the host
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
PSListenerConsoleSample()
// Create the host and runspace instances for this interpreter. Note
that
// will be available.
myRunSpace = RunspaceFactory.CreateRunspace(myHost);
myRunSpace.Open();
/// <summary>
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default outputter, this
method()
/// </summary>
if (String.IsNullOrEmpty(cmd))
return;
lock (instanceLock)
currentPipeline = myRunSpace.CreatePipeline();
try
currentPipeline.Commands.AddScript(cmd);
// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// application.
currentPipeline.Commands.Add("out-default");
currentPipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error,
PipelineResultTypes.Output);
if (input != null)
else
currentPipeline.Invoke();
finally
lock (instanceLock)
currentPipeline.Dispose();
currentPipeline = null;
/// <summary>
/// </summary>
try
executeHelper(cmd, null);
/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// they are printed to the console; otherwise they are ignored.
/// </summary>
try
lock (instanceLock)
currentPipeline.Stop();
e.Cancel = true;
this.myHost.UI.WriteErrorLine(exception.ToString());
/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// </summary>
Console.CancelKeyPress += new
ConsoleCancelEventHandler(HandleControlC);
Console.TreatControlCAsInput = false;
while (!ShouldExit)
myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black,
"\nPSConsoleSample: ");
Execute(cmd);
// Exit with the desired exit code that was set by exit command.
Environment.Exit(ExitCode);
}
/// <summary>
/// </summary>
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" =====================================");
Console.WriteLine("");
Console.WriteLine("");
Console.ForegroundColor = oldFg;
listener.Run();
Example 3
The following code is the implementation of the
System.Management.Automation.Host.PSHostUserInterface
class that is used by this
host application.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;
/// <summary>
/// console applications. Not all members are implemented. Those that are
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// application.
/// </summary>
/// <summary>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
string caption,
string message,
Collection<FieldDescription>
descriptions)
this.Write(
ConsoleColor.Blue,
ConsoleColor.Black,
this.WriteLine(label[1]);
if (userData == null)
return null;
results[fd.Name] = PSObject.AsPSObject(userData);
return results;
/// <summary>
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));
while (true)
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
if (data.Length == 0)
return defaultChoice;
if (promptData[0, i] == data)
return i;
/// <summary>
/// Prompts the user for credentials with a specified prompt window
caption,
/// prompt message, user name, and target name. In this example this
/// </summary>
string caption,
string message,
string userName,
string targetName)
/// <summary>
/// Prompts the user for credentials by using a specified prompt window
caption,
/// prompt message, user name and target name, credential types allowed
to be
/// </summary>
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions
options)
/// <summary>
/// Reads characters that are entered by the user until a newline
/// </summary>
return Console.ReadLine();
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.Write(value);
/// <summary>
/// Writes characters to the output display of the host with possible
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
/// <summary>
/// </summary>
Console.WriteLine();
/// <summary>
/// </summary>
Console.WriteLine(value);
/// <summary>
/// </summary>
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
/// <summary>
/// </summary>
/// <returns>
Collection<ChoiceDescription> choices)
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}
return hotkeysAndPlainLabels;
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (fragments.Length == 2)
if (fragments[1].Length > 0)
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
else
result[1] = input;
return result;
Example 4
The following code is the implementation of the
System.Management.Automation.Host.PSHostRawUserInterface
class that is used by this
host application. Those elements that are not implemented throw an
exception or return
nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Management.Automation.Host;
/// <summary>
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the cursor size taken directly from the
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// properties.
/// </summary>
/// <summary>
/// properties.
/// </summary>
/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
/// <summary>
/// This API resets the input buffer. In this example this
/// </summary>
/// <summary>
/// this example this functionality is not needed so the method throws
/// </summary>
/// <summary>
/// typed that matches the specified keystroke options. In this example
/// </summary>
/// <summary>
/// This API crops a region of the screen buffer. In this example
/// </summary>
/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// </summary>
/// <summary>
/// This API Copies a given character, foreground color, and background
See Also
System.Management.Automation.Host.PSHost
System.Management.Automation.Host.Pshostuserinterface
System.Management.Automation.Host.Pshostrawuserinterface
Host04 Sample
Article • 09/17/2021
This sample shows how to build an interactive console-based host application that reads
commands
from the command line, executes the commands, and then displays the
results to the console. This
host application also supports displaying prompts that allow
the user to specify multiple choices.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a custom host whose classes derive from the
System.Management.Automation.Host.PSHost
class, the
System.Management.Automation.Host.PSHostUserInterface
class, and the
System.Management.Automation.Host.PSHostRawUserInterface
class.
Building a console application that uses these host classes to build an interactive
Windows
PowerShell shell.
Implement the
System.Management.Automation.Host.IHostUISupportsMultipleChoiceSelection
interface.
Example 1
This example allows the user to enter commands at a command line, processes those
commands, and then
prints out the results.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the exit code that the host application will use
/// </summary>
/// <summary>
/// </summary>
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("
==================================================");
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;
listener.Run();
/// <summary>
/// </summary>
private PSListenerConsoleSample()
// Create the host and runspace instances for this interpreter. Note
that
// will be available.
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
try
this.currentPowerShell.Runspace = this.myRunSpace;
PSCommand[] profileCommands =
Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHo
st04");
this.currentPowerShell.Commands = command;
this.currentPowerShell.Invoke();
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default outputter, this
method
/// </summary>
if (String.IsNullOrEmpty(cmd))
return;
// variable.
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
this.currentPowerShell.Runspace = this.myRunSpace;
// be stopped.
try
this.currentPowerShell.AddScript(cmd);
// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// application.
this.currentPowerShell.AddCommand("out-default");
this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);
if (input != null)
else
this.currentPowerShell.Invoke();
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// </summary>
if (e != null)
object error;
if (icer != null)
error = icer.ErrorRecord;
else
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
this.currentPowerShell.Runspace = this.myRunSpace;
try
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");
Collection<PSObject> result;
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);
if (result.Count > 0)
if (!string.IsNullOrEmpty(str))
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// </summary>
try
this.executeHelper(cmd, null);
this.ReportException(rte);
/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// </summary>
try
lock (this.instanceLock)
this.currentPowerShell.Stop();
e.Cancel = true;
this.myHost.UI.WriteErrorLine(exception.ToString());
/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// </summary>
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;
while (!this.ShouldExit)
this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black,
"\nPSConsoleSample: ");
this.Execute(cmd);
// Exit with the desired exit code that was set by exit command.
Environment.Exit(this.ExitCode);
Example 2
The following code is the implementation of the
System.Management.Automation.Host.PSHost
class that is used by this host application.
Those elements that are not implemented throw an
exception or return nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Globalization;
using System.Management.Automation.Host;
/// <summary>
/// console applications. Not all members are implemented. Those that
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// </param>
this.program = program;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the version object for this application. Typically this
/// </summary>
/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// </summary>
/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// </summary>
/// <summary>
/// can restore state that has been modified by a child process (after
/// </summary>
return;
/// <summary>
/// </summary>
return;
/// <summary>
/// been requested. Pass the exit code that the host
/// </summary>
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
Example 3
The following code is the implementation of the
System.Management.Automation.Host.Pshostuserinterface
class that is used by this host
application.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;
/// <summary>
/// console applications. Not all members are implemented. Those that are
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// application.
/// </summary>
/// <summary>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
string caption,
string message,
Collection<FieldDescription> descriptions)
this.Write(
ConsoleColor.Blue,
ConsoleColor.Black,
this.WriteLine(label[1]);
if (userData == null)
return null;
results[fd.Name] = PSObject.AsPSObject(userData);
return results;
/// <summary>
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));
while (true)
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
if (data.Length == 0)
return defaultChoice;
if (promptData[0, i] == data)
return i;
/// <summary>
/// Provides a set of choices that enable the user to choose a one or
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
IEnumerable<int> defaultChoices)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
if (defaultChoices != null)
int countDefaults = 0;
++countDefaults;
defaultResults.Add(defaultChoice);
if (countDefaults != 0)
sb.AppendFormat(
CultureInfo.CurrentCulture,
"\"{0}\",",
promptData[0, defaultChoice]);
sb.Remove(sb.Length - 1, 1);
sb.Append("]");
this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
sb.ToString());
while (true)
ReadNext:
// If the choice string was empty, no more choices have been made.
if (data.Length == 0)
if (promptData[0, i] == data)
results.Add(i);
goto ReadNext;
#endregion
/// <summary>
/// Prompts the user for credentials with a specified prompt window
/// caption, prompt message, user name, and target name. In this
/// </summary>
string caption,
string message,
string userName,
string targetName)
/// <summary>
/// Prompts the user for credentials by using a specified prompt window
/// caption, prompt message, user name and target name, credential
/// </summary>
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions options)
/// <summary>
/// Reads characters that are entered by the user until a newline
/// </summary>
return Console.ReadLine();
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.Write(value);
/// <summary>
/// Writes characters to the output display of the host with possible
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
/// <summary>
/// </summary>
Console.WriteLine();
/// <summary>
/// </summary>
Console.WriteLine(value);
/// <summary>
/// </summary>
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (fragments.Length == 2)
if (fragments[1].Length > 0)
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
else
result[1] = input;
return result;
/// <summary>
/// </summary>
/// <returns>
Collection<ChoiceDescription> choices)
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}
return hotkeysAndPlainLabels;
Example 4
The following code is the implementation of the
System.Management.Automation.Host.Pshostrawuserinterface
class that is used by this
host application. Those elements that are not implemented throw an
exception or return
nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Management.Automation.Host;
/// <summary>
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the cursor size taken directly from the
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// properties.
/// </summary>
/// <summary>
/// properties.
/// </summary>
/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
/// <summary>
/// This API resets the input buffer. In this example this
/// </summary>
/// <summary>
/// this example this functionality is not needed so the method throws
/// </summary>
/// <summary>
/// typed that matches the specified keystroke options. In this example
/// </summary>
/// <summary>
/// This API crops a region of the screen buffer. In this example
/// </summary>
/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// </summary>
/// <summary>
/// This API Copies a given character, foreground color, and background
See Also
System.Management.Automation.Host.PSHost
System.Management.Automation.Host.Pshostuserinterface
System.Management.Automation.Host.Pshostrawuserinterface
Host05 Sample
Article • 09/17/2021
This sample shows how to build an interactive console-based host application that reads
commands
from the command line, executes the commands, and then displays the
results to the console. This
host application also supports calls to remote computers by
using the
Enter-PsSession and
Exit-PsSession cmdlets.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a custom host whose classes derive from the
System.Management.Automation.Host.PSHost
class, the
System.Management.Automation.Host.Pshostuserinterface
class, and the
System.Management.Automation.Host.Pshostrawuserinterface
class.
Building a console application that uses these host classes to build an interactive
Windows PowerShell shell.
Implement the
System.Management.Automation.Host.IHostUISupportsMultipleChoiceSelection
interface.
Implement the
System.Management.Automation.Host.IHostSupportsInteractiveSession
interface
to support interactive remoting by using the
Enter-PsSession and
Exit-PsSession
cmdlets.
Example 1
This example allows the user to enter commands at a command line, processes those
commands, and then
prints out the results.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Text;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the exit code that the host application will use
/// </summary>
/// <summary>
/// </summary>
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("
==================================================");
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;
// Create the listener and runs it. This method never returns.
listener.Run();
/// <summary>
/// </summary>
private PSListenerConsoleSample()
// Create the host and runspace instances for this interpreter. Note
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
try
this.currentPowerShell.Runspace = this.myRunSpace;
PSCommand[] profileCommands =
Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHo
st05");
this.currentPowerShell.Commands = command;
this.currentPowerShell.Invoke();
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// </summary>
if (String.IsNullOrEmpty(cmd))
return;
// variable.
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
// to be stopped.
try
this.currentPowerShell.Runspace = this.myRunSpace;
this.currentPowerShell.AddScript(cmd);
// Add the default outputter to the end of the pipe and then
this.currentPowerShell.AddCommand("out-default");
this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);
// the pipeline.
if (input != null)
else
this.currentPowerShell.Invoke();
finally
// ctrl-C handler.
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// </summary>
if (e != null)
object error;
if (icer != null)
error = icer.ErrorRecord;
else
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
this.currentPowerShell.Runspace = this.myRunSpace;
try
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");
Collection<PSObject> result;
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);
if (result.Count > 0)
if (!string.IsNullOrEmpty(str))
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// display.
/// </summary>
try
this.executeHelper(cmd, null);
this.ReportException(rte);
/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// </summary>
/// ConsoleCancelEventHandler.</param>
/// ConsoleCancelEventHandler.</param>
try
lock (this.instanceLock)
this.currentPowerShell.Stop();
e.Cancel = true;
this.myHost.UI.WriteErrorLine(exception.ToString());
/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// </summary>
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;
while (!this.ShouldExit)
string prompt;
if (this.myHost.IsRunspacePushed)
else
this.Execute(cmd);
// Exit with the desired exit code that was set by exit command.
Environment.Exit(this.ExitCode);
Example 2
The following code is the implementation of the
System.Management.Automation.Host.PSHost
class that is used by this host application.
Those elements that are not implemented throw an
exception or return nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Globalization;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
/// <summary>
/// console applications. Not all members are implemented. Those that
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// </param>
this.program = program;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the version object for this application. Typically this
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// </summary>
/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// </summary>
/// <summary>
/// can restore state that has been modified by a child process (after
/// </summary>
return;
/// <summary>
/// </summary>
return;
/// <summary>
/// been requested. Pass the exit code that the host
/// </summary>
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
/// <summary>
/// </summary>
Runspace = this.pushedRunspace;
this.pushedRunspace = null;
/// <summary>
/// </summary>
this.pushedRunspace = Runspace;
Runspace = runspace;
Example 3
The following code is the implementation of the
System.Management.Automation.Host.Pshostuserinterface
class that is used by this host
application.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;
/// <summary>
/// console applications. Not all members are implemented. Those that are
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// application.
/// </summary>
/// <summary>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
string caption,
string message,
Collection<FieldDescription> descriptions)
this.Write(
ConsoleColor.Blue,
ConsoleColor.Black,
this.WriteLine(label[1]);
if (userData == null)
return null;
results[fd.Name] = PSObject.AsPSObject(userData);
return results;
/// <summary>
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));
while (true)
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
if (data.Length == 0)
return defaultChoice;
if (promptData[0, i] == data)
return i;
/// <summary>
/// Provides a set of choices that enable the user to choose a one or
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
IEnumerable<int> defaultChoices)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
if (defaultChoices != null)
int countDefaults = 0;
++countDefaults;
defaultResults.Add(defaultChoice);
if (countDefaults != 0)
sb.AppendFormat(
CultureInfo.CurrentCulture,
"\"{0}\",",
promptData[0, defaultChoice]);
sb.Remove(sb.Length - 1, 1);
sb.Append("]");
this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
sb.ToString());
while (true)
ReadNext:
// If the choice string was empty, no more choices have been made.
if (data.Length == 0)
if (promptData[0, i] == data)
results.Add(i);
goto ReadNext;
#endregion
/// <summary>
/// Prompts the user for credentials with a specified prompt window
/// caption, prompt message, user name, and target name. In this
/// </summary>
string caption,
string message,
string userName,
string targetName)
/// <summary>
/// Prompts the user for credentials by using a specified prompt window
/// caption, prompt message, user name and target name, credential
/// </summary>
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions options)
/// <summary>
/// Reads characters that are entered by the user until a newline
/// </summary>
return Console.ReadLine();
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.Write(value);
/// <summary>
/// Writes characters to the output display of the host with possible
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
/// <summary>
/// </summary>
Console.WriteLine();
/// <summary>
/// </summary>
Console.WriteLine(value);
/// <summary>
/// </summary>
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (fragments.Length == 2)
if (fragments[1].Length > 0)
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
else
result[1] = input;
return result;
/// <summary>
/// </summary>
/// <returns>
Collection<ChoiceDescription> choices)
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}
return hotkeysAndPlainLabels;
Example 4
The following code is the implementation of the
System.Management.Automation.Host.Pshostrawuserinterface
class that is used by this
host application. Those elements that are not implemented throw an
exception or return
nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Management.Automation.Host;
/// <summary>
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the cursor size taken directly from the
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// properties.
/// </summary>
/// <summary>
/// properties.
/// </summary>
/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
/// <summary>
/// This API resets the input buffer. In this example this
/// </summary>
/// <summary>
/// this example this functionality is not needed so the method throws
/// </summary>
/// <summary>
/// typed that matches the specified keystroke options. In this example
/// </summary>
/// <summary>
/// This API crops a region of the screen buffer. In this example
/// </summary>
/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// </summary>
/// <summary>
/// This API Copies a given character, foreground color, and background
See Also
System.Management.Automation.Host.PSHost
System.Management.Automation.Host.Pshostuserinterface
System.Management.Automation.Host.Pshostrawuserinterface
Host06 Sample
Article • 09/17/2021
This sample shows how to build an interactive console-based host application that reads
commands
from the command line, executes the commands, and then displays the
results to the console. In
addition, this sample uses the Tokenizer APIs to specify the
color of the text that is entered by
the user.
Requirements
This sample requires Windows PowerShell 2.0.
This application must be run in elevated mode (Run as administrator).
Demonstrates
Creating a custom host whose classes derive from the
System.Management.Automation.Host.PSHost
class, the
System.Management.Automation.Host.Pshostuserinterface
class, and the
System.Management.Automation.Host.Pshostrawuserinterface
class.
Building a console application that uses these host classes to build an interactive
Windows
PowerShell shell.
Implement the
System.Management.Automation.Host.IHostUISupportsMultipleChoiceSelection
interface.
Implement the
System.Management.Automation.Host.IHostSupportsInteractiveSession
interface
to support interactive remoting by using the
Enter-PsSession and
Exit-PsSession
cmdlets.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Text;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("
==================================================");
Console.WriteLine(string.Empty);
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;
// Create the listener and run it. This method never returns.
listener.Run();
/// <summary>
/// </summary>
public PSListenerConsoleSample()
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
try
this.currentPowerShell.Runspace = this.myRunSpace;
PSCommand[] profileCommands =
Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHo
st06");
this.currentPowerShell.Commands = command;
this.currentPowerShell.Invoke();
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// A helper class that builds and executes a pipeline that writes
/// to the default output path. Any exceptions that are thrown are
/// just passed to the caller. Since all output goes to the default
/// </summary>
if (String.IsNullOrEmpty(cmd))
return;
// variable.
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
// Add a script and command to the pipeline and then run the pipeline.
Place
// stopped.
try
this.currentPowerShell.Runspace = this.myRunSpace;
this.currentPowerShell.AddScript(cmd);
// Add the default outputter to the end of the pipe and then call
the
// pipeline. This will result in the output being written using the
PSHost
// application.
this.currentPowerShell.AddCommand("out-default");
this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);
// the pipeline.
if (input != null)
else
this.currentPowerShell.Invoke();
finally
// ctrl-C handler.
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// </summary>
if (e != null)
object error;
if (icer != null)
error = icer.ErrorRecord;
else
lock (this.instanceLock)
this.currentPowerShell = PowerShell.Create();
this.currentPowerShell.Runspace = this.myRunSpace;
try
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");
Collection<PSObject> result;
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);
if (result.Count > 0)
if (!string.IsNullOrEmpty(str))
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
finally
lock (this.instanceLock)
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
/// <summary>
/// display.
/// </summary>
try
this.executeHelper(cmd, null);
this.ReportException(rte);
/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// </summary>
/// ConsoleCancelEventHandler.</param>
/// ConsoleCancelEventHandler.</param>
try
lock (this.instanceLock)
this.currentPowerShell.Stop();
e.Cancel = true;
this.myHost.UI.WriteErrorLine(exception.ToString());
/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// </summary>
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;
// Read commands and run them until the ShouldExit flag is set by
while (!this.ShouldExit)
string prompt;
if (this.myHost.IsRunspacePushed)
else
this.Execute(cmd);
// Exit with the desired exit code that was set by the exit command.
Environment.Exit(this.ExitCode);
Example 2
The following code is the implementation of the
System.Management.Automation.Host.PSHost
class that is used by this host application.
Those elements that are not implemented throw an
exception or return nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Globalization;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
/// <summary>
/// console applications. Not all members are implemented. Those that
/// </summary>
this.program = program;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentCulture;
/// <summary>
/// </summary>
System.Threading.Thread.CurrentThread.CurrentUICulture;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the version object for this application. Typically this
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// </summary>
/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// </summary>
/// <summary>
/// can restore state that has been modified by a child process (after
/// </summary>
return;
/// <summary>
/// </summary>
return;
/// <summary>
/// been requested. Pass the exit code that the host
/// </summary>
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
/// <summary>
/// </summary>
Runspace = this.pushedRunspace;
this.pushedRunspace = null;
/// <summary>
/// </summary>
this.pushedRunspace = Runspace;
Runspace = runspace;
Example 3
The following code is the implementation of the
System.Management.Automation.Host.Pshostuserinterface
class that is used by this host
application.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;
/// <summary>
/// console applications. Not all members are implemented. Those that are
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// application.
/// </summary>
/// <summary>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
string caption,
string message,
Collection<FieldDescription> descriptions)
this.Write(
ConsoleColor.DarkCyan,
ConsoleColor.Black,
this.WriteLine(label[1]);
if (userData == null)
return null;
results[fd.Name] = PSObject.AsPSObject(userData);
return results;
/// <summary>
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));
while (true)
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
if (data.Length == 0)
return defaultChoice;
if (promptData[0, i] == data)
return i;
/// <summary>
/// Provides a set of choices that enable the user to choose a one or
/// </summary>
string caption,
string message,
Collection<ChoiceDescription>
choices,
IEnumerable<int> defaultChoices)
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
sb.Append(String.Format(
CultureInfo.CurrentCulture,
promptData[0, element],
promptData[1, element]));
if (defaultChoices != null)
int countDefaults = 0;
++countDefaults;
defaultResults.Add(defaultChoice);
if (countDefaults != 0)
sb.AppendFormat(
CultureInfo.CurrentCulture,
"\"{0}\",",
promptData[0, defaultChoice]);
sb.Remove(sb.Length - 1, 1);
sb.Append("]");
this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
sb.ToString());
while (true)
ReadNext:
// If the choice string was empty, no more choices have been made.
if (data.Length == 0)
if (promptData[0, i] == data)
results.Add(i);
goto ReadNext;
#endregion
/// <summary>
/// Prompts the user for credentials with a specified prompt window
/// caption, prompt message, user name, and target name. In this
/// </summary>
string caption,
string message,
string userName,
string targetName)
/// <summary>
/// Prompts the user for credentials by using a specified prompt window
/// caption, prompt message, user name and target name, credential
/// </summary>
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions options)
/// <summary>
/// Reads characters that are entered by the user until a newline
/// </summary>
return Console.ReadLine();
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.Write(value);
/// <summary>
/// Writes characters to the output display of the host with possible
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
/// <summary>
/// </summary>
Console.WriteLine();
/// <summary>
/// </summary>
Console.WriteLine(value);
/// <summary>
/// </summary>
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
/// <summary>
/// </summary>
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (fragments.Length == 2)
if (fragments[1].Length > 0)
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
else
result[1] = input;
return result;
/// <summary>
/// </summary>
/// <returns>
Collection<ChoiceDescription> choices)
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}
return hotkeysAndPlainLabels;
Example 4
The following code is the implementation of the
System.Management.Automation.Host.Pshostrawuserinterface
class that is used by this
host application. Those elements that are not implemented throw an
exception or return
nothing.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Management.Automation.Host;
/// <summary>
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets or sets the cursor size taken directly from the
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// properties.
/// </summary>
/// <summary>
/// properties.
/// </summary>
/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
/// <summary>
/// This API resets the input buffer. In this example this
/// </summary>
/// <summary>
/// this example this functionality is not needed so the method throws
/// </summary>
/// <summary>
/// typed that matches the specified keystroke options. In this example
/// </summary>
/// <summary>
/// This API crops a region of the screen buffer. In this example
/// </summary>
/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// </summary>
/// <summary>
/// This API Copies a given character, foreground color, and background
Example 5
The following code reads the command line and colors the text as it is entered. Tokens
are
determined by using the
System.Management.Automation.Psparser.Tokenize*
method.
C#
namespace Microsoft.Samples.PowerShell.Host
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Text;
/// <summary>
/// This class is used to read the command line and color the text as
/// method.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// We do not pick different colors for every token, those tokens
/// </summary>
/// <summary>
/// </summary>
public ConsoleReadLine()
this.defaultColor, // Unknown
ConsoleColor.Yellow, // Command
ConsoleColor.Green, // CommandParameter
ConsoleColor.Cyan, // CommandArgument
ConsoleColor.Cyan, // Number
ConsoleColor.Cyan, // String
ConsoleColor.Green, // Variable
this.defaultColor, // Member
this.defaultColor, // LoopLabel
ConsoleColor.DarkYellow, // Attribute
ConsoleColor.DarkYellow, // Type
ConsoleColor.DarkCyan, // Operator
this.defaultColor, // GroupStart
this.defaultColor, // GroupEnd
ConsoleColor.Magenta, // Keyword
ConsoleColor.Red, // Comment
ConsoleColor.DarkCyan, // StatementSeparator
this.defaultColor, // NewLine
this.defaultColor, // LineContinuation
this.defaultColor, // Position
};
/// <summary>
/// </summary>
this.Initialize();
while (true)
switch (key.Key)
case ConsoleKey.Backspace:
this.OnBackspace();
break;
case ConsoleKey.Delete:
this.OnDelete();
break;
case ConsoleKey.Enter:
return this.OnEnter();
case ConsoleKey.RightArrow:
this.OnRight(key.Modifiers);
break;
case ConsoleKey.LeftArrow:
this.OnLeft(key.Modifiers);
break;
case ConsoleKey.Escape:
this.OnEscape();
break;
case ConsoleKey.Home:
this.OnHome();
break;
case ConsoleKey.End:
this.OnEnd();
break;
case ConsoleKey.UpArrow:
case ConsoleKey.DownArrow:
case ConsoleKey.LeftWindows:
case ConsoleKey.RightWindows:
// ignore these
continue;
default:
if (key.KeyChar == '\x0D')
if (key.KeyChar == '\x08')
this.Insert(key);
break;
/// <summary>
/// </summary>
this.buffer.Length = 0;
this.current = 0;
this.rendered = 0;
/// <summary>
/// </summary>
this.buffer.Insert(this.current, key.KeyChar);
this.current++;
this.Render();
/// <summary>
/// </summary>
this.current = this.buffer.Length;
this.cursor.Place(this.rendered);
/// <summary>
/// </summary>
this.current = 0;
this.cursor.Reset();
/// <summary>
/// </summary>
this.buffer.Length = 0;
this.current = 0;
this.Render();
/// <summary>
/// </summary>
this.MoveLeft();
if (IsSeparator(this.buffer[this.current]) != nonLetter)
if (!nonLetter)
this.MoveRight();
break;
nonLetter = false;
else
this.MoveLeft();
/// <summary>
/// </summary>
/// is a separator.</returns>
return !Char.IsLetter(ch);
/// <summary>
/// </summary>
this.MoveRight();
if (this.current == this.buffer.Length)
break;
if (IsSeparator(this.buffer[this.current]) != nonLetter)
if (nonLetter)
break;
nonLetter = true;
else
this.MoveRight();
/// <summary>
/// </summary>
char c = this.buffer[this.current];
this.current++;
Cursor.Move(1);
/// <summary>
/// </summary>
this.current--;
char c = this.buffer[this.current];
Cursor.Move(-1);
/// <summary>
/// </summary>
Console.Out.Write("\n");
return this.buffer.ToString();
/// <summary>
/// </summary>
this.buffer.Remove(this.current, 1);
this.Render();
/// <summary>
/// </summary>
this.buffer.Remove(this.current - 1, 1);
this.current--;
this.Render();
/// <summary>
/// </summary>
if (tokens.Count > 0)
int i;
break;
// Place the cursor at the start of the first token to render. The
this.cursor.Place(tokens[i].Start);
// use the actual text from our input because the content
sometimes
Console.ForegroundColor = this.tokenColors[(int)tokens[i].Type];
Console.Out.Write(text.Substring(tokens[i].Start,
tokens[i].Length));
if (i != (tokens.Count - 1))
Console.ForegroundColor = this.defaultColor;
Console.Out.Write(text[j]);
Console.ForegroundColor = this.defaultColor;
Console.Out.Write(text[j]);
else
this.cursor.Reset();
Console.Out.Write(text);
this.rendered = text.Length;
this.cursor.Place(this.current);
/// <summary>
/// A helper class for maintaining the cursor while editing the command
line.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
public Cursor()
this.anchorTop = Console.CursorTop;
this.anchorLeft = Console.CursorLeft;
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Console.CursorTop = this.anchorTop;
Console.CursorLeft = this.anchorLeft;
/// <summary>
/// </summary>
cursorTop = Console.BufferHeight - 1;
Console.CursorTop = cursorTop;
} // End Cursor
See Also
System.Management.Automation.Host.PSHost
System.Management.Automation.Host.Pshostuserinterface
System.Management.Automation.Host.Pshostrawuserinterface
Runspace Samples
Article • 09/17/2021
This section includes sample code that shows how to use different types of runspaces to
run commands synchronously and asynchronously. You can use Microsoft Visual Studio
to create a console application and then copy the code from the topics in this section
into your host application.
In This Section
7 Note
For samples of host applications that create custom host interfaces, see Custom
Host Samples.
Runspace01 Sample
This sample shows how to use the
System.Management.Automation.Powershell class to run the Get-Process cmdlet
synchronously and display its output in a console window.
Runspace02 Sample
This sample shows how to use the
System.Management.Automation.Powershell class to run the Get-Process and Sort-
Object cmdlets synchronously. The results of these commands is displayed by using a
System.Windows.Forms.Datagridview control.
Runspace03 Sample
This sample shows how to use the
System.Management.Automation.Powershell class to run a script synchronously, and
how to handle non-terminating errors. The script receives a list of process names and
then retrieves those processes. The results of the script, including any non-terminating
errors that were generated when running the script, are displayed in a console window.
Runspace04 Sample
This sample shows how to use the
System.Management.Automation.Powershell class to run commands, and how to catch
terminating errors that are thrown when running the commands. Two commands are
run, and the last command is passed a parameter argument that is not valid. As a result
no objects are returned and a terminating error is thrown.
Runspace05 Sample
This sample shows how to add a snap-in to an
System.Management.Automation.Runspaces.Initialsessionstate object so that the cmdlet
of the snap-in is available when the runspace is opened. The snap-in provides a Get-
Proc cmdlet (defined by the GetProcessSample01 Sample) that is run synchronously
using a System.Management.Automation.Powershell object.
Runspace06 Sample
This sample shows how to add a module to an
System.Management.Automation.Runspaces.Initialsessionstate object so that the
module is loaded when the runspace is opened. The module provides a Get-Proc cmdlet
(defined by the GetProcessSample02 Sample) that is run synchronously using a
System.Management.Automation.Powershell object.
Runspace07 Sample
This sample shows how to create a runspace, and then use that
runspace to run two cmdlets synchronously by using a
System.Management.Automation.Powershell object.
Runspace08 Sample
This sample shows how to add commands and arguments to the
pipeline of a System.Management.Automation.Powershell object and how to run the
commands synchronously.
Runspace09 Sample
This sample shows how to add a script to the pipeline of a
System.Management.Automation.Powershell object and how to run the script
asynchronously. Events are used to handle the output of the script.
Runspace10 Sample
This sample shows how to create a default initial session state, how
to add a cmdlet to the System.Management.Automation.Runspaces.Initialsessionstate,
how to create a runspace that uses the initial session state, and how to run the
command by using a System.Management.Automation.Powershell object.
Runspace11 Sample
This shows how to use the
System.Management.Automation.Proxycommand class to create a proxy command that
calls an existing cmdlet, but restricts the set of available parameters. The proxy
command is then added to an initial session state that is used to create a constrained
runspace. This means that the user can access the functionality of the cmdlet only
through the proxy command.
See Also
Runspace01 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a System.Management.Automation.Powershell object to run a command.
Example
This sample runs the Get-Process cmdlet synchronously in the default runspace
provided by Windows PowerShell.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Management.Automation;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
System.Console.ReadKey();
See Also
Runspace02 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample runs the Get-Process and Sort-Object cmdlets synchronously in the default
runspace provided by Windows PowerShell. The output is displayed in a form using a
System.Windows.Forms.Datagridview control.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Windows.Forms;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This method creates the form where the output is displayed.
/// </summary>
form.Controls.Add(grid);
grid.Dock = DockStyle.Fill;
powershell.AddCommand("get-process").AddCommand("sort-
object").AddArgument("ID");
if (Runspace.DefaultRunspace == null)
Runspace.DefaultRunspace = powershell.Runspace;
objects.AddRange(results);
grid.DataSource = objects;
form.ShowDialog();
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
Runspace02.CreateForm();
See Also
Writing a Windows PowerShell Host Application
Runspace03 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Retrieving and displaying error records that were generated when the script was
run.
Example
This sample runs a script synchronously in the default runspace provided by Windows
PowerShell. The output of the script and any non-terminating errors that were
generated are displayed in a console window.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to use the PowerShell class to run a
/// process names passed to the script. It shows how to pass input
/// </summary>
/// <remarks>
/// 3. Passing input objects to the script from the calling program.
/// </remarks>
};
// building all of the other data structures needed to run the script.
powershell.AddScript(script);
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
// the script.
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace04 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Retrieving and displaying error records that were generated during the running of
the commands.
Example
This sample runs commands synchronously in the default runspace provided by
Windows PowerShell. The last command throws a terminating error because a
parameter argument that is not valid is passed to the command. The terminating error is
trapped and displayed.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to use a PowerShell object to run commands.
/// </summary>
/// <remarks>
/// 3. Passing input objects to the commands from the calling program.
/// 4. Using PSObject objects to extract and display properties from the
/// </remarks>
powershell.AddCommand("Get-ChildItem").AddCommand("Select-
String").AddArgument("*");
try
Console.WriteLine("'{0}'", result.ToString());
// Process any error records that were generated while running the
commands.
System.Console.WriteLine(
runtimeException.ErrorRecord.InvocationInfo.InvocationName,
runtimeException.Message,
runtimeException.ErrorRecord.InvocationInfo.PositionMessage);
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace05 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample creates a runspace that uses an
System.Management.Automation.Runspaces.Initialsessionstate object to define the
elements that are available when the runspace is opened. In this sample, a snap-in that
defines a Get-Proc cmdlet is added to the initial session state.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to define an initial session state that is
/// used when creating a runspace. The sample invokes a command from
/// </summary>
/// <remarks>
/// This sample assumes that user has coppied the GetProcessSample01.dll
/// directory.
/// </remarks>
// PowerShell.
PSSnapInException warning;
myRunSpace.Open();
powershell.AddCommand("GetProcPSSnapIn01\\get-proc");
powershell.Runspace = myRunSpace;
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace06 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample creates a runspace that uses an
System.Management.Automation.Runspaces.Initialsessionstate object to define the
elements that are available when the runspace is opened. In this sample, a module that
defines a Get-Proc cmdlet is added to the initial session state.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to define an initial session state that is
/// used when creating a runspace. The sample invokes a command from
/// </summary>
/// <remarks>
/// This sample assumes that user has coppied the GetProcessSample02.dll
/// directory.
/// </remarks>
// Create the default initial session state and add the module.
myRunSpace.Open();
powershell.AddCommand(@"GetProcessSample02\get-proc");
powershell.Runspace = myRunSpace;
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace07 Sample
Article • 09/17/2021
This sample shows how to create a runspace, and then use that runspace to run two
cmdlets synchronously by using a System.Management.Automation.Powershell object.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample creates a runspace that used by a
System.Management.Automation.PSObject object to run the Get-Process and Measure-
Object cmdlets.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to create a runspace and how to run commands
/// </summary>
/// <remarks>
/// </remarks>
myRunSpace.Open();
powershell.Runspace = myRunSpace;
using (powershell)
powershell.AddCommand("get-process");
// of the pipeline.
powershell.AddCommand("measure-object");
result = powershell.Invoke();
powershell = null;
// everything is ok first.
if (count == null)
Console.WriteLine(
count.Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace08 Sample
Article • 09/17/2021
This sample shows how to add commands and arguments to the pipeline of a
System.Management.Automation.Powershell object and how to run the commands
synchronously.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample runs the Get-Process and Sort-Object cmdlets by using a
System.Management.Automation.Powershell object.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to use a PowerShell object to run commands.
The
/// which is then piped to the sort-object cmdlet. Parameters are added
to the
/// </summary>
/// <remarks>
/// </remarks>
using (powershell)
powershell.AddCommand("get-process");
// in descending order.
powershell.AddCommand("sort-
object").AddParameter("descending").AddParameter("property", "handlecount");
results = powershell.Invoke();
powershell = null;
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace09 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample runs to run a script that generates the numbers from 1 to 10 with delays
between each number. The script is run asynchronously and events are used to handle
the output.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// is run asynchronously and events are used to handle the output.
/// </summary>
/// <remarks>
/// </remarks>
// Add the event handlers. If we did not care about hooking the
DataAdded
// event, we would let BeginInvoke create the output stream for us.
powershell.InvocationStateChanged += new
EventHandler<PSInvocationStateChangedEventArgs>
(Powershell_InvocationStateChanged);
// Wait for things to happen. If the user hits a key before the
// to halt processing.
Console.ReadKey();
if (powershell.InvocationStateInfo.State !=
PSInvocationState.Completed)
powershell.Stop();
System.Threading.Thread.Sleep(500);
Console.ReadKey();
/// <summary>
/// The output data added event handler. This event is called when
/// data is added to the output pipe. It reads the data that is
/// </summary>
Console.WriteLine(result.ToString());
/// <summary>
/// This event handler is called when the pipeline state is changed.
/// </summary>
if (e.InvocationStateInfo.State == PSInvocationState.Completed)
See Also
Writing a Windows PowerShell Host Application
Runspace10 Sample
Article • 09/17/2021
This sample shows how to create a default initial session state, how to add a cmdlet to
the System.Management.Automation.Runspaces.Initialsessionstate, how to create a
runspace that uses the initial session state, and how to run the command by using a
System.Management.Automation.Powershell object.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Example
This sample creates a runspace that uses an
System.Management.Automation.Runspaces.Initialsessionstate object to define the
elements that are available when the runspace is opened. In this sample, the Get-Proc
cmdlet (defined by the Host application) is added to the initial session state, and the
cmdlet is run synchronously by using a System.Management.Automation.Powershell
object.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
/// <summary>
/// For each of the requested process names, retrieve and write
/// </summary>
WriteObject(processes, true);
#endregion Overrides
#endregion GetProcCommand
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to create a default initial session state, how
to add
/// </summary>
// by Windows PowerShell.
iss.Commands.Add(ssce);
// See the Hosting samples for information on creating your own custom
host.
myRunSpace.Open();
powershell.Runspace = myRunSpace;
powershell.AddCommand("get-proc");
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Runspace11 Sample
Article • 09/17/2021
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
This sample demonstrates the following.
Creating a proxy function that calls the existing cmdlet, but exposes only a
restricted set of parameters.
Example
This creates a proxy command for a private cmdlet to demonstrate a constrained
runspace.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
#region GetProcCommand
/// <summary>
/// This class implements the get-proc cmdlet. It has been copied
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
} // if (processNames...
} // ProcessRecord
} // GetProcCommand
#endregion GetProcCommand
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This shows how to use the ProxyCommand class to create a proxy
/// command that calls an existing cmdlet, but restricts the set of
/// means that the user can access the cmdlet only through the proxy
/// command.
/// </summary>
/// <remarks>
/// 4. Creating a proxy function that calls the existing cmdlet, but
exposes
/// 7. Calling the private cmdlet and the proxy function to demonstrate
the
/// </remarks>
iss.Commands.Add(cmdletEntry);
cmdletEntry.Visibility = SessionStateEntryVisibility.Private;
iss.LanguageMode = PSLanguageMode.NoLanguage;
// get-proc cmdlet.
cmdletMetadata.Parameters.Remove("Name");
// Add the proxy function to the initial session state. The name of
the proxy
// function can be the same as the name of the cmdlet, but to clearly
iss.Commands.Add(new SessionStateFunctionEntry("get-procProxy",
bodyOfProxyFunction));
myRunspace.Open();
try
powershell.Runspace = myRunspace;
powershell.AddCommand("get-proc").AddParameter("Name",
"*explore*");
powershell.Invoke();
catch (CommandNotFoundException e)
System.Console.WriteLine(
e.GetType().FullName,
e.Message);
// not available.
try
powershell.Runspace = myRunspace;
powershell.AddCommand("get-procProxy").AddParameter("Name",
"idle");
powershell.Invoke();
catch (ParameterBindingException e)
System.Console.WriteLine(
e.GetType().FullName,
e.Message);
powershell.Runspace = myRunspace;
powershell.AddCommand("get-procProxy");
System.Console.WriteLine(
processes.Count);
myRunspace.Close();
System.Console.ReadKey();
See Also
Writing a Windows PowerShell Host Application
Remote Runspace Samples
Article • 09/17/2021
This section includes sample code that shows how to create runspaces that can be used
to connect to
a computer by using WS-Management-based Windows PowerShell
remoting. You can use Microsoft Visual
Studio to create a console application and then
copy the code from the topics in this section into
your host application.
In This Section
7 Note
This sample shows how to create a remote runspace that is used to establish a remote
connection.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a System.Management.Automation.Runspaces.Wsmanconnectioninfo
object.
Setting the
System.Management.Automation.Runspaces.Runspaceconnectioninfo.Operationti
meout* and
System.Management.Automation.Runspaces.Runspaceconnectioninfo.Opentimeou
t* properties of the
System.Management.Automation.Runspaces.Wsmanconnectioninfo object.
Example
This sample defines a remote connection and then uses that connection information to
establish a remote connection.
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
/// <summary>
/// </summary>
// for any operation. This includes sending input data to the remote
computer,
// receiving output data from the remote computer, and more. The user
can
remoteRunspace.Open();
// Add the code to run commands in the remote runspace here. The
// Close the connection. Call the Close() method to close the remote
remoteRunspace.Close();
RemoteRunspacePool01 Sample
Article • 09/17/2021
This sample shows how to construct a remote runspace pool and how to run multiple
commands concurrently by using this pool.
Requirements
This sample requires Windows PowerShell 2.0.
Demonstrates
Creating a System.Management.Automation.Runspaces.Wsmanconnectioninfo
object.
Setting the
System.Management.Automation.Runspaces.Runspaceconnectioninfo.Operationti
meout* and
System.Management.Automation.Runspaces.Runspaceconnectioninfo.Opentimeou
t* properties of the
System.Management.Automation.Runspaces.Wsmanconnectioninfo object.
Example
This sample shows how to construct a remote runspace pool and how to run multiple
commands concurrently by using this pool.
C#
namespace Samples
using System;
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
/// <summary>
/// This sample shows how to construct a remote RunspacePool and how to
/// concurrently run the get-process and get-service commands using the
/// </summary>
RunspaceFactory.CreateRunspacePool(1, 2, connectionInfo))
// Call the Open() method to open the runspace pool and establish
// the connection.
remoteRunspacePool.Open();
gpsCommand.RunspacePool = remoteRunspacePool;
// The previous call does not block the current thread because it is
getServiceCommand.RunspacePool = remoteRunspacePool;
IAsyncResult getServiceCommandAsyncResult =
getServiceCommand.BeginInvoke();
// When you are ready to handle the output, wait for the command to
complete
// the output.
PSDataCollection<PSObject> gpsCommandOutput =
gpsCommand.EndInvoke(gpsCommandAsyncResult);
Console.WriteLine(
gpsCommandOutput[0].Properties["ProcessName"].Value,
gpsCommandOutput[0].Properties["Id"].Value);
Console.WriteLine();
PSDataCollection<PSObject> getServiceCommandOutput =
getServiceCommand.EndInvoke(
getServiceCommandAsyncResult);
Console.WriteLine(
getServiceCommandOutput[0].Properties["ServiceName"].Value,
getServiceCommandOutput[0].Properties["DisplayName"].Value,
getServiceCommandOutput[0].Properties["Status"].Value);
// Once done with running all the commands, close the remote
runspace pool.
} // End Using.
} // End Main.
See Also
Formatting File Overview
Article • 03/13/2023
The display format for the objects that are returned by commands (cmdlets, functions,
and scripts)
are defined by using formatting files (format.ps1xml files). Several of these
files are provided by
PowerShell to define the display format for those objects returned
by PowerShell-provided commands,
such as the System.Diagnostics.Process object
returned by the Get-Process cmdlet. However,
you can also create your own custom
formatting files to overwrite the default display formats or you
can write a custom
formatting file to define the display of objects returned by your own commands.
) Important
Formatting files do not determine the elements of an object that are returned to
the pipeline.
When an object is returned to the pipeline, all members of that object
are available even if some
are not displayed.
PowerShell uses the data in these formatting files to determine what is displayed and
how the
displayed data is formatted. The displayed data can include the properties of an
object or the value
of a script. Scripts are used if you want to display some value that is
not available directly from
the properties of an object, such as adding the value of two
properties of an object and then
displaying the sum as a piece of data. Formatting of
the displayed data is done by defining views
for the objects that you want to display.
You can define a single view for each object, you can
define a single view for multiple
objects, or you can define multiple views for the same object.
There is no limit to the
number of views that you can define.
Default configuration setting, such as whether the data displayed in the rows of
tables will be
displayed on the next line if the data is longer than the width of the
column. For more
information about these settings, see Wrap Element for
TableRowEntry.
Sets of objects that can be displayed by any of the views of the formatting file. For
more
information about these sets (referred to as selection sets), see
Defining Sets
of Objects.
Common controls that can be used by all the views of the formatting file. Controls
give you finer
control on how data is displayed. For more information about
controls, see
Defining Custom Controls.
Formatting Views
Formatting views can display objects in a table format, list format, wide format, and
custom format.
For the most part, each formatting definition is described by a set of
XML tags that describe the
view. Each view contains the name of the view, the objects
that use the view, and the elements of
the view, such as the column and row
information for a table view.
Table View
Lists the properties of an object or a script block value in one or more columns. Each
column
represents a single property of the object or a script value. You can define a
table view that
displays all the properties of an object, a subset of the properties of an
object, or a combination
of properties and script values. Each row of the table
represents a returned object. Creating a
table view is very similar to when you pipe an
object to the Format-Table cmdlet. For more
information about this view, see Table
View.
List View
Lists the properties of an object or a script value in a single column. Each row of the list
displays an optional label or the property name followed by the value of the property or
script.
Creating a list view is very similar to piping an object to the Format-List cmdlet.
For more
information about this view, see List View.
Wide View
Lists a single property of an object or a script value in one or more columns. There is no
label or
header for this view. Creating a wide view is very similar to piping an object to
the Format-Wide
cmdlet. For more information about this view, see Wide View.
Custom View
Displays a customizable view of object properties or script values that does not adhere
to the rigid
structure of table views, list views, or wide views. You can define a stand-
alone custom view, or
you can define a custom view that is used by another view, such
as a table view or list view.
Creating a custom view is very similar to piping an object to
the Format-Custom cmdlet. For more
information about this view, see Custom View.
Components of a View
The following XML examples show the basic XML components of a view. The individual
XML elements vary
depending on which view you want to create, but the basic
components of the views are all the same.
To start with, each view has a Name element that specifies a user friendly name that is
used to
reference the view. a ViewSelectedBy element that defines which .NET objects
are displayed by the
view, and a control element that defines the view.
XML
<ViewDefinitions>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<ListControl>...</ListControl>
<View>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<WideControl>...</WideControl>
<View>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<CustomControl>...</CustomControl>
</View>
</ViewDefinitions>
Within the control element, you can define one or more entry elements. If you use
multiple
definitions, you must specify which .NET objects use each definition. Typically
only one entry, with
only one definition, is needed for each control.
XML
<ListControl>
<ListEntries>
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
Within each entry element of a view, you specify the item elements that define the .NET
properties or scripts that are displayed by that view.
XML
<ListItems>
<ListItem>...</ListItem>
<ListItem>...</ListItem>
<ListItem>...</ListItem>
</ListItems>
As shown in the preceding examples, the formatting file can contain multiple views, a
view can
contain multiple definitions, and each definition can contain multiple items.
XML
<ViewDefinitions>
<View>
<Name>Name of View</Name>
<ViewSelectedBy>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
</TableColumnItem>
<TableColumnItem>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
See Also
Creating a List View
The topics in this section provide information that you might need to know when
creating your own
formatting files, such as the different types of views that you can
define and the special
components of those views.
In This Section
Creating a Table View
Provides an example of a displayed table view and the XML
elements used to define the view.
A table view displays data in one or more columns. Each row in the table represents a
.NET object, and each column of the table represents a property of the object or a script
value. You can define a table view that displays all the properties of an object or a subset
of the properties of an object.
ServiceName property), and the DisplayName property. Each row in the table represents
Output
XML
<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width>8</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>18</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>38</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Status</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
The View element is the parent element of the table view. (This is the same parent
element for the list, wide, and custom control views.)
The Name element specifies the name of the view. This element is required for all
views.
The ViewSelectedBy element defines the objects that use the view. This element is
required.
The GroupBy element (not shown in this example) defines when a new group of
objects is displayed. A new group is started whenever the value of a specific
property or script changes. This element is optional.
The Controls element (not shown in this example) defines the custom controls that
are defined by the table view. Controls give you a way to further specify how the
data is displayed. This element is optional. A view can define its own custom
controls, or it can use common controls that can be used by any view in the
formatting file. For more information about custom controls, see Creating Custom
Controls.
The HideTableHeaders element (not show in this example) specifies that the table
will not show any labels at the top of the table. This element is optional.
The TableControl element that defines the header and row information of the
table. Similar to all other views, a table view can display the values of object
properties or values generated by scripts.
There is no limit to the number of these element that you can use, but the number
of TableColumnHeader elements in your table view must equal the number of
TableRowEntry elements that you use.
3. The Label element specifies the text that is displayed. This element is optional.
4. The Width element specifies the width (in characters) of the column. This element
is optional.
5. The Alignment element specifies how the label is displayed. The label can be
aligned to the left, to the right, or centered. This element is optional.
In the following example, the view provides a single definition that displays the values of
several properties of the System.Diagnostics.Process?Displayproperty=Fullname object.
A table view can display the value of a property or the value of a script (not shown in the
example) in its rows.
XML
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Status</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
The following XML elements can be used to provide definitions for a row:
The TableRowEntries element and its child elements define what is displayed in the
rows of the table.
The EntrySelectedBy element specifies the objects that are displayed by a specific
definition. This element is optional and is needed only when you define multiple
TableRowEntry elements that display different objects.
The Wrap element specifies that text that exceeds the column width is displayed
on the next line. By default, text that exceeds the column width is truncated.
The TableColumnItems element defines the properties or scripts whose values are
displayed in the row.
The PropertyName element specifies the property whose value is displayed in the
row. You must specify either a property or a script, but you cannot specify both.
The ScriptBlock element specifies the script whose value is displayed in the row.
You must specify either a script or a property, but you cannot specify both.
The FormatString element specifies a format pattern that defines how the property
or script value is displayed. This element is optional.
The Alignment element specifies how the value of the property or script is
displayed. The value can be aligned to the left, to the right, or centered. This
element is optional.
The following example shows how to define the objects that are displayed by the table
view using the ViewSelectedBy and TypeName elements. There is no limit to the number
of TypeName elements that you can specify, and their order is not significant.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
The following XML elements can be used to specify the objects that are used by the
table view:
The ViewSelectedBy element defines which objects are displayed by the list view.
The TypeName element specifies the .NET object that is displayed by the view. The
fully qualified .NET type name is required. You must specify at least one type or
selection set for the view, but there is no maximum number of elements that can
be specified.
The following example uses the ViewSelectedBy and SelectionSetName elements. Use
selection sets where you have a related set of objects that are displayed using multiple
views, such as when you define a list view and a table view for the same objects. For
more information about how to create a selection set, see Defining Selection Sets.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
The following XML elements can be used to specify the objects that are used by the list
view:
The ViewSelectedBy element defines which objects are displayed by the list view.
The following example shows how to define the objects displayed by a specific
definition of the table view using the EntrySelectedBy element. Using this element, you
can specify the .NET type name of the object, a selection set of objects, or a selection
condition that specifies when the definition is used. For more information about how to
create a selection conditions, see Defining Conditions for Displaying Data.
7 Note
When creating multiple definitions of the table view you cannot specify different
column headers. You can specify only what is displayed in the rows of the table,
such as what objects are displayed.
XML
<TableRowEntry>
<EntrySelectedBy>
<TypeName>.NET Type</TypeName>
</EntrySelectedBy>
</TableRowEntry>
The following XML elements can be used to specify the objects that are used by a
specific definition of the list view:
The EntrySelectedBy element defines which objects are displayed by the definition.
The TypeName element specifies the .NET object that is displayed by the definition.
When using this element, the fully qualified .NET type name is required. You must
specify at least one type, selection set, or selection condition for the definition, but
there is no maximum number of elements that can be specified.
The SelectionSetName element (not shown) specifies a set of objects that can be
displayed by this definition. You must specify at least one type, selection set, or
selection condition for the definition, but there is no maximum number of
elements that can be specified.
The SelectionCondition element (not shown) specifies a condition that must exist
for this definition to be used. You must specify at least one type, selection set, or
selection condition for the definition, but there is no maximum number of
elements that can be specified. For more information about defining selection
conditions, see Defining Conditions for Displaying Data.
XML
<TableColumnItem>
<PropertyName>StartTime</PropertyName>
</TableColumnItem>
The PropertyName element specifies the property whose value is displayed in the
row. You must specify either a property or a script, but you cannot specify both.
The FormatString element specifies a format pattern that defines how the property
or script value is displayed.
In the following example, the ToString method is called to format the value of the
script. Scripts can call any method of an object. Therefore, if an object has a method,
such as ToString , that has formatting parameters, the script can call that method to
format the output value of the script.
XML
<ListItem>
<ScriptBlock>
</ScriptBlock>
</ListItem>
The following XML element can be used to calling the ToString method:
The ScriptBlock element specifies the script whose value is displayed in the row.
You must specify either a script or a property, but you cannot specify both.
See Also
Writing a PowerShell Formatting File
Creating a List View
Article • 01/20/2022
A list view displays data in a single column (in sequential order). The data displayed in
the list can be the value of a .NET property or the value of a script.
PowerShell
Get-Service | format-list
Output
Name : AEADIFilters
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess
Name : AeLookupSvc
DisplayName : Application Experience
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32ShareProcess
Name : AgereModemAudio
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess
...
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
The View element is the parent element of the list view. (This is the same parent
element for the table, wide, and custom control views.)
The Name element specifies the name of the view. This element is required for all
views.
The ViewSelectedBy element defines the objects that use the view. This element is
required.
The GroupBy element defines when a new group of objects is displayed. A new
group is started whenever the value of a specific property or script changes. This
element is optional.
The Controls element defines the custom controls that are defined by the list view.
Controls give you a way to further specify how the data is displayed. This element
is optional. A view can define its own custom controls, or it can use common
controls that can be used by any view in the formatting file. For more information
about custom controls, see Creating Custom Controls.
The ListControl element defines what is displayed in the view and how it is
formatted. Similar to all other views, a list view can display the values of object
properties or values generated by script.
For an example of a complete formatting file that defines a simple list view, see List View
(Basic).
XML
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
The following XML elements can be used to provide definitions for a list view:
The ListControl element and its child elements define what is displayed in the view.
The ListEntries element provides the definitions of the view. In most cases, a view
will have only one definition. This element is required.
The ListEntry element provides a definition of the view. At least one ListEntry is
required; however, there is no maximum limit to the number of elements that you
can add. In most cases, a view will have only one definition.
The EntrySelectedBy element specifies the objects that are displayed by a specific
definition. This element is optional and is needed only when you define multiple
ListEntry elements that display different objects.
The ListItems element specifies the properties and scripts whose values are
displayed in the rows of the list view.
The PropertyName element specifies the property whose value is displayed in the
row. You must specify either a property or a script, but you cannot specify both.
The ScriptBlock element specifies the script whose value is displayed in the row.
You must specify either a script or a property, but you cannot specify both.
The Label element specifies the label that is displayed to the left of the property or
script value in the row. This element is optional. If a label is not specified, the name
of the property or the script is displayed. For a complete example, see List View
(Labels).
The ItemSelectionCondition element specifies a condition that must exist for the
row to be displayed. For more information about adding conditions to the list view,
see Defining Conditions for Displaying Data. This element is optional.
The FormatString element specifies a pattern that is used to display the value of
the property or script. This element is optional.
For an example of a complete formatting file that defines a simple list view, see List View
(Basic).
Defining the Objects That Use the List View
There are two ways to define which .NET objects use the list view. You can use the
ViewSelectedBy element to define the objects that can be displayed by all the
definitions of the view, or you can use the EntrySelectedBy element to define which
objects are displayed by a specific definition of the view. In most cases, a view has only
one definition, so objects are typically defined by the ViewSelectedBy element.
The following example shows how to define the objects that are displayed by the list
view using the ViewSelectedBy and TypeName elements. There is no limit to the number
of TypeName elements that you can specify, and their order is not significant.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>
The following XML elements can be used to specify the objects that are used by the list
view:
The ViewSelectedBy element defines which objects are displayed by the list view.
The TypeName element specifies the .NET object that is displayed by the view. The
fully qualified .NET type name is required. You must specify at least one type or
selection set for the view, but there is no maximum number of elements that can
be specified.
The following example uses the ViewSelectedBy and SelectionSetName elements. Use
selection sets where you have a related set of objects that are displayed using multiple
views, such as when you define a list view and a table view for the same objects. For
more information about how to create a selection set, see Defining Selection Sets.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>
The following XML elements can be used to specify the objects that are used by the list
view:
The ViewSelectedBy element defines which objects are displayed by the list view.
The following example shows how to define the objects displayed by a specific
definition of the list view using the EntrySelectedBy element. Using this element, you can
specify the .NET type name of the object, a selection set of objects, or a selection
condition that specifies when the definition is used. For more information about how to
create a selection conditions, see Defining Conditions for Displaying Data.
XML
<ListEntry>
<EntrySelectedBy>
<TypeName>.NET Type</TypeName>
</EntrySelectedBy>
</ListEntry>
The following XML elements can be used to specify the objects that are used by a
specific definition of the list view:
The EntrySelectedBy element defines which objects are displayed by the definition.
The TypeName element specifies the .NET object that is displayed by the definition.
When using this element, the fully qualified .NET type name is required. You must
specify at least one type, selection set, or selection condition for the definition, but
there is no maximum number of elements that can be specified.
The SelectionSetName element (not shown) specifies a set of objects that can be
displayed by this definition. You must specify at least one type, selection set, or
selection condition for the definition, but there is no maximum number of
elements that can be specified.
The SelectionCondition element (not shown) specifies a condition that must exist
for this definition to be used. You must specify at least one type, selection set, or
selection condition for the definition, but there is no maximum number of
elements that can be specified. For more information about defining selection
conditions, see Defining Conditions for Displaying Data.
XML
<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>
The following XML elements are used to define when a group is started:
The GroupBy element defines the property or script that starts the new group and
defines how the group is displayed.
The PropertyName element specifies the property that starts a new group
whenever its value changes. You must specify a property or script to start the
group, but you cannot specify both.
The ScriptBlock element specifies the script that starts a new group whenever its
value changes. You must specify a script or property to start the group, but you
cannot specify both.
The Label element defines a label that is displayed at the beginning of each group.
In addition to the text specified by this element, Windows PowerShell displays the
value that triggered the new group and adds a blank line before and after the
label. This element is optional.
The CustomControl element defines a control that is used to display the data. This
element is optional.
XML
<ListItem>
<PropertyName>StartTime</PropertyName>
</ListItem>
The ListItem element specifies the data that is displayed by the view.
The PropertyName element specifies the property whose value is displayed by the
view. You must specify either a property or a script, but you cannot specify both.
The FormatString element specifies a format pattern that defines how the property
or script value is displayed in the view.
The ScriptBlock element (not shown) specifies the script whose value is displayed
by the view. You must specify either a script or a property, but you cannot specify
both.
In the following example, the ToString method is called to format the value of the
script. Scripts can call any method of an object. Therefore, if an object has a method,
such as ToString , that has formatting parameters, the script can call that method to
format the output value of the script.
XML
<ListItem>
<ScriptBlock>
</ScriptBlock>
</ListItem>
The following XML element can be used to calling the ToString method:
The ListItem element specifies the data that is displayed by the view.
The ScriptBlock element (not shown) specifies the script whose value is displayed
by the view. You must specify either a script or a property, but you cannot specify
both.
See Also
Writing a Windows PowerShell Cmdlet
Creating a Wide View
Article • 03/13/2023
A wide view displays a single value for each object that's displayed. The displayed value
can be the
value of a .NET object property or the value of a script. By default, there is no
label or header
for this view.
PowerShell
Get-Process | format-wide
Output
AEADISRV agrsmsvc
Ati2evxx Ati2evxx
audiodg CCC
CcmExec communicator
Crypserv csrss
csrss DevDtct2
DM1Service dpupdchk
dwm DxStudio
EXCEL explorer
GoogleToolbarNotifier GrooveMonitor
hpqwmiex hpservice
Idle InoRpc
InoRT InoTask
ipoint lsass
lsm MOM
MSASCui notepad
... ...
XML
<View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<GroupBy>...</GroupBy>
<Controls>...</Controls>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
The View element is the parent element of the wide view. (This is the same parent
element
for the table, list, and custom control views.)
The Name element specifies the name of the view. This element is required for all
views.
The ViewSelectedBy element defines the objects that use the view. This element is
required.
The GroupBy element defines when a new group of objects is displayed. A new
group is started
whenever the value of a specific property or script changes. This
element is optional.
The Controls elements defines the custom controls that are defined by the wide
view.
Controls give you a way to further specify how the data is displayed. This
element is optional. A
view can define its own custom controls, or it can use
common controls that can be used by any
view in the formatting file. For more
information about custom controls, see
Creating Custom Controls.
The WideControl element and its child elements define what's displayed in the
view. In the
preceding example, the view is designed to display the
System.Diagnostics.Process.ProcessName property.
For an example of a complete formatting file that defines a simple wide view, see
Wide
View (Basic).
Providing Definitions for Your Wide View
Wide views can provide one or more definitions by using the child elements of the
WideControl
element. Typically, a view will have only one definition. In the following
example, the view
provides a single definition that displays the
System.Diagnostics.Process.ProcessName
property. A wide view can display the value of
a property or the value of a script (not shown in the
example).
XML
<WideControl>
<AutoSize/>
<ColumnNumber></ColumnNumber>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
The following XML elements can be used to provide definitions for a wide view:
The WideControl element and its child elements define what's displayed in the
view.
The AutoSize element specifies whether the column size and the number of
columns are
adjusted based on the size of the data. This element is optional.
The ColumnNumber element specifies the number of columns displayed in the
wide view. This
element is optional.
The WideEntries element provides the definitions of the view. In most cases, a view
will
have only one definition. This element is required.
The WideEntry element provides a definition of the view. At least one WideEntry is
required; however, there is no maximum limit to the number of elements that you
can add. In most
cases, a view will have only one definition.
The EntrySelectedBy element specifies the objects that are displayed by a specific
definition. This element is optional and is needed only when you define multiple
WideEntry
elements that display different objects.
The WideItem element specifies the data that's displayed by the view. In contrast
to other
types of views, a wide control can display only one item.
The PropertyName element specifies the property whose value is displayed by the
view. You
must specify either a property or a script, but you can't specify both.
The ScriptBlock element specifies the script whose value is displayed by the view.
You must
specify either a script or a property, but you can't specify both.
The FormatString element specifies a pattern that's used to display the data. This
element
is optional.
For an example of a complete formatting file that defines a wide view definition, see
Wide View (Basic).
The following example shows how to define the objects that are displayed by the wide
view using the
ViewSelectedBy and TypeName elements. There is no limit to the number
of TypeName
elements that you can specify, and their order isn't significant.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<WideControl>...</WideControl>
</View>
The following XML elements can be used to specify the objects that are used by the
wide view:
The ViewSelectedBy element defines which objects are displayed by the wide view.
The TypeName element specifies the .NET that's displayed by the view. The fully
qualified
.NET type name is required. You must specify at least one type or
selection set for the view, but
there is no maximum number of elements that can
be specified.
The following example uses the ViewSelectedBy and SelectionSetName elements. Use
selection sets where you have a related set of objects that are displayed using multiple
views, such
as when you define a wide view and a table view for the same objects. For
more information about how
to create a selection set, see Defining Selection Sets.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
</ViewSelectedBy>
<WideControl>...</WideControl>
</View>
The following XML elements can be used to specify the objects that are used by the
wide view:
The ViewSelectedBy element defines which objects are displayed by the wide view.
The SelectionSetName element specifies a set of objects that can be displayed by
the view.
You must specify at least one selection set or type for the view, but there
is no maximum number
of elements that can be specified.
The following example shows how to define the objects displayed by a specific
definition of the wide
view using the EntrySelectedBy element. Using this element, you
can specify the .NET type name
of the object, a selection set of objects, or a selection
condition that specifies when the
definition is used. For more information about how to
create a selection conditions, see
Defining Conditions for Displaying Data.
XML
<WideEntry>
<EntrySelectedBy>
<TypeName>.NET Type</TypeName>
</EntrySelectedBy>
</WideEntry>
The following XML elements can be used to specify the objects that are used by a
specific definition
of the wide view:
The EntrySelectedBy element defines which objects are displayed by the definition.
The TypeName element specifies the .NET that's displayed by the definition. When
using this
element the fully qualified .NET type name is required. You must specify
at least one type,
selection set, or selection condition for the definition, but there is
no maximum number of
elements that can be specified.
The SelectionSetName element (not shown) specifies a set of objects that can be
displayed by
this definition. You must specify at least one type, selection set, or
selection condition for the
definition, but there is no maximum number of
elements that can be specified.
The SelectionCondition element (not shown) specifies a condition that must exist
for this
definition to be used. You must specify at least one type, selection set, or
selection condition
for the definition, but there is no maximum number of
elements that can be specified. For more
information about defining selection
conditions, see
Defining Conditions for Displaying Data.
XML
<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>
The following XML elements are used to define when a group is started:
The GroupBy element defines the property or script that starts the new group and
defines how
the group is displayed.
The PropertyName element specifies the property that starts a new group
whenever its value
changes. You must specify a property or script to start the
group, but you can't specify both.
The ScriptBlock element specifies the script that starts a new group whenever its
value
changes. You must specify a script or property to start the group, but you
can't specify both.
The Label element defines a label that's displayed at the beginning of each group.
In
addition to the text specified by this element, Windows PowerShell displays the
value that
triggered the new group and adds a blank line before and after the
label. This element is
optional.
The CustomControl element defines a control that's used to display the data. This
element is
optional.
The CustomControlName element specifies a common or view control that's used
to display the
data. This element is optional.
For an example of a complete formatting file that defines groups, see Wide View
(GroupBy).
XML
<WideItem>
<PropertyName>StartTime</PropertyName>
</WideItem>
The WideItem element specifies the data that's displayed by the view.
The PropertyName element specifies the property whose value is displayed by the
view. You
must specify either a property or a script, but you can't specify both.
The FormatString element specifies a format pattern that defines how the property
or script
value is displayed in the view
The ScriptBlock element (not shown) specifies the script whose value is displayed
by the
view. You must specify either a script or a property, but you can't specify
both.
In the following example, the ToString method is called to format the value of the
script. Scripts
can call any method of an object. Therefore, if an object has a method,
such as ToString , that has
formatting parameters, the script can call that method to
format the output value of the script.
XML
<WideItem>
<ScriptBlock>
</ScriptBlock>
</WideItem>
The following XML element can be used to calling the ToString method:
The WideItem element specifies the data that's displayed by the view.
The ScriptBlock element (not shown) specifies the script whose value is displayed
by the
view. You must specify either a script or a property, but you can't specify
both.
See Also
Wide View (Basic)
Wide View (GroupBy)
Writing a PowerShell Formatting File
Creating Custom Controls
Article • 09/17/2021
Custom controls are the most flexible components of a formatting file. Unlike table, list,
and wide views that define a formal structure of data, such as a table of data, custom
controls allow you to define how an individual piece of data is displayed. You can define
a common set of custom controls that are available to all the views of the formatting
file, you can define custom controls that are available to a specific view, or you can
define a set of controls that are available to a group of objects.
XML
<Controls>
<Control>
<Name>SignatureTypes-GroupingFormat</Name>
<CustomControl>
<CustomEntries>
<CustomEntry>
<CustomItem>
<Frame>
<LeftIndent>4</LeftIndent>
<CustomItem>
<Text AssemblyName="System.Management.Automation"
BaseName="FileSystemProviderStrings"
ResourceId="DirectoryDisplayGrouping"/>
<ExpressionBinding>
<ScriptBlock>split-path $_.Path</ScriptBlock>
</ExpressionBinding>
<NewLine/>
</CustomItem>
</Frame>
</CustomItem>
</CustomEntry>
</CustomEntries>
</CustomControl>
</Control>
</Controls>
See Also
Writing a PowerShell Formatting File
Loading and Exporting Formatting Data
Article • 03/07/2023
Once you've created your formatting file, you need to update the format data of the
session by
loading your files into the current session. PowerShell loads a predefined set
of formats. Once the
format data of the current session is updated, PowerShell uses that
data to display the .NET objects
associated with the views defined in the loaded formats.
There's no limit to the number of formats
that you can load into the current session. You
can also export the format data in the current
session back to a formatting file.
You can import the formatting file into the current session from the command line.
Use the
Update-FormatData cmdlet as described in the following procedure.
You can create a module manifest that references your formatting file. Modules
allow you to
package your formatting files for distribution. Use the New-
ModuleManifest cmdlet to create
the manifest, and the Import-Module cmdlet to
load the module into the current session. For
more information about modules,
see Writing a Windows PowerShell Module.
You can create a snap-in that references your formatting file. Use the
System.Management.Automation.PSSnapIn.Formats to reference your formatting
files. However,
best practice recommendation is to use modules to package
cmdlets and associated formatting and
types files.
If you're invoking commands programmatically, you can add formatting files to the
initial session
state of the runspace where the commands are run. For more
information, see the
System.Management.Automation.Runspaces.SessionStateFormatEntry class.
When a formatting file is loaded, it's added to an internal list that PowerShell uses to
choose the
view used when displaying objects in the host. You can prepend your
formatting file to the beginning
of the list, or you can append it to the end of the list.
If you're loading a formatting file that defines the only view for an object, you can
use any of
the methods described previously.
If you're loading a formatting file that defines a view for an object that has an
existing view
defined, it must be added to the beginning of the list. You must use
the Update-FormatData
cmdlet and prepend your file to the beginning of the list.
Use the following command to determine the location of your profile script.
PowerShell
If you're changing how an object is displayed, use the following command to add
your formatting
file to the front of the list.
PowerShell
Use the following command to add your formatting file to the end of the list.
PowerShell
7 Note
Once format data has been loaded in a session it can't be removed. You must
open a new session
without the format data loaded.
The following commands export the format data for the System.Guid type to a file
named
System.Guid.format.ps1xml in the current directory.
PowerShell
Get-Content ./System.Guid.format.ps1xml
Output
<Configuration>
<ViewDefinitions>
<View>
<Name>System.Guid</Name>
<ViewSelectedBy>
<TypeName>System.Guid</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders />
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Guid</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>
</Configuration>
You can edit the exported file create a custom format definition for that type.
Defining Selection Sets
Article • 09/17/2021
When creating multiple views and controls, you can define sets of objects that are
referred to as
selection sets. A selection set enables you to define the objects one time,
without having to define
them repeatedly for each view or control. Typically, selection
sets are used when you have a set of
related .NET objects. For example, The FileSystem
formatting file (FileSystem.format.ps1xml)
defines a selection set of the file system types
that several views use.
XML
<Configuration>
<SelectionSets>
<SelectionSet>...</SelectionSet>
<SelectionSet>...</SelectionSet>
<SelectionSet>...</SelectionSet>
</SelectionSets>
</Configuration>
Each view has a ViewSelectedBy element that defines which objects are displayed
by using the
view. The ViewSelectedBy element has a SelectionSetName child
element that specifies the
selection set that all the definitions of the view use.
There is no restriction on the number of
selection sets that you can reference from
a view.
XML
<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>
The previous selection set is referenced in the ViewSelectedBy element of a table view.
XML
<ViewDefinitions>
<View>
<Name>Files</Name>
<ViewSelectedBy>
<SelectionSetName>FileSystemTypes</SelectionSetName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
</ViewDefinitions>
XML Elements
There is no limit to the number of selection sets that you can define. The following XML
elements
are used to create a selection set.
The following element specifies the selection set to use in all the definitions of the
view:
The following elements specify the selection set used by a single view definition:
The following elements specify the selection set used by common and view control
definitions:
The following elements specify the selection set used when you define which
object to expand:
SelectionSetName Element for EntrySelectedBy for EnumerableExpansion
(Format)
The following elements specify the selection set used by selection conditions.
SelectionSetName Element for SelectionCondition for Controls for
Configuration (Format)
See Also
SelectionSets
SelectionSet
Name
Types
When defining what data is displayed by a view or a control, you can specify a condition
that must
exist for the data to be displayed. The condition can be triggered by a specific
property, or when a
script or property value evaluates to true . When the selection
condition is met, the definition of
the view or control is used.
XML
<TableRowEntry>
<EntrySelectedBy>
<SelectionCondition>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
</EntrySelectedBy>
<TableColumnItems>
</TableColumnItems>
</TableRowEntry>
There is no limit to the number of selection conditions that you can specify for a
definition of a
view or control. The only requirements are the following:
The selection condition must specify one property name or script to trigger the
condition, but
cannot specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
XML
<ListItem>
<ItemSelectionCondition>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
</ListItem>
You can specify only one selection condition for an item. And the condition must specify
one
property name or script to trigger the condition, but cannot specify both.
XML Elements
The following XML elements are used to create a selection condition.
The following elements specify selection conditions for common and view control
definitions:
The following element specifies the selection condition for expanding collection
objects:
SelectionCondition Element for EntrySelectedBy for EnumerableExpansion
(Format)
The following element specifies the selection condition for displaying a new group
of data:
SelectionCondition Element for EntrySelectedBy for GroupBy (Format)
The following element specifies an item selection condition for a list view:
ItemSelectionCondition Element for ListItem for ListControl (Format)
See Also
Writing a PowerShell Formatting File
Formatting Displayed Data
Article • 03/13/2023
You can specify how the individual data points in your List, Table, or Wide view are
displayed. You
can use the FormatString element when defining the items of your view,
or you can use the
ScriptBlock element to call the FormatString method on the data.
XML
<TableColumnItem>
<PropertyName>TotalProcessorTime</PropertyName>
<FormatString>{0:MMM}{0:dd}{0:HH}:{0:mm}</FormatString>
</TableColumnItem>
Windows PowerShell provides several formatting files (.format.ps1xml) that are located
in the
installation directory ( $pshome ). Each of these files defines the default display for a
specific
set of .NET objects. These files should never be changed. However, you can use
them as a reference
for creating your own custom formatting files.
x.509
certificates and certificate stores.
CultureInfo,
FileVersionInfo, and EventLogEntry objects.
FileSystem.Format.ps1xml Defines the display of file system objects such as file and
directory
objects.
Registry.Format.ps1xml Defines the display of registry objects such as key and entry
objects.
See Also
Writing a Windows PowerShell Cmdlet
How to Create a Formatting File
(.format.ps1xml)
Article • 09/17/2021
7 Note
You can also create a formatting file by making a copy of one of the files provided
by Windows
PowerShell. If you make a copy of an existing file, delete the existing
digital signature, and add
your own signature to the new file.
XML
<Configuration>
<ViewDefinitions>
</ViewDefinitions>
</Configuration>
3. Save the file to the Windows PowerShell installation folder, to your module folder,
or to a
subfolder of the module folder. Use the following name format when you
save the file:
MyFile.format.ps1xml . Formatting files must use the .format.ps1xml
extension.
You are now ready to add views to the formatting file. There is no limit to the
number of views
that can be defined in a formatting file. You can add a single view
for each object, multiple
views for the same object, or a single view that is used by
multiple objects.
See Also
Writing a Windows PowerShell Formatting and Types File
Wide View (Basic)
Article • 09/17/2021
This example shows how to implement a basic wide view that displays the
System.Serviceprocess.Servicecontroller?Displayproperty=Fullname
objects returned by
the Get-Service cmdlet. For more information about the components of a wide
view,
see Creating a Wide View.
2. Save the text file. Be sure to add the format.ps1xml extension to the file to identify
it as a
formatting file.
3. Open Windows PowerShell, and run the following command to load the formatting
file into the
current session: Update-FormatData -PrependPath
<PathToFormattingFile> .
2 Warning
This formatting file defines the display of an object that is already defined by
a Windows
PowerShell formatting file. You must use the PrependPath
parameter when you run the cmdlet,
and you cannot load this formatting file
as a module.
Demonstrates
This formatting file demonstrates the following XML elements:
The ViewSelectedBy element that defines what objects are displayed by the view.
The WideItem element that defines what property is displayed by the view.
Example
The following XML defines a wide view that displays the value of the
System.Serviceprocess.Servicecontroller.Servicename property.
XML
<Configuration>
<ViewDefinitions>
<View>
<Name>ServiceWideView</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ServiceName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
</ViewDefinitions>
</Configuration>
PowerShell
Get-Service f*
Output
Fax FCSAM
fdPHost FDResPub
FontCache FontCache3.0.0.0
FSysAgent FwcAgent
See Also
Examples of Formatting Files
This example shows how to implement a wide view that displays groups of
System.Serviceprocess.Servicecontroller?Displayproperty=Fullname
objects returned by
the Get-Service cmdlet. For more information about the components of a wide
view,
see Creating a Wide View.
2. Save the text file. Be sure to add the format.ps1xml extension to the file to identify
it as a
formatting file.
3. Open Windows PowerShell, and run the following command to load the formatting
file into the
current session: Update-FormatData -PrependPath <Path to file> .
2 Warning
This formatting file defines the display of an object that is already defined by
a Windows
PowerShell formatting files. You must use the PrependPath
parameter when you run the
cmdlet, and you cannot load this formatting file
as a module.
Demonstrates
This formatting file demonstrates the following XML elements:
The ViewSelectedBy element that defines what objects are displayed by the view.
The WideItem element that defines what property is displayed by the view.
Example
The following XML defines a wide view that displays groups of objects. Each new group
is started
when the value of the System.Serviceprocess.Servicecontroller.Servicetype
property changes.
XML
<Configuration>
<ViewDefinitions>
<View>
<Name>ServiceWideView</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ServiceName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
</ViewDefinitions>
</Configuration>
PowerShell
Get-Service f*
Output
Fax FCSAM
fdPHost FDResPub
FontCache
FontCache3.0.0.0 FSysAgent
FwcAgent
See Also
Examples of Formatting Files
This example shows how to implement a basic list view that displays the
System.Serviceprocess.Servicecontroller?Displayproperty=Fullname
objects returned by
the Get-Service
cmdlet. For more information about the components of a list view, see
Creating a List View.
2. Save the text file. Be sure to add the format.ps1xml extension to the file to identify
it as a
formatting file.
3. Open Windows PowerShell, and run the following command to load the formatting
file into the
current session: Update-formatdata -prependpath
PathToFormattingFile .
2 Warning
This formatting file defines the display of an object that is already defined by a
Windows
PowerShell formatting file. You must use the prependPath parameter
when you run the cmdlet, and
you cannot load this formatting file as a module.
Demonstrates
This formatting file demonstrates the following XML elements:
Example
The following XML defines a list view that displays four properties of the
System.Serviceprocess.Servicecontroller?Displayproperty=Fullname
object. In each row,
the name of the property is displayed followed by the value of the property.
XML
<Configuration>
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
</Configuration>
PowerShell
Get-Service f*
Output
Name : Fax
DisplayName : Fax
Status : Stopped
ServiceType : Win32OwnProcess
Name : FCSAM
Status : Running
ServiceType : Win32OwnProcess
Name : fdPHost
Status : Stopped
ServiceType : Win32ShareProcess
Name : FDResPub
Status : Running
ServiceType : Win32ShareProcess
Name : FontCache
Status : Running
ServiceType : Win32ShareProcess
Name : FontCache3.0.0.0
Status : Stopped
ServiceType : Win32OwnProcess
Name : FSysAgent
Status : Running
ServiceType : Win32OwnProcess
Name : FwcAgent
Status : Running
ServiceType : Win32OwnProcess
See Also
Examples of Formatting Files
This example shows how to implement a list view that displays a custom label for each
row of the
list. This list view displays the properties of the
System.Serviceprocess.Servicecontroller?Displayproperty=Fullname
object that is
returned by the Get-Service
cmdlet. For more information about the components of a
list view, see Creating a List View.
2. Save the text file. Be sure to add the format.ps1xml extension to the file to identify
it as a
formatting file.
3. Open Windows PowerShell, and run the following command to load the formatting
file into the
current session: Update-formatdata -prependpath
PathToFormattingFile .
2 Warning
This formatting file defines the display of an object that is already defined by a
Windows
PowerShell formatting file. You must use the prependPath parameter when
you run the cmdlet, and
you cannot load this formatting file as a module.
Demonstrates
This formatting file demonstrates the following XML elements:
XML
<Configuration>
<ViewDefinitions>
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<Label>NAME property</Label>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<Label>DISPLAYNAME property</Label>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<Label>STATUS property</Label>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<Label>SERVICETYPE property</Label>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
</ViewDefinitions>
</Configuration>
PowerShell
Get-Service f*
Output
See Also
Examples of Formatting Files
This example shows how to implement a list view that separates the rows of the list into
groups.
This list view displays the properties of the
System.Serviceprocess.Servicecontroller?Displayproperty=Fullname
objects returned by
the Get-Service
cmdlet. For more information about the components of a list view, see
Creating a List View.
2. Save the text file. Be sure to add the format.ps1xml extension to the file to identify
it as a
formatting file.
3. Open Windows PowerShell, and run the following command to load the formatting
file into the
current session: Update-formatdata -prependpath
PathToFormattingFile .
2 Warning
This formatting file defines the display of an object that is already defined by a
Windows
PowerShell formatting file. You must use the prependPath parameter
when you run the cmdlet, and
you cannot load this formatting file as a module.
Demonstrates
This formatting file demonstrates the following XML elements:
XML
<Configuration>
<ViewDefinitions>
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<GroupBy>
<PropertyName>Status</PropertyName>
</GroupBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
</ViewDefinitions>
</Configuration>
PowerShell
Get-Service f*
Output
Name : Fax
DisplayName : Fax
ServiceType : Win32OwnProcess
Name : FCSAM
ServiceType : Win32OwnProcess
Name : fdPHost
ServiceType : Win32ShareProcess
Name : FDResPub
ServiceType : Win32ShareProcess
Name : FontCache
ServiceType : Win32ShareProcess
Name : FontCache3.0.0.0
ServiceType : Win32OwnProcess
Name : FSysAgent
ServiceType : Win32OwnProcess
Name : FwcAgent
ServiceType : Win32OwnProcess
See Also
Examples of Formatting Files
The topics in this section describe the XML elements used by formatting files
(Format.ps1xml files).
Formatting files define how the .NET object is displayed; they do
not change the object itself.
In This Section
Alignment Element for TableColumnHeader for TableControl (Format)
Defines how the
data in a column header is displayed.
FirstLineIndent Element
Specifies how many characters the first line of data is shifted to
the right. This element is used
when defining a custom control view.
RightIndent Element
Specifies how many characters the data is shifted away from the
right margin. This element is used
when defining a custom control view.
See Also
Writing a PowerShell Formatting File
Configuration Element
Article • 09/17/2021
Schema
Configuration Element
Syntax
XML
<Configuration>
<DefaultSettings>...</DefaultSettings>
<SelectionSets>...</SelectionSets>
<Controls>...</Controls>
<ViewDefinitions>...</ViewDefinitions>
</Configuration>
Attributes
None.
Child Elements
Element Description
Configuration
Defines the common controls that can be used by all views of the
formatting file.
Element Description
Defines common settings that apply to all the views of the formatting
file.
Format
Defines the common sets of .NET objects that can be used by all
views of the formatting file.
Parent Elements
None.
Remarks
Formatting files define how objects are displayed. In most cases, this root element
contains a ViewDefinitions
element that defines the table, list, and wide views of the
formatting file. In addition to the view
definitions, the formatting file can define
common selection sets, settings, and controls that those
views can use.
See Also
Controls Element for Configuration
DefaultSettings Element
SelectionSets Element
ViewDefinitions Element
Defines the common controls that can be used by all views of the formatting file.
Schema
Configuration Element
Controls Element
Syntax
XML
<Controls>
<Control>...</Control>
</Controls>
Attributes
None.
Child Elements
Element Description
Configuration
Defines a common control that can be used by all views of
the formatting file.
Parent Elements
Element Description
Remarks
You can create any number of common controls. For each control, you must specify the
name that is
used to reference the control and the components of the control.
See Also
Configuration Element
Defines a common control that can be used by all the views of the formatting file and
the name that
is used to reference the control.
Schema
Configuration Element
Controls Element
Control Element
Syntax
XML
<Control>
<Name>NameOfControl</Name>
<CustomControl>...</CustomControl>
</Control>
Attributes
None.
Child Elements
Element Description
Configuration
Defines the control.
Element Description
Parent Elements
Element Description
Controls Element of Defines the common controls that can be used by all views of the
Configuration formatting file or by other controls.
Remarks
The name given to this control can be referenced in the following elements:
See Also
Controls Element of Configuration
Defines a control. This element is used when defining a common control that can be
used by all the
views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
Syntax
XML
<CustomControl>
<CustomEntries>...</CustomEntries>
</CustomControl>
Attributes
None.
Child Elements
Element Description
Element Description
Configuration
Provides the definitions of a
control.
Parent Elements
Element Description
Control Element for Defines a common control that can be used by all the views of the
Controls for formatting file and the name that is used to reference the control.
Configuration
Remarks
See Also
Control Element for Controls for Configuration
Provides the definitions of a common control. This element is used when defining a
common control
that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
Syntax
XML
<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>
Attributes
None.
Child Elements
Element Description
Element Description
CustomEntry Element for CustomControl for Controls for Provides a definition of the common
Configuration control.
Parent Elements
Element Description
Remarks
In most cases, a control has only one definition, which is defined in a single CustomEntry
element. However it is possible to have multiple definitions if you want to use the same
control to
display different .NET objects. In those cases, you can define a CustomEntry
element for each
object or set of objects.
See Also
CustomControl Element for Control for Configuration
Provides a definition of the common control. This element is used when defining a
common control
that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
Syntax
XML
<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomEntries Element for CustomControl for Provides the definitions of the common
Configuration control.
Remarks
In most cases, only one definition is required for each common custom control, but it is
possible to
have multiple definitions if you want to use the same control to display
different .NET objects. In
those cases, you can provide a separate definition for each
object or set of objects.
See Also
CustomEntries Element for CustomControl for Configuration
Defines what data is displayed by the control and how it is displayed. This element is
used when
defining a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Syntax
XML
<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<NewLine/>
<Text>TextToDisplay</Text>
<Frame>...</Frame>
</CustomItem>
Attributes
None.
Child Elements
Element Description
for Configuration
Defines how the data is displayed, such as
shifting the data to the left or right.
for Configuration
Adds a blank line to the display of the control.
Configuration
Adds text, such as parentheses or brackets, to
the display of the control.
Parent Elements
Element Description
CustomEntry Element for CustomControl for Controls for Provides a definition of the
Configuration control.
Remarks
When specifying the child elements of the CustomItem element, keep the following in
mind:
There is no maximum limit to the number of sequences that you can specify.
In each sequence, there is no maximum limit to the number of ExpressionBinding
elements that you
can use.
See Also
ExpressionBinding Element for CustomItem for Controls for Configuration
Frame Element for CustomItem for Controls for Configuration
Defines the data that is displayed by the control. This element is used when defining a
common
control that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
Syntax
XML
<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the custom
Controls for Configuration control view and how it is displayed.
Remarks
See Also
CustomItem Element for CustomEntry for Controls for Configuration
Specifies the name of a common control. This element is used when defining a common
control that can
be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
CustomControlName Element
Syntax
XML
<CustomControlName>NameofCustomControl</CustomControlName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Controls Defines the data that is displayed by
for Configuration the control.
Text Value
Specify the name of the control.
Remarks
You can create common controls that can be used by all the views of a formatting file,
and you can
create view controls that can be used by a specific view. The following
elements specify the names
of these controls:
See Also
Name Element for Control for Controls for Configuration
Specified that the elements of collections are displayed by the control. This element is
used when
defining a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
EnumerateCollection Element
Syntax
XML
<EnumerateCollection/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Controls Defines the data that is displayed by
for Configuration the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for Controls for Configuration
Defines the condition that must exist for this control to be used. This element is used
when
defining a common control that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
Syntax
XML
<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Controls Defines the data that is displayed by
for Configuration the control.
Remarks
You can specify one property name or a script for this condition but cannot specify both.
See Also
PropertyName Element for ItemSelectionCondition for Controls for Configuration
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the control is used. This element is
used when
defining a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for ExpressionBinding Defines the condition that must exist for
for Controls for Configuration this control to be used.
Text Value
Specify the name of the .NET property that triggers the condition.
Remarks
If this element is used, you cannot specify the ScriptBlock
element when defining the
selection condition.
See Also
ScriptBlock Element for ItemSelectionCondition for Controls for Configuration
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the control is used. This element is used when defining a common
control that
can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for ExpressionBinding Defines the condition that must exist for
for Controls for Configuration this control to be used.
Text Value
Specify the script that is evaluated.
Remarks
If this element is used, you cannot specify the PropertyName
element when defining the
selection condition.
See Also
PropertyName Element for ItemSelectionCondition for Controls for Configuration
Specifies the .NET property whose value is displayed by the common control. This
element is used
when defining a common control that can be used by all the views in
the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Controls Defines the data that is displayed by
for Configuration the control.
Text Value
Specify the name of the .NET property whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for Controls for Configuration
Specifies the script whose value is displayed by the common control. This element is
used when
defining a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
Controls for Configuration common control.
Text Value
Specify the script whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for Controls for Configuration
Defines how the data is displayed, such as shifting the data to the left or right. This
element is
used when defining a common control that can be used by all the views in
the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
Syntax
XML
<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>
Attributes
None.
Child Elements
Element Description
for Configuration
Specifies how many characters the data is shifted
away from the left margin.
for Configuration
Specifies how many characters the data is shifted
away from the right margin.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the control
Controls for Configuration and how it is displayed.
Remarks
You cannot specify the FirstLineHanging and the FirstLineIndent elements in the same
Frame element.
See Also
FirstLineHanging Element for Frame for Controls for Configuration
Specifies how many characters the first line of data is shifted to the left. This element is
used
when defining a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineHanging Element
Syntax
XML
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting
Controls for Configuration the data to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineIndent element.
See Also
Frame Element for CustomItem for Controls for Configuration
Specifies how many characters the first line of data is shifted to the right. This element is
used
when defining a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineIndent Element
Syntax
XML
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting
Controls for Configuration the data to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineHanging element.
See Also
FirstLineHanging Element for Frame for Controls for Configuration
Specifies how many characters the data is shifted away from the left margin. This
element is used
when defining a common control that can be used by all the views in
the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
LeftIndent Element
Syntax
XML
<LeftIndent>CharactersToShift</LeftIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting
Controls for Configuration the data to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the left.
Remarks
See Also
Frame Element for CustomItem for Controls for Configuration
Specifies how many characters the data is shifted away from the right margin. This
element is used
when defining a common control that can be used by all the views in
the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
RightIndent Element
Syntax
XML
<RightIndent>CharactersToShift</RightIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting
Controls for Configuration the data to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the right.
Remarks
See Also
Frame Element for CustomItem for Controls for Configuration
Adds a blank line to the display of the control. This element is used when defining a
common control
that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
NewLine Element
Syntax
XML
<NewLine/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Controls for Defines a control for the custom
Configuration control view.
Remarks
See Also
CustomItem Element for CustomEntry for Controls for Configuration
Specifies text that is added to the data that is displayed by the control, such as a label,
brackets
to enclose the data, and spaces to indent the data. This element is used when
defining a common
control that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Text Element
Syntax
XML
<Text>TextToDisplay</Text>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the control
Controls for Configuration and how it is displayed.
Text Value
Specify the text of a control for data that you want to display.
Remarks
See Also
CustomItem Element for CustomEntry for Controls for Configuration
Defines the .NET types that use the definition of the common control or the condition
that must
exist for this control to be used. This element is used when defining a
common control that can be
used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>SelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomEntry Element for CustomControl for Controls for Provides a definition of the common
Configuration control.
Remarks
At a minimum, each definition must have at least one .NET type, selection set, or
selection
condition specified. There is no maximum limit to the number of types,
selection sets, or selection
conditions that you can specify.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for Configuration
Defines a condition that must exist for a common control definition to be used. This
element is used
when defining a common control that can be used by all the views in
the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
for Configuration
Specifies the script that triggers the
condition.
for Configuration
Specifies a .NET type that triggers the
condition.
Parent Elements
Element Description
EntrySelectedBy Element for CustomEntry for Defines the .NET types that use this entry of the
Controls for Configuration common control definition.
Remarks
The following guidelines must be followed when defining a selection condition:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how selection conditions can be used, see Defining
Conditions for when Data is Displayed.
See Also
PropertyName Element for SelectionCondition for Controls for Configuration
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the entry is used. This element is
used when defining
a common control that can be used by all the views in the
formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify a least one property name or a script, but cannot
specify both.
For more information about how selection conditions can be used, see
Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for Configuration
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the definition is used. This element is used when defining a
common control
that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the
EntrySelectedBy for Controls for Configuration common control definition to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify a least one script or property name to evaluate, but
cannot
specify both. For more information about how selection conditions can be used,
see Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for Configuration
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met, and the object is displayed by using this control.
This element is
used when defining a common control that can be used by all the views
in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for EntrySelectedBy Defines a condition that must exist for the
for Controls for Configuration control definition to be used.
Text Value
Specify the name of the selection set.
Remarks
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Sets of Objects.
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for Configuration
Specifies a .NET type that triggers the condition. This element is used when defining a
common
control that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for EntrySelectedBy for Defines a condition that must exist for the
CustomEntry for Configuration control definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
SelectionCondition Element for EntrySelectedBy for CustomEntry for Configuration
Specifies a set of .NET types that use this definition of the control. This element is used
when
defining a common control that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element of Configuration
Control Element for Controls for Configuration
CustomControl Element for Control for Configuration
CustomEntries Element for CustomControl for Configuration
CustomEntry Element for CustomControl for Controls for Configuration
EntrySelectedBy Element for CustomEntry for Controls for Configuration
SelectionSetName Element for EntrySelectedBy for Controls for Configuration
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or
CustomEntry for Controls for the condition that must exist for this definition to be used.
Configuration
Text Value
Specify the name of the selection set.
Remarks
Each control definition must have at least one type name, selection set, or selection
condition
defined.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For more information about defining selection sets, see Defining
Selection Sets.
See Also
EntrySelectedBy Element for CustomEntry for Controls for Configuration
Specifies a .NET type that uses this definition of the control. This element is used when
defining a
common control that can be used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or
CustomEntry for Controls for the condition that must exist for this definition to be used.
Configuration
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
EntrySelectedBy Element for CustomEntry for Controls for Configuration
Specifies the name of the control. This element is used when defining a common control
that can be
used by all the views in the formatting file.
Schema
Configuration Element
Controls Element
Control Element
Name Element
Syntax
XML
<Name>NameOfControl</Name>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
Control Element for Defines a common control that can be used by all the views of the
Controls for formatting file and the name that is used to reference the control.
Configuration
Text Value
Specify the name that is used to reference this control.
Remarks
The name specified here can be used in the following elements to reference this control.
When creating a table, list, wide or custom control view, the control can be
specified by the
following element: GroupBy Element for View
When creating another common control, this control can be specified by the
following element: ExpressionBinding Element for CustomItem for Controls for
Configuration
When creating a control that can be used by a view, this control can be specified
by the following
element: ExpressionBinding Element for CustomItem for Controls
for View
See Also
Control Element for Controls for Configuration
Defines common settings that apply to all the views of the formatting file. Common
settings include
displaying errors, wrapping text in tables, defining how collections are
expanded, and more.
Schema
Configuration Element
DefaultSettings Element
Syntax
XML
<DefaultSettings>
<ShowError/>
<DisplayError/>
<PropertyCountForTable>NumberOfProperties</PropertyCountFortable>
<WrapTables/>
<EnumerableExpansions>...</EnumerableExpansions>
</DefaultSettings>
Attributes
None.
Child Elements
Element Description
Element Description
Specifies that the string #ERR is displayed when an error occurs while
displaying a piece of data.
Element
Defines the different ways that .NET objects are expanded when they
are displayed in a view.
Specifies that the full error record is displayed when an error occurs
while displaying a piece of data.
Specifies that data in a table is moved to the next line if it does not fit
into the width of the column.
Parent Elements
Element Description
Remarks
See Also
Configuration Element
DisplayError Element
EnumerableExpansions Element
PropertyCountForTable
ShowError Element
WrapTables Element
Specifies that the string #ERR is displayed when an error occurs displaying a piece of
data.
Schema
Configuration Element
DefaultSettings Element
DisplayError Element
Syntax
XML
<DisplayError/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
DefaultSettings Defines common settings that apply to all the views of the formatting
Element file.
Remarks
By default, when an error occurs while trying to display a piece of data, the location of
the data
is left blank. When this element is set to true, the #ERR string will be displayed.
See Also
DefaultSettings Element
Defines how .NET collection objects are expanded when they are displayed in a view.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
Syntax
XML
<EnumerableExpansions>
<EnumerableExpansion>...</EnumerableExpansion>
</EnumerableExpansions>
Attributes
None.
Child Elements
Element Description
Element
Defines the specific .NET collection objects that are expanded when they
are displayed in a view.
Parent Elements
Element Description
DefaultSettings Defines common settings that apply to all the views of the formatting
Element file.
Remarks
This element is used to define how collection objects and the objects in the collection
are
displayed. In this case, a collection object refers to any object that supports the
System.Collections.ICollection interface.
See Also
Writing a PowerShell Formatting File
EnumerableExpansion Element
Article • 09/17/2021
Defines how specific .NET collection objects are expanded when they are displayed in a
view.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
Syntax
XML
<EnumerableExpansion>
<EntrySelectedBy>...</EntrySelectedBy>
</EnumerableExpansion>
Attributes
None.
Child Elements
Element Description
EnumerableExpansion
Defines which .NET collection objects are expanded by
this definition.
Element Description
Expand Element Specifies how the collection object is expanded for this
definition.
Parent Elements
Element Description
EnumerableExpansions Defines the different ways that .NET collection objects are expanded
Element when they are displayed in a view.
Remarks
This element is used to define how collection objects and the objects in the collection
are
displayed. In this case, a collection object refers to any object that supports the
System.Collections.ICollection interface.
The default behavior is to display only the properties of the objects in the collection.
See Also
Writing a PowerShell Formatting File
EntrySelectedBy Element for
EnumerableExpansion
Article • 09/17/2021
Defines the .NET types that use this definition or the condition that must exist for this
definition
to be used.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
EntrySelectedBy Element for EnumerableExpansion
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
Attributes
None.
Child Elements
Element Description
Element Description
for EnumerableExpansion
Specifies a .NET type that uses this definition of how
collection objects are expanded.
Parent Elements
Element Description
EnumerableExpansion Defines how specific .NET collection objects are expanded when they
Element are displayed in a view.
Remarks
You must specify at least one type, selection set, or selection condition for a definition
entry.
There is no maximum limit to the number of child elements that you can use.
Selection conditions are used to define a condition that must exist for the definition to
be used,
such as when an object has a specific property or that a specific property value
or script evaluates
to true . For more information about selection conditions, see
Defining Conditions for Displaying Data.
See Also
Defining Conditions for Displaying Data
EnumerableExpansion Element
Defines the condition that must exist to expand the collection objects of this definition.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
element. The
SelectionSetName and TypeName elements are optional. You can specify
one of either element.
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
EntrySelectedBy Element for Defines which .NET collection objects are expanded by
EnumerableExpansion this definition.
Remarks
Each definition must have at least one type name, selection set, or selection condition
defined.
When you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how to use selection conditions, see Defining Conditions
for Diplaying Data.
For more information about other components of a wide view, see Wide View.
See Also
Defining Conditions for When Data Is Displayed
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the entry is used. This element is
used when defining
controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element for Controls for View
CustomControl Element for Control for Controls for View
CustomEntries Element for CustomControl for Controls for View
CustomEntry Element for CustomEntries for Controls for View
EntrySelectedBy Element for CustomEntry for Controls for View
SelectionCondition Element for EntrySelectedBy for Controls for View
PropertyName Element for SelectionCondition for Controls for View
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the
EntrySelectedBy for Controls for View control definition to be used.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify a least one property name or a script, but cannot
specify both.
For more information about how selection conditions can be used, see
Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for View
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the definition is used. This element is used when defining controls
that can
be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the
EntrySelectedBy for Controls for View control definition to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify a least one script or property name to evaluate, but
cannot
specify both. For more information about how selection conditions can be used,
see Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for View
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansions Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist to expand the
EntrySelectedBy for EnumerableExpansion collection objects of this definition.
Text Value
Specify the name of the selection set.
Remarks
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for Displaying Data.
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Selection Sets.
See Also
Defining Selection Sets
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansions Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist to expand the
EntrySelectedBy for EnumerableExpansion collection objects of this definition.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
SelectionCondition Element for EntrySelectedBy for EnumerableExpansion
Specifies the set of .NET types that are expanded by this definition.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET collection objects that are expanded
EnumerableExpansion by this definition.
Text Value
Specify the name of the selection set.
Remarks
Each definition must specify one or more type names, a selection set, or a selection
condition.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For example, you might want to create a table view and a list
view for the same set
of objects. For more information about defining selection sets, see
Defining Sets of Objects for a View.
See Also
Defining Selection Sets
Specifies a .NET type that is expanded by this definition. This element is used when
defining a
default settings.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
EntrySelectedBy Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this definition or the condition
EnumerableExpansion that must exist for this definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
EntrySelectedBy Element for EnumerableExpansion
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
Expand Element
Syntax
XML
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EnumerableExpansion Defines how specific .NET collection objects are expanded when they
Element are displayed in a view.
Text Value
Specify one of the following values:
Both: Displays the properties of the objects in the collection and the properties of
the
collection object.
Remarks
This element is used to define how collection objects and the objects in the collection
are
displayed. In this case, a collection object refers to any object that supports the
System.Collections.ICollection interface.
The default behavior is to display only the properties of the objects in the collection.
See Also
Writing a PowerShell Formatting File
PropertyCountForTable Element
Article • 09/17/2021
Optional element. Specifies the minimum number of properties that an object must
have to display the
object in a table view.
Schema
DefaultSettings Element
PropertyCountForTable Element
Syntax
XML
<PropertyCountForTable>NumberOfProperties</PropertyCountFortable>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
DefaultSettings Defines common settings that apply to all the views of the formatting
Element file.
Remarks
See Also
Writing a PowerShell Formatting File
ShowError Element
Article • 09/17/2021
Specifies that the full error record is displayed when an error occurs while displaying a
piece of
data.
Schema
Configuration Element
DefaultSettings Element
ShowError Element
Syntax
scr
<ShowError/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
DefaultSettings Defines common settings that apply to all the views of the formatting
Element file.
Remarks
See Also
Writing a PowerShell Formatting File
WrapTables Element
Article • 09/17/2021
Specifies that data in a table cell is moved to the next line if the data is longer than the
width
of the column.
Schema
Configuration Element
DefaultSettings Element
WrapTables Element
Syntax
XML
<WrapTables/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
DefaultSettings Defines common settings that apply to all the views of the formatting
Element file.
Remarks
See Also
Writing a PowerShell Formatting File
SelectionSets Element
Article • 09/17/2021
Defines the common sets of .NET objects that can be used by all views of the formatting
file. The
views and controls of the formatting file can reference the complete set of
objects by using only
the name of the selection set.
Schema
Configuration Element
SelectionSets Element
Syntax
XML
<SelectionSets>
<SelectionSet>...</SelectionSet>
</SelectionSets>
Attributes
None.
Child Elements
Element Description
Element
Defines a single set of .NET objects that can be referenced by the name of
the set.
Parent Elements
Element Description
Remarks
You can use selection sets when you have a set of related objects that you want to
reference by
using a single name, such as a set of objects that are related through
inheritance. When defining
your views, you can specify the set of objects by using the
name of the selection set instead of
listing all the objects within each view.
Common selection sets are specified by their name when defining the views of the
formatting file or
the definitions of the views. In these cases, the SelectionSetName child
element of the
ViewSelectedBy and EntrySelectedBy elements specifies the set to be
used. For more information
about selection sets, see Defining Sets of Objects.
See Also
Configuration Element
SelectionSet Element
Defines a set of .NET objects that can be referenced by the name of the set.
Schema
Configuration Element
SelectionSets Element
SelectionSet Element
Syntax
XML
<SelectionSet>
<Name>SelectionSetName</Name>
<Types>...</Types>
</SelectionSet>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
SelectionSets Element Defines the common sets of .NET objects that can be used by all views
Format of the formatting file.
Remarks
You can use selection sets when you have a set of related objects that you want to
reference by
using a single name, such as a set of objects that are related through
inheritance. When defining
your views, you can specify the set of objects by using the
name of the selection set instead of
listing all the objects within each view.
Common selection sets are specified by their name when defining the views of the
formatting file or
the definitions of the views. In these cases, the SelectionSetName child
element of the
ViewSelectedBy and EntrySelectedBy elements specifies the set to be
used. For more information
about selection sets, see Defining Sets of Objects.
Example
The following example shows a SelectionSet element that defines four .NET types.
XML
<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>
See Also
Defining Selection Sets
SelectionSets Element
Types Element
Schema
Configuration Element
SelectionSets Element
SelectionSet Element
Name Element
Syntax
XML
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionSet Defines a single set of .NET objects that can be referenced by the name of
Element the set.
Text Value
Specify the name to reference the selection set. There are no restrictions as to what
characters can
be used.
Remarks
The name specified here is used in the SelectionSetName element. The selection set that
can be
used by a view, by a definition of a view (views can have multiple definitions), or
when specifying
a selection condition. For more information about selection sets, see
Defining Sets of Objects.
Example
This example shows a SelectionSet element that defines four .NET types. The name of
the selection
set is "FileSystemTypes".
XML
<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>
See Also
Defining Selection Sets
SelectionSet Element
Schema
Configuration Element
SelectionSets Element
SelectionSet Element
Types Element
Syntax
XML
<Types>
<TypeName>Nameof.NetType</TypeName>
</Types>
Attributes
None.
Child Elements
Element Description
Element Description
SelectionSet Defines a set of .NET objects that can be referenced by the name of the
Element set.
Remarks
The objects defined by this element make up a selection set that can be used by a view,
by a
definition of a view (views can have multiple definitions), or when specifying a
selection
condition. For more information about selection sets, see Defining Sets of
Objects.
Example
This example shows a SelectionSet element that defines four .NET types.
XML
<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>
See Also
Defining Sets of Objects
SelectionSet Element
Specifies the .NET type of an object that belongs to the selection set.
Schema
Configuration Element
SelectionSets Element
SelectionSet Element
Types Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</Name>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Types Element Defines the .NET objects that are in the selection set.
Text Value
Specify the fully qualified name for the .NET type.
Remarks
You can use selection sets when you have a set of related objects that you want to
reference by
using a single name, such as a set of objects that are related through
inheritance. When defining
your views, you can specify the set of objects by using the
name of the selection set instead of
listing all the objects within each view.
Common selection sets are specified by their name when defining the views of the
formatting file. In
these cases, the SelectionSetName child element of the
ViewSelectedBy element for the view
specifies the set. However, different entries of a
Example
The following example shows a SelectionSet element that defines four .NET types.
<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>
See Also
Defining Selection Sets
SelectionSet Element
SelectionSets Element
Types Element
Defines the views used to display .NET objects. These views can display the properties
and script
values of an object in a table format, list format, wide format, and custom
control format.
Schema
Configuration Element
ViewDefinitions
Syntax
XML
<ViewDefinitions>
<View>...</View>
</ViewDefinitions>
Attributes
None.
Child Elements
Element Description
View Element Defines a view that is used to display one or more .NET objects.
Parent Elements
Element Description
Remarks
For more information about the components of the different types of views, see the
following topics:
Custom Controls
Example
This example shows a ViewDefinitions element that contains the parent elements for a
table view
and a list view.
XML
<Configuration>
<ViewDefinitions>
<View>
<TableControl>...</TableControl>
</View>
<View>
<ListControl>...</ListControl>
</View>
</ViewDefinitions>
</Configuration>
See Also
Configuration Element
View Element
Custom Controls
Defines a view that displays one or more .NET objects. There is no limit to the number of
views that
can be defined in a formatting file.
Schema
Configuration Element
ViewDefinitions Element
View Element
Syntax
XML
<View>
<OutOfBand />
<ViewSelectedBy>...</ViewSelectedBy>
<Controls>...</Controls>
<GroupBy>...</GroupBy>
<TableControl>...</TableControl>
<ListControl>...</ListControl>
<WideControl>...</WideControl>
<CustomControl>...</CustomControl>
</View>
Attributes
None.
Child Elements
Element Description
View
Defines a set of controls that can be referenced by their name from within
the view.
Element
Defines a custom control format for the view.
View
Defines how the members of the .NET objects are grouped.
View
Specifies the name used to reference the view.
Element
Defines a table format for the view.
Element
Defines a wide (single value) list format for the view.
Parent Elements
Element Description
Custom Controls
Example
This example shows a View element that defines a table view for the
System.Serviceprocess.Servicecontroller
object.
XML
<ViewDefinitions>
<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
</ViewDefinitions>
See Also
ViewDefinitions Element
ViewSelectedBy Element
TableControl Element
ListControl Element
WideControl Element
CustomControl Element
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Syntax
XML
<Controls>
<Control>...</Control>
</Controls>
Attributes
None.
Child Elements
Element Description
Control Element for Controls for View Defines a control that can be used by the view.
Parent Elements
Element Description
View Element Defines a view that is used to display the members of one or more .NET objects.
Remarks
See Also
Control Element
View Element
Defines a control that can be used by the view and the name that is used to reference
the control.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
Syntax
XML
<Control>
<Name>NameOfControl</Name>
<CustomControl>...</CustomControl>
</Control>
Attributes
None.
Child Elements
Element Description
CustomControl Element for Control for Controls for View Required element.
Parent Elements
Element Description
Controls Element Defines the view controls that can be used by a specific view.
Remarks
This control can be specified by the following elements:
See Also
CustomControl Element for Control for Controls for View
Controls Element
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
Syntax
XML
<CustomControl>
<CustomEntries>...</CustomEntries>
</CustomControl>
Attributes
None.
Child Elements
Element Description
Element Description
View
Provides the definitions for the
control.
Parent Elements
Element Description
Control Element for Defines a control that can be used by the view and the name that is
Controls for View used to reference the control.
Remarks
See Also
CustomEntries Element for CustomControl for View
Provides the definitions for the control. This element is used when defining controls that
can be
used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
Syntax
XML
<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>
can be
specified.
Attributes
None.
Child Elements
Element Description
View
Provides a definition of the
control.
Parent Elements
Element Description
CustomControl Element for Control for Controls for View Defines the control used by the view.
Remarks
In most cases, a control has only one definition, which is specified in a single
CustomEntry
element. However, it is possible to provide multiple definitions if you want
to use the same control
to display different .NET objects. In those cases, you can define
a CustomEntry element for each
object or set of objects.
See Also
CustomEntry Element for CustomEntries for Controls for View
Provides a definition of the control. This element is used when defining controls that can
be used
by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
Syntax
XML
<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomEntries Element for CustomControl for View Provides the definitions for the control.
Remarks
See Also
CustomEntries Element for CustomControl for View
Defines what data is displayed by the control and how it is displayed. This element is
used when
defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Syntax
XML
<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<NewLine/>
<Text>TextToDisplay</Text>
<Frame>...<Frame>
</CustomItem>
Attributes
None.
Child Elements
Element Description
for View
Adds text, such as parentheses or brackets, to the
display of the control.
Parent Elements
Element Description
CustomEntry Element for CustomEntries for Controls for Provides a definition of the
View control.
Remarks
When specifying the child elements of the CustomItem element, keep the following in
mind:
There is no maximum limit to the number of sequences that you can specify.
In each sequence, there is no maximum limit to the number of ExpressionBinding
elements that you
can use.
See Also
ExpressionBinding Element for CustomItem for Controls for View
Frame Element for CustomItem for Controls for View
Defines the data that is displayed by the control. This element is used when defining
controls that
can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
Syntax
XML
<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the control and
Controls for View how it is displayed.
Remarks
See Also
CustomItem Element for CustomEntry for Controls for View
Specifies the name of a common control or a view control. This element is used when
defining
controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
CustomControlName Element
Syntax
XML
<CustomControlName>NameofCustomControl</CustomControlName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
Controls for View control.
Text Value
Specify the name of the control.
Remarks
You can create common controls that can be used by all the views of a formatting file,
and you can
create view controls that can be used by a specific view. The following
elements specify the names
of these controls:
See Also
Name Element for Control for Controls for Configuration
Specified that the elements of collections are displayed. This element is used when
defining
controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
EnumerateCollection Element
Syntax
XML
<EnumerateCollection/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
Controls for View control.
Remarks
See Also
ExpressionBinding Element for CustomItem for Controls for View
Defines the condition that must exist for this control to be used. This element is used
when
defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
Syntax
XML
<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
Controls for View control.
Remarks
You can specify one property name or a script for this condition but cannot specify both.
See Also
PropertyName Element for ItemSelectionCondition for Controls for View
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the control is used. This element is
used when
defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Text Value
Specify the name of the .NET property that triggers the condition.
Remarks
If this element is used, you cannot specify the ScriptBlock
element when defining the
selection condition.
See Also
ScriptBlock Element for ItemSelectionCondition for Controls for View
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the control is used. This element is used when defining controls
that can be
used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Text Value
Specify the script that is evaluated.
Remarks
If this element is used, you cannot specify the PropertyName
element when defining the
selection condition.
See Also
PropertyName Element for ItemSelectionCondition for Controls for View
Specifies the .NET property whose value is displayed by the control. This element is used
when
defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
Controls for View control.
Text Value
Specify the name of the .NET property whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for Controls for View
Specifies the script whose value is displayed by the control. This element is used when
defining
controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
Controls for View control.
Text Value
Specify the script whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for Controls for View
Defines how the data is displayed, such as shifting the data to the left or right. This
element is
used when defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
Syntax
XML
<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>
Attributes
None.
Child Elements
Element Description
Controls of View
Specifies how many characters the first line is shifted to
the left.
Controls of View
Specifies how many characters the first line is shifted to
the right.
Controls of View
Specifies how many characters the data is shifted away
from the left margin.
Controls of View
Specifies how many characters the data is shifted away
from the right margin.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the control and
Controls for View how it is displayed.
Remarks
You cannot specify the FirstLineHanging and the FirstLineIndent elements in the same
Frame element.
See Also
FirstLineHanging Element of Frame of Controls of View
FirstLineIndent Element of Frame of Controls of View
Specifies how many characters the first line of data is shifted to the left. This element is
used
when defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineHanging Element
Syntax
XML
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
Controls for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineIndent element.
See Also
FirstLineIndent Element for Frame for Controls for View
Specifies how many characters the first line of data is shifted to the right. This element is
used
when defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineIndent Element
Syntax
XML
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
Controls for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineHanging element.
See Also
FirstLineHanging Element for Frame for Controls for View
Specifies how many characters the data is shifted away from the left margin. This
element is used
when defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
LeftIndent Element
Syntax
XML
<LeftIndent>CharactersToShift</LeftIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
Controls for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the left.
Remarks
See Also
Frame Element for CustomItem for Controls for View
Specifies how many characters the data is shifted away from the right margin. This
element is used
when defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
RightIndent Element
Syntax
XML
<RightIndent>CharactersToShift</RightIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
Controls for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the right.
Remarks
See Also
Frame Element for CustomItem for Controls for View
Adds a blank line to the display of the control. This element is used when defining
controls that
can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
NewLine Element
Syntax
XML
<NewLine/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the control and
Controls for View how it is displayed.
Remarks
See Also
CustomItem Element for CustomEntry for Controls for View
Specifies text that is added to the data that is displayed by the control, such as a label,
brackets
to enclose the data, and spaces to indent the data. This element is used when
defining controls that
can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Syntax
XML
<Text>TextToDisplay</Text>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the control and
Controls for View how it is displayed.
Text Value
Specify the text of a control for data that you want to display.
Remarks
See Also
CustomItem Element for CustomEntry for Controls for View
Defines the .NET types that use this control definition or the condition that must exist
for this
definition to be used. This element is used when defining controls that can be
used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
condition
for a definition. There is no maximum limit to the number of child elements
that you can use.
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomEntry Element for CustomEntries for Controls for Provides a definition of the
View control.
Remarks
Selection conditions are used to define a condition that must exist for the definition to
be used,
such as when an object has a specific property or when a specific property
value or script evaluates
to true . For more information about selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
See Also
CustomEntry Element for CustomEntries for Controls for View
Defines a condition that must exist for the control definition to be used. This element is
used when
defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or the
CustomEntry for Controls for condition that must exist for this definition to be used.
View
Remarks
When you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
See Also
PropertyName Element for SelectionCondition for Controls for View
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the definition is used. This element
is used when
defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for EntrySelectedBy Defines a condition that must exist for the
for CustomControl for View control definition to be used.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify a least one property name or a script, but cannot
specify both.
For more information about how selection conditions can be used, see
Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for CustomControl for View
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the definition is used. This element is used when defining a
custom control
view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for EntrySelectedBy Defines a condition that must exist for the
for CustomControl for View control definition to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify a least one script or property name to evaluate, but
cannot
specify both. For more information about how selection conditions can be used,
see Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for CustomControl for View
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met and the object is displayed using this control. This
element is used
when defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the
EntrySelectedBy for Controls for View control definition to be used.
Text Value
Specify the name of the selection set.
Remarks
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Selection Sets.
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for Controls for View
Specifies a .NET type that triggers the condition. This element is used when defining
controls that
can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the
EntrySelectedBy for Controls for View control definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
SelectionCondition Element for EntrySelectedBy for Controls for View
Specifies a set of .NET types that use this definition of the control. This element is used
when
defining controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or the
CustomEntry for Controls for condition that must exist for this definition to be used.
View
Text Value
Specify the name of the selection set.
Remarks
Each control definition must have at least one type name, selection set, or selection
condition
defined.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For more information about defining selection sets, see Defining
Selection Sets.
See Also
EntrySelectedBy Element for CustomEntry for Controls for View
Specifies a .NET type that uses this definition of the control. This element is used when
defining
controls that can be used by a view.
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
CustomControl Element
CustomEntries Element
CustomEntry Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or the
CustomEntry for Controls for condition that must exist for this definition to be used.
View
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
EntrySelectedBy Element for CustomEntry for Controls for View
Schema
Configuration Element
ViewDefinitions Element
View Element
Controls Element
Control Element
Name Element
Syntax
XML
<Name>ControlName</Name>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
Control Element for Defines a control that can be used by the view and the name that is
Controls for View used to reference the control.
Text Value
Specify the name that is used to reference the control.
Remarks
The name specified here can be used in the following elements to reference this control.
When creating a table, list, wide or custom control view, the control can be
specified by the
following element: GroupBy Element for View
When creating another control that can be used by a view, this control can be
specified by the
following element: ExpressionBinding Element for CustomItem for
Controls for View
See Also
GroupBy Element for View
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
Syntax
XML
<CustomControl>
<CustomEntries>...</CustomEntries>
</CustomControl>
Attributes
None.
Child Elements
Element Description
View
Provides the definitions of the custom control
view.
Parent Elements
Element Description
View Element Defines a view that is used to display one or more .NET objects.
Remarks
In most cases, only one definition is required for each control view, but it is possible to
provide
multiple definitions if you want to use the same view to display different .NET
objects. In those
cases, you can provide a separate definition for each object or set of
objects.
See Also
CustomEntries Element for CustomControl for View
View Element
Provides the definitions of the custom control view. The custom control view must
specify one or
more definitions.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
Syntax
XML
<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>
Attributes
None.
Child Elements
Element Description
Element Description
View
Provides a definition of the custom control
view.
Parent Elements
Element Description
Remarks
In most cases, a control has only one definition, which is defined in a single CustomEntry
element. However it is possible to have multiple definitions if you want to use the same
control to
display different .NET objects. In those cases, you can define a CustomEntry
element for each
object or set of objects.
See Also
CustomControl Element for View
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
Syntax
XML
<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>
Attributes
None.
Child Elements
Element Description
Element Description
CustomItem Element for Defines a control for the custom control definition.
CustomEntry for View
Parent Elements
Element Description
CustomEntries Element for Provides the definitions of the custom control view. The custom
CustomControl for View control view must specify one or more definitions.
Remarks
In most cases, only one definition is required for each custom control view, but it is
possible to
have multiple definitions if you want to use the same view to display
different .NET objects. In
those cases, you can provide a separate definition for each
object or set of objects.
See Also
CustomControl Element for View
Defines what data is displayed by the custom control view and how it is displayed. This
element is
used when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Syntax
XML
<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<Frame>...</Frame>
<NewLine/>
<Text>TextToDisplay</Text>
</CustomItem>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
Remarks
See Also
CustomEntry Element for CustomEntries for View
Defines the data that is displayed by the control. This element is used when defining a
custom
control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
Syntax
XML
<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ExpressionBinding>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines what data is displayed by the custom control
CustomControl for View view and how it is displayed.
Remarks
See Also
CustomControlName Element for ExpressionBinding for CustomControl for View
Specifies the name of a common control or a view control. This element is used when
defining a
custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
CustomControlName Element
Syntax
XML
<CustomControlName>NameofCustomControl</CustomControlName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem Defines the data that is displayed by the control.
Text Value
Specify the name of the control.
Remarks
You can create common controls that can be used by all the views of a formatting file
and you can
create view controls that can be used by a specific view. The names of
these controls are specified
by the following elements.
See Also
Name Element for Control for Controls for Configuration
Specifies that the elements of collections are displayed. This element is used when
defining a
custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
EnumerateCollection Element
Syntax
XML
<EnumerateCollection/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem Defines the data that is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem
Defines the condition that must exist for this control to be used. There is no limit to the
number
of selection conditions that can be specified for a control item. This element is
used when defining
a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
Syntax
XML
<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by
CustomControl for View the control.
Remarks
You can specify one property name or a script for this condition but cannot specify both.
See Also
Writing a PowerShell Formatting File
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the control is used. This element is
used when
defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element for CustomControl for View
CustomEntry Element for CustomEntries for View
CustomItem Element for CustomEntry for View
ExpressionBinding Element for CustomItem for CustomControl for View
ItemSelectionCondition Element for Expression Binding for CustomControl for
View
PropertyName Element for ItemSelectionCondition for CustomControl for View
(Format
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for Expression Defines the condition that must exist for
Binding for CustomControl for View this control to be used.
Text Value
Specify the name of the .NET property that triggers the condition.
Remarks
If this element is used, you cannot specify the ScriptBlock
element when defining the
selection condition.
See Also
ScriptBlock Element for ItemSelectionCondition for CustomControl for View
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the control is used. This element is used when defining a custom
control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for Expression Defines the condition that must exist for
Binding for CustomControl for View this control to be used.
Text Value
Specify the script that is evaluated.
Remarks
If this element is used, you cannot specify the PropertyName
element when defining the
selection condition.
See Also
PropertyName Element for ItemSelectionCondition for CustomControl for View
Specifies the .NET property whose value is displayed by the control. This element is used
when
defining a custom control view
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by
CustomControl for View the control.
Text Value
Specify the name of the .NET property whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for CustomControl for View
Specifies the script whose value is displayed by the control. This element is used when
defining a
custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by
CustomControl for View the control.
Text Value
Specify the script whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for CustomControl for View
Defines how the data is displayed, such as shifting the data to the left or right. This
element is
used when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
Syntax
XML
<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>
Attributes
None.
Child Elements
Element Description
Element
Specifies how many characters the first line of data is shifted to the left.
Specifies how many characters the first line of data is shifted to the
right.
Specifies how many characters the data is shifted away from the left
margin.
Specifies how many characters the data is shifted away from the right
margin.
Parent Elements
Element Description
CustomItem Element for CustomEntry Defines what data is displayed by the control and how it
for View is displayed.
Remarks
You cannot specify the FirstLineHanging and the FirstLineIndent elements in the same
Frame element.
See Also
FirstLineHanging Element
FirstLineIndent Element
LeftIndent Element
RightIndent Element
Specifies how many characters the first line of data is shifted to the left. This element is
used
when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineHanging Element
Syntax
XML
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
CustomControl for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineIndent element.
See Also
FirstLineIndent Element for Frame for CustomControl for View
Specifies how many characters the first line of data is shifted to the right. This element is
used
when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineIndent Element
Syntax
XML
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
CustomControl for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineHanging element.
See Also
FirstLineHanging Element for Frame for CustomControl for View
Specifies how many characters the data is shifted away from the left margin. This
element is used
when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
LeftIndent Element
Syntax
XML
<LeftIndent>CharactersToShift</LeftIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
CustomControl for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the left.
Remarks
See Also
Frame Element for CustomItem for CustomControl for View
Specifies how many characters the data is shifted away from the right margin. This
element is used
when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
RightIndent Element
Syntax
XML
<RightIndent>CharactersToShift</RightIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem for Defines how the data is displayed, such as shifting the
CustomControl for View data to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the right.
Remarks
See Also
Frame Element for CustomItem for CustomControl for View
Adds a blank line to the display of the control. This element is used when defining a
custom control
view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
NewLine Element
Syntax
XML
<NewLine/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for View Defines a control for the custom control view.
Remarks
See Also
CustomItem Element for CustomEntry for View
Specifies text that is added to the data that is displayed by the control, such as a label,
brackets
to enclose the data, and spaces to indent the data. This element is used when
defining a custom
control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Text Element
Syntax
XML
<Text>TextToDisplay</Text>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for View Defines a control for the custom control view.
Text Value
Specify the text of a control for data that you want to display.
Remarks
See Also
CustomItem Element for CustomEntry for View
Defines the .NET types that use this custom entry or the condition that must exist for
this entry to be used.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
Attributes
None.
Child Elements
Element Description
CustomEntry
Specifies a .NET type that uses this definition of
the control view.
Parent Elements
Element Description
CustomEntry Element for CustomEntries for Defines the controls used by specific .NET
View objects.
Remarks
You must specify at least one type, selection set, or selection condition for an entry.
There is no
maximum limit to the number of child elements that you can use.
Selection conditions are used to define a condition that must exist for the entry to be
used, such
as when an object has a specific property or when a specific property value
or script evaluates to
true . For more information about selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
For more information about the components of a custom control view, see Custom
Control View.
See Also
SelectionCondition Element for EntrySelectedBy for CustomEntry
Defines a condition that must exist for a control definition to be used. This element is
used when
defining a custom control view.
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or the
CustomEntry for CustomControl for condition that must exist for this definition to be used.
View
Remarks
When you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
See Also
PropertyName Element for SelectionCondition for CustomControl for View
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the definition is used.
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist to expand the
EntrySelectedBy for EnumerableExpansion collection objects of this definition.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify at least one property name or a script to evaluate,
but cannot
specify both. For more information about how to use selection conditions,
see Defining Conditions for when Data is Displayed.
See Also
Defining Conditions for When Data is Displayed
Schema
Configuration Element
DefaultSettings Element
EnumerableExpansions Element
EnumerableExpansion Element
EntrySelectedBy Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist to expand the
EntrySelectedBy for EnumerableExpansion collection objects of this definition.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify at least one script or property name to evaluate,
but cannot
specify both. For more information about how to use selection conditions,
see Defining Conditions for when Data is Displayed.
See Also
Defining Conditions for When Data Is Displayed
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met and the object is displayed using this control. This
element is used
when defining a custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for EntrySelectedBy Defines a condition that must exist for the
for CustomControl for View control definition to be used.
Text Value
Specify the name of the selection set.
Remarks
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Sets of Objects.
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
See Also
SelectionCondition Element for EntrySelectedBy for CustomControl for View
Specifies a .NET type that triggers the condition. This element is used when defining a
custom
control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for EntrySelectedBy Defines a condition that must exist for the
for CustomControl for View control definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
See Also
SelectionCondition Element for EntrySelectedBy for CustomControl for View
Specifies a set of .NET objects for the list entry. There is no limit to the number of
selection
sets that can be specified for an entry.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this custom entry or the
CustomEntry for View condition that must exist for this entry to be used.
Text Value
Specify the name of the selection set.
Remarks
Each custom control entry must have at least one type name, selection set, or selection
condition
defined.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For example, you might want to create a table view and a list
view for the same set
of objects. For more information about defining selection sets, see
Defining Selection Sets.
For more information about the components of a custom control view, see Creating
Custom Controls.
See Also
EntrySelectedBy Element for CustomEntry for View
Specifies a .NET type that uses this definition of the custom control view. There is no
limit to the
number of types that can be specified for a definition.
Schema
Configuration Element
ViewDefinitions Element
View Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this custom control view definition or
for CustomEntry for View the condition that must exist for this definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
Each custom control view definition must have at least one type name, selection set, or
selection
condition defined.
For more information about the components of a custom control view, see Creating
Custom Controls.
See Also
Creating Custom Controls
Defines how a new group of objects is displayed. This element is used when defining a
table, list,
wide, or custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
Syntax
XML
<GroupBy>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
<Label>TextToDisplay</Label>
<CustomControl>...</CustomControl>
<CustomControlName>NameOfControl</CustomControlName>
</GroupBy>
Attributes
None.
Child Elements
Element Description
GroupBy
Defines the custom control that display new groups.
Element Description
GroupBy
Specifies the name of a control that is used to display the new
group.
GroupBy
Specifies the .NET property the starts a new group whenever
its value changes.
Specifies the script that starts a new group whenever its value
changes.
Parent Elements
Element Description
View Element Defines a view that displays one or more .NET objects.
Remarks
When defining how a new group of objects is displayed, you must specify the property
or script that
will start the new group; however, you cannot specify both.
See Also
CustomControlName Element for GroupBy
View Element
Writing a PowerShell Formatting File
CustomControl Element for GroupBy
Article • 09/17/2021
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
Syntax
XML
<CustomControl>
<CustomEntries>...</CustomEntries>
<CustomControl>
any order.
Attributes
None.
Child Elements
Element Description
Element Description
GroupBy Element for View Defines how Windows PowerShell displays a new group of objects.
Remarks
See Also
CustomEntries Element for CustomControl for GroupBy
Provides the definitions for the control. This element is used when defining how a new
group of
objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
Syntax
XML
<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>
Attributes
None.
Child Elements
Element Description
Element Description
Parent Elements
Element Description
CustomControl Element for GroupBy Defines the custom control that displays the new group.
Remarks
In most cases, a control has only one definition, which is specified in a single
CustomEntry
element. However, it is possible to provide multiple definitions if you want
See Also
CustomEntry Element for CustomEntries for Controls for View
Provides a definition of the control. This element is used when defining how a new
group of objects
is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
Syntax
XML
<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
CustomEntries Element for CustomControl for GroupBy Provides the definitions for the control.
Remarks
See Also
EntrySelectedBy Element for CustomEntry for GroupBy
Defines what data is displayed by the custom control view and how it is displayed. This
element is
used when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomItem Element
Syntax
XML
<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<Frame>...</Frame>
<NewLine/>
<Text>TextToDisplay</Text>
</CustomItem>
Attributes
None.
Child Elements
Element Description
GroupBy
Defines what data is displayed by the custom control
view and how it is displayed.
GroupBy
Adds a blank line to the display of the control.
GroupBy
Specifies additional text to the data displayed by the
control.
Parent Elements
Element Description
CustomEntry Element for CustomControl for Provides a definition of the custom control
GroupBy view.
Remarks
See Also
CustomEntry Element for CustomControl for GroupBy
Defines the data that is displayed by the control. This element is used when defining
how a new
group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
Syntax
XML
<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>
Attributes
None.
Child Elements
Element Description
GroupBy
Specifies the name of a
common control or a view
control.
GroupBy
Defines the condition that must
exist for this control to be used.
Parent Elements
Element Description
CustomItem Element for Defines what data is displayed by the custom control view
CustomEntry for GroupBy and how it is displayed.
See Also
CustomControlName Element for ExpressionBinding for GroupBy
Specifies the name of a common control or a view control. This element is used when
defining how a
new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
CustomControlName Element
Syntax
XML
<CustomControlName>NameofCustomControl</CustomControlName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
GroupBy control.
Text Value
Specify the name of the control.
Remarks
You can create common controls that can be used by all the views of a formatting file,
and you can
create view controls that can be used by a specific view. The following
elements specify the names
of these controls:
See Also
Name Element for Control for Controls for Configuration
Specifies that the elements of collections are displayed. This element is used when
defining how a
new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
EnumerateCollection Element
Syntax
XML
<EnumerateCollection/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
GroupBy control.
Remarks
See Also
ExpressionBinding Element for CustomItem for GroupBy
Defines the condition that must exist for this control to be used. There is no limit to the
number
of selection conditions that can be specified for a control item. This element is
used when defining
how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
Syntax
XML
<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
Attributes
None.
Child Elements
Element Description
for GroupBy
Specifies the .NET property that triggers the
condition.
GroupBy
Specifies the script that triggers the
condition.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
GroupBy control.
Remarks
You can specify one property name or a script for this condition but cannot specify both.
See Also
Writing a PowerShell Formatting File
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the control is used. This element is
used when
defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for Defines the condition that must exist for this
ExpressionBinding for GroupBy control to be used.
Text Value
Specify the name of the .NET property that triggers the condition.
Remarks
If this element is used, you cannot specify the ScriptBlock
element when defining the
selection condition.
See Also
ScriptBlock Element for ItemSelectionCondition for GroupBy
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the control is used. This element is used when defining how a new
group of
objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ItemSelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for Defines the condition that must exist for this
ExpressionBinding for GroupBy control to be used.
Text Value
Specify the script that is evaluated.
Remarks
If this element is used, you cannot specify the PropertyName
element when defining the
selection condition.
See Also
ItemSelectionCondition Element for ExpressionBinding for GroupBy
Specifies the .NET property whose value is displayed by the control. This element is used
when
defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
GroupBy control.
Text Value
Specify the name of the .NET property whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for GroupBy
Specifies the script whose value is displayed by the control. This element is used when
defining how
a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
ExpressionBinding Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ExpressionBinding Element for CustomItem for Defines the data that is displayed by the
GroupBy control.
Text Value
Specify the script whose value is displayed by the control.
Remarks
See Also
ExpressionBinding Element for CustomItem for GroupBy
Defines how the data is displayed, such as shifting the data to the left or right. This
element is
used when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
Syntax
XML
<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>
Attributes
None.
Child Elements
Element Description
GroupBy
Specifies how many characters the first line of data
is shifted to the left.
GroupBy
Specifies how many characters the first line of data
is shifted to the right.
GroupByRightIndent Element
Specifies how many characters the data is shifted
away from the right margin.
Parent Elements
Element Description
CustomItem Element for CustomEntry Defines what data is displayed by the control and how
for GroupBy it is displayed.
Remarks
You cannot specify the FirstLineHanging and the FirstLineIndent elements in the same
Frame element.
See Also
FirstLineHanging Element for Frame for GroupBy
Specifies how many characters the first line of data is shifted to the left. This element is
used
when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineHanging Element
Syntax
XML
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem Defines how the data is displayed, such as shifting the data
for GroupBy to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineIndent element.
See Also
FirstLineIndent Element for Frame for GroupBy
Specifies how many characters the first line of data is shifted to the right. This element is
used
when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element for View
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
FirstLineIndent Element
Syntax
XML
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem Defines how the data is displayed, such as shifting the data
for GroupBy to the left or right.
Text Value
Specify the number of characters that you want to shift the first line of the data.
Remarks
If this element is specified, you cannot specify the FirstLineHanging element.
See Also
FirstLineHanging Element for Frame for GroupBy
Specifies how many characters the data is shifted away from the left margin. This
element is used
when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
LeftIndent Element
Syntax
XML
<LeftIndent>CharactersToShift</LeftIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem Defines how the data is displayed, such as shifting the data
for GroupBy to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the left.
Remarks
See Also
Frame Element for CustomItem for GroupBy
Specifies how many characters the data is shifted away from the right margin. This
element is used
when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Frame Element
RightIndent Element
Syntax
XML
<RightIndent>CharactersToShift</RightIndent>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Frame Element for CustomItem Defines how the data is displayed, such as shifting the data
for GroupBy to the left or right.
Text Value
Specify the number of characters that you want to shift the data to the right.
Remarks
See Also
Frame Element for CustomItem for GroupBy
Adds a blank line to the display of the control. This element is used when defining how a
new group
of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
NewLine Element
Syntax
XML
<NewLine/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines a control for the custom control view.
GroupBy
Remarks
See Also
CustomItem Element for CustomEntry for GroupBy
Specifies text that is added to the data that is displayed by the control, such as a label,
brackets
to enclose the data, and spaces to indent the data. This element is used when
defining how a new
group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
CustomItem Element
Text Element
Syntax
XML
<Text>TextToDisplay</Text>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
CustomItem Element for CustomEntry for Defines a control for the custom control view.
GroupBy
Text Value
Specify the text of a control for data that you want to display.
Remarks
See Also
CustomItem Element for CustomEntry for GroupBy
Defines the .NET types that use this control definition or the condition that must exist
for this
definition to be used. This element is used when defining how a new group of
objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element for View
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
condition
for a definition. There is no maximum limit to the number of child elements
that you can use.
Attributes
None.
Child Elements
Element Description
GroupBy
Specifies a .NET type that uses this definition of
the control.
Parent Elements
Element Description
CustomEntry Element for CustomControl for GroupBy Provides a definition of the control.
Remarks
Selection conditions are used to define a condition that must exist for the definition to
be used,
such as when an object has a specific property or when a specific property
value or script evaluates
to true . For more information about selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
See Also
SelectionCondition Element for EntrySelectedBy for GroupBy
Defines a condition that must exist for a control definition to be used. This element is
used when
defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element for View
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
GroupBy
Specifies a .NET property that triggers the
condition.
GroupBy
Specifies the script that triggers the
condition.
GroupBy
Specifies a .NET type that triggers the
condition.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or the
CustomEntry for GroupBy condition that must exist for this definition to be used.
Remarks
When you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both. For more information about how to use selection conditions, see Defining
Conditions for when Data is Displayed.
See Also
PropertyName Element for SelectionCondition for CustomControl for View
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the definition is used. This element
is used when
defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the control
EntrySelectedBy for GroupBy definition to be used.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify a least one property name or a script, but cannot
specify both.
For more information about how selection conditions can be used, see
Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for GroupBy
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the definition is used. This element is used when defining how a
new group of
objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the control
EntrySelectedBy for GroupBy definition to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify a least one script or property name to evaluate, but
cannot
specify both. For more information about how selection conditions can be used,
see Defining Conditions for Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for GroupBy
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met, and the object is displayed by using this control.
This element is
used when defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the control
EntrySelectedBy for GroupBy definition to be used.
Text Value
Specify the name of the selection set.
Remarks
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Selection Sets.
See Also
TypeName Element for SelectionCondition for GroupBy
Specifies a .NET type that triggers the condition. This element is used when defining
how a new
group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines a condition that must exist for the control
EntrySelectedBy for GroupBy definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
When this element is specified, you cannot specify the SelectionSetName element. For
more
information about defining selection conditions, see Defining Conditions for
Displaying Data.
See Also
SelectionCondition Element for EntrySelectedBy for GroupBy
Specifies a set of .NET objects for the list entry. There is no limit to the number of
selection
sets that can be specified for an entry. This element is used when defining how
a new group of
objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this custom entry or the
CustomEntry for GroupBy condition that must exist for this entry to be used.
Text Value
Specify the name of the selection set.
Remarks
Each custom control definition must have at least one type name, selection set, or
selection
condition defined.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For example, you may want to create a table view and a list view
for the same set of
objects. For more information about defining selection sets, see
Defining Selection Sets.
For more information about the components of a custom control view, see Creating
Custom Controls.
See Also
EntrySelectedBy Element for CustomEntry for GroupBy
Specifies a .NET type that uses this definition of the custom control. This element is used
when
defining how a new group of objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControl Element
CustomEntries Element
CustomEntry Element
EntrySelectedBy Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element for Defines the .NET types that use this control definition or the
CustomEntry for GroupBy condition that must exist for this definition to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
Each control definition must have at least one type name, selection set, or selection
condition
defined.
For more information about the components of a custom control view, see Creating
Custom Controls.
See Also
Creating Custom Controls
Specifies the name of a custom control that is used to display the new group. This
element is used
when defining a table, list, wide or custom control view.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
CustomControlName Element
Syntax
XML
<CustomControlName>ControlName</CustomControlName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
GroupBy Element for View Defines how Windows PowerShell displays a new group of objects.
Text Value
Specify the name of the custom control that is used to display a new group.
Remarks
You can create common controls that can be used by all the views of a formatting file,
and you can
create view controls that can be used by a specific view. The following
elements specify the names
of these custom controls:
See Also
GroupBy Element for View
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
Label Element
Syntax
XML
<Label>DisplayedLabel</Label>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
GroupBy Element for View Defines how a new group of objects is displayed.
Text Value
Specify the text that is displayed whenever Windows PowerShell encounters a new
property or script
value.
Remarks
In addition to the text specified by this element, Windows PowerShell displays the new
value that
starts the group, and adds a blank line before and after the group.
Example
The following example shows the label for a new group. The displayed label would look
similar to
this: Service Type: NewValueofProperty
XML
<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>
For an example of a complete formatting file that includes this element, see Wide View
(GroupBy).
See Also
GroupBy Element for View
Specifies the .NET property that starts a new group whenever its value changes.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
GroupBy Element for View Defines how a group of .NET objects is displayed.
Text Value
Specify the .NET property name.
Remarks
Windows PowerShell starts a new group whenever the value of this property changes.
Example
The following example shows how to start a new group when the value of a property
changes.
XML
<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>
For an example of a complete formatting file that includes this element, see Wide View
(GroupBy).
See Also
GroupBy Element for View
Specifies the script that starts a new group whenever its value changes.
Schema
Configuration Element
ViewDefinitions Element
View Element
GroupBy Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
GroupBy Element for View Defines how a group of .NET objects is displayed.
Text Value
Specify the script that is evaluated.
Remarks
PowerShell starts a new group whenever the value of this script changes.
See Also
PropertyName Element for GroupBy
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
Syntax
XML
<ListControl>
<ListEntries>...</ListEntries>
</ListControl>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
View Element Defines a view that is used to display the members of one or more objects.
Remarks
For more information about creating a list view, see Creating a List View.
Example
This example shows a list view for the System.Serviceprocess.Servicecontroller
object.
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>...</ListEntry>
</ListEntries>
</ListControl>
</View>
See Also
View Element
ListEntries Element
Provides the definitions of the list view. The list view must specify one or more
definitions.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
Syntax
XML
<ListEntries>
<ListEntry>...</ListEntry>
</ListEntries>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
Remarks
For more information about list views, see List View.
Example
This example shows the XML elements that define the list view for the
System.Serviceprocess.Servicecontroller
object.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>...</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
See Also
ListControl Element
ListEntry Element
List View
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
Syntax
XML
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>
Attributes
None.
Child Elements
Element Description
Defines the properties and scripts whose values are displayed by the list
view.
Parent Elements
Element Description
Remarks
A list view is a list format that displays property values or script values for each object.
For
more information about list views, see Creating a List View.
Example
This example shows the XML elements that define the list view for the
System.Serviceprocess.Servicecontroller
object.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>...</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
See Also
Creating a List View
EntrySelectedBy Element for ListEntry
ListEntries Element
ListItems Element
Defines the .NET types that use this list view definition or the condition that must exist
for this
definition to be used. In most cases only one definition is needed for a list view.
However, you can
provide multiple definitions for the list view if you want to use the
same list view to display
different data for different objects.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
Attributes
None.
Child Elements
Element Description
ListControl
Specifies a .NET type that uses this list view
definition.
Parent Elements
Element Description
ListEntry Element for ListControl Defines how the rows of the list are displayed.
Remarks
You must specify at least one type, selection set, or selection condition for a list view
definition. There is no maximum limit to the number of child elements that you can use.
Selection conditions are used to define a condition that must exist for the definition to
be used,
such as when an object has a specific property or that a specific property value
or script evaluates
to true . For more information about selection conditions, see
Defining Conditions for when Data is displayed.
For more information about the components of a list view, see Creating a List View.
Example
The following example shows how to define the objects for a list view using their .NET
type name.
XML
<ListEntry>
<EntrySelectedBy>
<TypeName>NameofDotNetType</TypeName>>
</EntrySelectedBy>
</ListEntry>
See Also
ListEntry Element for ListControl
Defines the condition that must exist to use this definition of the list view. There is no
limit to
the number of selection conditions that can be specified for a list definition.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this table entry or the condition
for TableRowEntry that must exist for this entry to be used.
Remarks
lWhen you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
For more information about other components of a list view, see Creating a List View.
See Also
Creating a List View
ListEntry Element
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the list entry is used.
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this list
EntrySelectedBy for ListEntry entry to be used.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify at least one property name or a script block, but
cannot
specify both. For more information about how to use selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
For more information about other components of a list view, see Creating List View.
See Also
Creating a List View
ListEntry Element
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the list entry is used.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this list
EntrySelectedBy for ListEntry entry to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify a least one script or property name to evaluate, but
cannot
specify both. (For more information about how selection conditions can be used,
see Defining Conditions for when a View Entry or Item is Used.)
For more information about the other components of a list view, see List View.
See Also
ListEntry Element
List View
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met, and the object is displayed by using this definition
of the list
view.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist to use this
EntrySelectedBy for ListEntry definition of the list view.
Text Value
Specify the name of the selection set.
Remarks
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Sets of Objects.
For more information about other components of a list view, see Creating a List View.
See Also
Creating a List View
Specifies a .NET type that triggers the condition. When this type is present, the list entry
is used.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this list
EntrySelectedBy for ListControl entry to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both. For more information about how to use selection conditions, see
Defining Conditions for when Data is Displayed.
For more information about other the components of a list view, see Creating a List
View.
See Also
Creating a List View
Specifies a set of .NET objects for the list entry. There is no limit to the number of
selection
sets that can be specified for an entry.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this list entry or the condition that
for ListEntry must exist for this entry to be used.
Text Value
Specify the name of the selection set.
Remarks
Each list entry must have at least one type name, selection set, or selection condition
defined.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For example, you might want to create a table view and a list
view for the same set
of objects. For more information about defining selection sets, see
Defining Sets of objects for a View.
For more information about the components of a list view, see Creating a List View.
Example
The following example shows how to specify a selection set for an entry of a list view.
XML
<ListEntry>
<EntrySelectedBy>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>
See Also
Creating a List View
Specifies a .NET type that uses this entry of the list view. There is no limit to the number
of
types that can be specified for a list entry.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
EntrySelectedBy
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this list entry or the condition that
for ListEntry must exist for this entry to be used.
Text Value
Specify the fully-qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
Each list entry must have at least one type name, selection set, or selection condition
defined.
For more information about how this element is used in a list view, see List View.
Example
The following example shows how to specify a selection set for an entry of a list view.
XML
<ListEntry>
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>
See Also
Creating a List View
Defines the properties and scripts whose values are displayed in the rows of the list
view.
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
Syntax
XML
<ListItems>
<ListItem>...</ListItem>
</ListItems>
Attributes
None.
Child Elements
Element Description
Element Description
ListControl
Defines the property or script whose value is displayed by the list
view.
Parent Elements
Element Description
Remarks
For more information about this type of view, see Creating a List View.
Example
This example shows the XML elements that define three rows of the list view.
XML
<ListEntry>
<ListItems>
<ListItem>
<Label>Property1: </Label>
<PropertyName>.NetTypeProperty1</PropertyName>
</ListItem>
<ListItem>
<PropertyName>.NetTypeProperty2</PropertyName>
</ListItem>
<ListItem>
</ListItem>
</ListEntry>
See Also
ListEntry Element for ListControl
Specifies a format pattern that defines how the property or script value is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
FormatString Element
Syntax
XML
<FormatString>PropertyPattern</FormatString>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ListItem Element Defines the property or script whose value is displayed in a row of the list view.
Text Value
Specify the pattern that is used to format the data. For example, you can use this pattern
to format
the value of any property that is of type System.Timespan:
{0:MMM}{0:dd}
{0:HH}:{0:mm}.
Remarks
Format strings can be used when creating table views, list views, wide views, or custom
views. For
more information about formatting a value displayed in a view, see
Formatting Displayed Data.
For more information about using format strings in list views, see Creating List View.
Example
The following example shows how to define a formatting string for the value of the
StartTime
property.
XML
<ListItem>
<PropertyName>StartTime</PropertyName>
</ListItem>
See Also
Creating a List View
ListItem Element
Defines the condition that must exist for this list item to be used.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
ItemSelectionCondition Element
Syntax
XML
<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
Attributes
None.
Child Elements
Element Description
for ListControl
Specifies the .NET property that triggers
the condition.
ListControl
Specifies the script that triggers the
condition.
Parent Elements
Element Description
ListItem Element for ListItems for Defines the property or script whose value is displayed in a
ListControl row of the list view.
Remarks
You can specify one property name or a script for this condition but cannot specify both.
See Also
ListItem Element for ListItems for ListControl
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the view is used. This element is
used when defining
a list view.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
ItemSelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Text Value
Specify the name of the property whose value is displayed.
Remarks
If this element is used, you cannot specify the ScriptBlock
element when defining the
selection condition.
See Also
ScriptBlock Element for ItemSelectionCondition for ListIControl
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the list item is used. This element is used when defining a list view.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element for ListControl
ListEntry Element for ListEntries for ListControl
ListItems Element for ListEntry for ListControl
ListItem Element for ListItems for List Control
ItemSelectionCondition Element for ListItem for ListControl
ScriptBlock Element for ItemSelectionCondition for ListControl
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ItemSelectionCondition Element for ListItem Defines the condition that must exist for this list
for ListControl item to be used.
Text Value
Specify the script that is evaluated.
Remarks
If this element is used, you cannot specify the PropertyName element when defining the
selection
condition.
See Also
Writing a PowerShell Formatting File
Label Element for ListItem for
ListControl
Article • 09/17/2021
Specifies the label that is displayed to the left of the property or script value in the row.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
Label Element
Syntax
XML
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ListItem Element for ListItems for Defines the property or script whose value is displayed in a
ListControl row of the list view.
Text Value
Specify the label to be display to the left of the property or script value.
Remarks
If a label is not specified, the name of the property or the script is displayed. For more
information about using labels in a list view, see Creating a List View.
Example
The following example shows how to add a label to a row.
XML
<ListItem>
<Label>Property1: </Label>
<PropertyName>DotNetProperty1</PropertyName>
</ListItem>
See Also
Creating a List View
ListItem Element
Defines the property or script whose value is displayed in a row of the list view.
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
Syntax
XML
<ListItem>
<PropertyName>PropertyToDisplay</PropertyName>
<ScriptBlock>ScriptToExecute</ScriptBlock>
<Label>LabelToDisplay</Label>
<FormatString>FormatPattern</FormatString>
<ItemSelectionCondition>...</ItemSelectionCondition>
</ListItem>
Attributes
None
Child Elements
Element Description
ListControl
Specifies a format string that defines how the property
or script value is displayed.
ListControl
Specifies the label that is displayed to the left of the
property or script value in the row.
for ListControl
Specifies the .NET property whose value is displayed in
the row.
ListControl
Specifies the script whose value is displayed in the row.
Parent Elements
Element Description
ListItems Element for List Defines the properties and scripts whose values are displayed in
Control the list view.
Remarks
For more information about the components of a list view, see Creating a List View.
Example
This example shows the XML elements that define three rows of the list view. The first
two rows
display the value of a .NET property, and the last row displays a value
generated by a script.
XML
<ListEntry>
<ListItems>
<ListItem>
<Label>Property1: </Label>
<PropertyName>DotNetProperty1</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DotNetProperty2</PropertyName>
</ListItem>
<ListItem>
</ListItem>
</ListItems>
</ListEntry>
See Also
ListItems Element
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ListItem Defines the property or script whose value is displayed in the row of the list
Element view.
Text Value
Specify the name of the property whose value is displayed.
Remarks
When this element is specified, you cannot specify the ScriptBlock element.
In addition to displaying the property value, you can also specify a label for the value or
a format
string that can be used to change the display of the value. For more
information about specifying
data in a list view, see Creating a List View.
Example
The following example shows how to specify the label and property whose value is
displayed.
XML
ListItem>
<Label>NameOfProperty</Label>
<PropertyName>.NetTypeProperty</PropertyName>
</ListItem>
See Also
ScriptBlock Element for ListItem for ListControl
Schema
Configuration Element
ViewDefinitions Element
View Element
ListControl Element
ListEntries Element
ListEntry Element
ListItems Element
ListItem Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ListItem Element Defines the property or script whose value is displayed in a row of the list view.
Text Value
Specify the script whose value is displayed in the row.
Remarks
When this element is specified, you cannot specify the PropertyName
element.
For more information about specifying scripts in a list view, see List View.
Example
The following example shows how to specify the property whose value is displayed.
XML
<ListItem>
</ListItem>
See Also
PropertyName Element for ListItem for ListControl
Schema
Configuration Element
ViewDefinitions Element
View Element
Name Element
Syntax
XML
<Name>ViewName</Name>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
View Element Defines a view that is used to display the members of one or more .NET objects.
Text Value
Specify a unique friendly name for the view. This name can include a reference to the
type of the
view (such as a table view or list view), which object or set of objects use the
view, what command
returns the objects, or a combination of these.
Remarks
For more information about the different types of views, see the following topics: Table
View,
List View, Wide View, and Custom View.
Example
The following example shows a View element that defines a table view for the
System.Serviceprocess.Servicecontroller
object. The name of the view is "service".
XML
<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
See Also
Creating a List View
View Element
In a pipeline, the first object emitted is chosen as the type to format the output of the
pipeline.
PowerShell attempts for format subsequent objects using the same view. If the
object does not fit
the view, it is not displayed. You can create OutOfBand views that can
be used for format these
other types.
Schema
Configuration Element
ViewDefinitions Element
View Element
OutOfBand Element
Syntax
XML
<OutOfBand/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
View Element Defines a view that displays one or more .NET objects.
Remarks
When the "shape" of formatting (view) has been determined by previous objects, you
may want objects
of different types to continue using that shape (table, list, or whatever)
even if they specify
their own views. Or sometimes you want your view to take over.
When OutOfBand is true, the view
applies regardless of previous objects that may have
selected a different view.
See Also
View Element
Schema
ViewDefinitions Element
View Element
TableControl Element
Syntax
XML
<TableControl>
<AutoSize/>
<HideTableHeaders/>
<TableHeaders>...</TableHeaders>
<TableRowEntries>...</TableRowEntries>
</TableControl>
are optional.
Attributes
None.
Child Elements
Element Description
Element Description
TableControl
Specifies whether the column size and the number of columns are
adjusted based on the size of the data.
for TableControl
Indicates whether the header of the table is not displayed.
TableControl
Defines the labels, the widths, and the alignment of the data for the
columns of the table view.
for TableControl
Provides the definitions of the table view.
Parent Elements
Element Description
View Element Defines a view that is used to display the members of one or more objects.
Remarks
For more information about the components of a table view, see Creating a Table View.
Example
This example shows a TableControl element that is used to display the properties of the
System.Serviceprocess.Servicecontroller
object.
XML
<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>...</TableHeaders>
<TableRowEntries>...</TableRowEntries>
</TableControl>
</View>
See Also
Creating a Table View
View Element
HideTableHeaders Element
TableHeaders Element
TableRowEntries Element
Specifies whether the column size and the number of columns are adjusted based on
the size of the
data.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
AutoSize Element
Syntax
XML
<AutoSize/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
See Also
Creating a Table View
TableControl Element
Schema
ViewDefinitions Element
View Element
TableControl Element
HideTableHeaders Element
Syntax
VB
<HideTableHeaders/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Remarks
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
TableControl Element
TableHeaders Element
Article • 09/17/2021
Schema
ViewDefinitions Element
View Element
TableControl Element
TableHeaders Element for TableControl
Syntax
XML
<TableHeaders>
<TableColumnHeader>...</TableColumnHeader>
</TableHeaders>
Attributes
None.
Child Elements
Element Description
Element Description
Element
Defines the label, the width, and the alignment of the data for a column
of a table view.
Parent Elements
Element Description
Remarks
For more information about the components of a table view, see Creating a Table View.
Example
This example shows a TableHeaders element that defines two column headers.
XML
<TableHeaders>
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Column 2</Label)
<Width>10</Width>
<Alignment>Centered</Alignment>
</TableColumnHeader>
</TableHeaders>
See Also
Creating a Table View
TableColumnHeader Element
TableControl Element
Writing a PowerShell Formatting File
TableColumnHeader Element
Article • 09/17/2021
Defines the label, the width of the column, and the alignment of the label for a column
of the
table.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableHeaders Element
TableColumnHeader Element
Syntax
XML
<TableColumnHeader>
<Label>DisplayedLabel</Label>
<Width>NumberOfCharacters</Width>
</TableColumnHeader>
Attributes
None.
Child Elements
Element Description
Element Description
TableColumnHeader for
TableControl Defines the label that is displayed at the top of the column. If no
label is specified, the name of the property whose value is displayed
in the rows is used.
TableColumnHeader for
TableControl Specifies the width (in characters) of the column.
TableColumnHeader for
TableControl Specifies how the label of the column is displayed. If no alignment is
specified, the label is aligned on the left.
Parent Elements
Element Description
Remarks
Specify a header for each column of the table. The columns are displayed in the order in
which the
TableColumnHeader elements are defined.
For more information about the components of a table view, see Table View.
Example
The following example shows two TableColumnHeader elements. The first element
defines a column
whose label is "Column 1", has a width of 16 characters, and whose
label is aligned on the left. The
second element defines a column whose label is
"Column 2", has a width of 10 characters, and whose
label is centered in the column.
XML
<TableHeaders>
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Column 2</Label)
<Width>10</Width>
<Alignment>Centered</Alignment>
</TableColumnHeader>
</TableHeaders>
See Also
Alignment Element for TableColumnHeader for TableControl
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableHeaders Element
TableColumnHeader Element
Alignment Element
Syntax
XML
<Alignment>AlignmentType</Alignment>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableColumnHeader Defines a label, the width, and the alignment of the data for a column
Element of the table.
Text Value
Specify one of the following values. These values are not case-sensitive.
Left - Aligns the data displayed in the column on the left This is the default if this
element is
not specified.
Right - Aligns the data displayed in the column on the right.
Center - Centers the data displayed in the column.
Remarks
For more information about the components of a table view, see Creating a Table View.
Example
This example shows a TableColumnHeader element whose data is aligned on the center.
XML
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Center</Alignment>
</TableColumnHeader>
See Also
Creating a Table View
TableColumnHeader Element
Defines the label that is displayed at the top of a column. This element is used when
defining a
table view.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableHeaders Element
TableColumnHeader Element
Label Element
Syntax
XML
<Label>DisplayedLabel</Label>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableColumnHeader Element for Defines a label, the width, and the alignment of the
TableHeaders for TableControl data for a column of the table.
Text Value
Specify the text that is displayed at the top of the column of the table. There are no
restricted
characters for the column label.
Remarks
If no label is specified, the name of the property whose value is displayed in the rows is
used.
For more information about the components of a table view, see Creating a Table View.
Example
This example shows a TableColumnHeader element whose label is "Column 1".
XML
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
See Also
Creating a Table View
TableColumnHeader Element
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableHeaders Element
TableColumnHeader
Width Element
Syntax
XML
<Width>NumberOfCharacters</Width>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
TableColumnHeader Element for Defines a label, width, and alignment of the data
TableHeaders for TableControl for a column of the table.
Text Value
When at all possible, specify a width (in characters) that is greater than the length of the
displayed property values.
Remarks
For more information about the components of a table view, see Creating a Table View.
Example
The following example shows a TableColumnHeader element whose width is 16
characters.
XML
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
See Also
Creating a Table View
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
Syntax
XML
<TableRowEntries>
<TableRowEntry>...</TableRowEntry>
</TableRowEntries>
Attributes
None.
Child Elements
Element Description
TableControl
Defines the data that is displayed in a row of
the table.
Parent Elements
Element Description
Remarks
You must specify one or more TableRowEntry elements for the table view. There is no
maximum limit
to the number of TableRowEntry elements that can be added nor is their
order significant.
For more information about the components of a table view, see Creating a Table View.
Example
The following example shows a TableRowEntries element that defines a row that
displays the values
of two properties of the System.Diagnostics.Process
object.
XML
<TableRowEntries>
<TableRowEntry>
<EntrySelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</EntrySelectedBy>
<TableColumnItems>
<TableColumnItem>
<PropertyName> Property for first column</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName> Property for second column</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
See Also
Creating a Table View
TableControl Element
TableRowEntry Element
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element for TableControl
TableRowEntry Element for TableRowEntries for TableControl
TableColumnItems Element for TableControlEntry for TableControl
Syntax
XML
<TableColumnItems>
<TableColumnItem>...</TableColumnItem>
</TableColumnItems>
Attributes
None.
Child Elements
Element Description
Element Description
Parent Elements
Element Description
TableRowEntry Element for TableRowEntries for Defines the data that is displayed in a row of
TableControl the table.
Remarks
A TableColumnItem element is required for each column of the row. The first entry is
displayed in
first column, the second entry in the second column, and so on.
For more information about the components of a table view, see Creating a Table View.
Example
The following example shows a TableColumnItems element that defines three properties
of the System.Diagnostics.Process
object.
XML
<TableColumnItems>
<TableColumnItem>
<PropertyName>Status</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
See Also
Creating a Table View
TableColumnItem Element
TableRowEntry Element
Defines the property or script whose value is displayed in the column of the row.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
TableColumnItems Element
TableColumnItem Element
Syntax
XML
<TableColumnItem>
<FormatString>FormatPattern</FormatString>
<PropertyName>Nameof.NetProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</TableColumnItem>
Attributes
None.
Child Elements
Element Description
Element Description
FormatString Element for Specifies a format pattern that is used to format the
TableColumnItem for TableControl data in the column of the row.
Parent Elements
Element Description
TableColumnItems Element for Defines the properties or scripts whose values are
TableControlEntry for TableControl displayed in the row.
Remarks
You can specify a property of an object or a script in each column of the row. If no child
elements
are specified, the item is a placeholder, and no data is displayed.
For more information about the components of a table view, see Creating a Table View.
Example
This example shows a TableColumnItem element that displays the value of the Status
property of
the System.Diagnostics.Process object.
XML
<TableColumnItem>
<Alignment>Centered</Alignment>
<PropertyName>Status</PropertyName>
</TableColumnItem>
See Also
Creating a Table View
TableColumnItems Element
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
TableColumnItems Element
TableColumnItem Element
Alignment Element
Syntax
XML
<Alignment>AlignmentType</Alignment>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableColumnItem Defines a label, the width, and the alignment of the data for a column of
Element the table.
Text Value
Specify one of the following values. (These values are not case-sensitive.)
Left - Shifts the data displayed in the column to the left. (This is the default if this
element
is not specified.)
Right - Shifts the data displayed in the column to the right.
Center - Centers the data displayed in the column.
Remarks
For more information about the components of a table view, see Table View.
See Also
Table View
TableColumnItem Element
FormatString Element for
TableColumnItem for TableControl
Article • 01/18/2022
Specifies a format pattern that defines how the property or script value of the table is
displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
TableColumnItems Element
TableColumnItem Element
FormatString Element
Syntax
XML
<FormatString>FormatPattern</FormatString>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableColumnItem Defines the property or script whose value is displayed in the column of
Element the row.
Text Value
Specify the pattern that is used to format the data. For example, this pattern can be
used to format
the value of any property that is of type System.Timespan:
{0:MMM}
{0:dd}{0:HH}:{0:mm}.
Remarks
Format strings can be used when creating table views, list views, wide views, or custom
views. For
more information about formatting a value displayed in a view, see
Formatting Displayed Data.
For more information about the components of a table view, see Table View.
Example
The following example shows how to define a formatting string for the value of the
StartTime
property.
XML
<TableColumnItem>
<PropertyName>StartTime</PropertyName>
</TableColumnItem>
See Also
Creating a Table View
TableColumnItem Element
Specifies the property whose value is displayed in the column of the row.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
TableColumnItems Element
TableColumnItem Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableColumnItem Defines the property or script whose value is displayed in the column of
Element the row.
Text Value
Specify the name of the property whose value is displayed.
Remarks
For more information about the components of a table view, see Creating a Table View.
Example
This example shows a TableColumnItem element that specifies the Status property of
the System.Diagnostics.Process
object.
XML
<TableColumnItem>
<Alignment>Centered</Alignment>
<PropertyName>Status</PropertyName>
</TableColumnItem>
See Also
Creating a Table View
TableColumnItem Element
Specifies the script whose value is displayed in the column of the row.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
TableColumnItems Element
TableColumnItem Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableColumnItem Defines the property or script whose value is displayed in the column of
Element the row.
Text Value
Specify the script whose value is displayed.
Remarks
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
TableColumnItem Element
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element for TableControl
TableRowEntry Element for TableRowEntries
Syntax
XML
<TableRowEntry>
<Wrap/>
<EntrySelectedBy>...</EntrySelectedBy>
<TableColumnItems>...</TableColumnItems>
</TableRowEntry>
Attributes
None.
Child Elements
Element Description
Element Description
TableControl
Specifies that text that exceeds the column width is
displayed on the next line.
Parent Elements
Element Description
Remarks
One TableColumnItems element and one EntrySelectedBy element must be specified.
For more information about the components of a table view, see Creating a Table View.
Example
The following example shows a TableRowEntry element that defines a row that displays
the values of
two properties of the System.Diagnostics.Process object.
XML
<TableRowEntry>
<EntrySelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</EntrySelectedBy>
<TableColumnItems>
<TableColumnItem>
</TableColumnItem>
<TableColumnItem>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
See Also
Creating a Table View
Defines the .NET types that use this definition of the table view or the condition that
must exist
for this definition to be used.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
Attributes
None.
Child Elements
Element Description
TableControl
Specifies a .NET type that uses this table view
definition.
Parent Elements
Element Description
TableRowEntry Element for TableControl Defines the data that is displayed in a row of the table.
Remarks
You must specify at least one type, selection set, or selection condition for a table view
definition. There is no maximum limit to the number of child elements that you can use.
Selection conditions are used to define a condition that must exist for the definition to
be used,
such as when an object has a specific property or that a specific property value
or script evaluates
to true . For more information about selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
For more information about the components of a table view, see Creating a Table View.
Example
The following example shows a TableRowEntry element that is used to display the
properties of the System.Diagnostics.Process object.
XML
<TableRowEntry>
<EntrySelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</EntrySelectedBy>
<TableColumnItems>
<TableColumnItem>
<PropertyName>PropertyForFirstColumn</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>PropertyForSecondColumn</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
See Also
Creating a Table View
Defines the condition that must exist to use for this definition of the table view. There is
no
limit to the number of selection conditions that can be specified for a table
definition.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this table entry or the condition
for TableRowEntry that must exist for this entry to be used.
Remarks
Each list entry must have at least one type name, selection set, or selection condition
defined.
When you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how to use selection conditions, see Defining Conditions
for when a View Entry or Item is Used.
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
EntrySelectedBy Element
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the table entry is used.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this
EntrySelectedBy for TableRowEntry table entry to be used.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify at least one property name or a script block, but
cannot
specify both. For more information about how selection conditions can be used,
see Defining Conditions for when a View Entry or Item is Used.
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
Specifies the script block that triggers the condition. When this script is evaluated to
true , the
condition is met, and the table entry is used.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
SelectionCondition Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this
EntrySelectedBy for TableRowEntry table entry to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify at least one script block or property name, but
cannot specify
both. For more information about how to use selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met, and the object is displayed by using this definition
of the table
view.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist to use for this
EntrySelectedBy for TableRowEntry definition of the table view.
Text Value
Specify the name of the selection set.
Remarks
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Sets of Objects.
For more information about other components of a wide view, see Creating a Table
View.
See Also
Creating a Table View
Specifies a .NET type that triggers the condition. When this type is present, the condition
is met,
and the table row is used.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this
EntrySelectedBy for TableRowEntry table row to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both. For more information about how to use selection conditions, see
Defining Conditions for when a View Entry or Item is Used.
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
Specifies a set of .NET types the use this entry of the table view. There is no limit to the
number
of selection sets that can be specified for an entry.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Defines the .NET types that use this entry or the condition that must exist for
Element this entry to be used.
Text Value
Specify the name of the selection set.
Remarks
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For example, you might want to create a table view and a list
view for the same set
of objects. For more information about defining selection sets, see
Defining Sets of objects for a View.
If you specify a selection set for an entry, you cannot specify a type name. For more
information
about how to specify a .NET type, see TypeName Element for
EntrySelectedBy for TableRowEntry.
For more information about the components of a table view, see Creating a Table View.
See Also
EntrySelectedBy Element
Specifies a .NET type that uses this entry of the table view. There is no limit to the
number of
types that can be specified for a table entry.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element
TableRowEntry Element
EntrySelectedBy Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Defines the .NET types that use this entry or the condition that must exist for
Element this entry to be used.
Text Value
Specify the name of the .NET type.
Remarks
Each list entry must have at least one type name, selection set, or selection condition
defined.
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
EntrySelectedBy Element
Specifies that text that exceeds the column width is displayed on the next line. By
default, text
that exceeds the column width is truncated.
Schema
Configuration Element
ViewDefinitions Element
View Element
TableControl Element
TableRowEntries Element for TableControl
TableRowEntry Element for TableRowEntries for TableControl
Wrap Element for TableRowEntry for TableControl
Syntax
XML
<Wrap/>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
TableRowEntry Element for TableRowEntries for Defines the data that is displayed in a row of
TableControl the table.
Remarks
For more information about the components of a table view, see Creating a Table View.
See Also
Creating a Table View
Defines the .NET objects that are displayed by the view. Each view must specify at least
one .NET
object.
Schema
ViewDefinitions Element
View Element
ViewSelectedBy Element
Syntax
XML
<ViewSelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>SelectionSet</SelectionSetName>
</ViewSelectedBy>
Attributes
None.
Child Elements
Element Description
ViewSelectedBy
Specifies a set of .NET objects that are displayed by
the view.
Parent Elements
Element Description
View Element Defines a view that displays one or more .NET objects.
Remarks
For more information about how this element is used in different views, see Table View
Components, List View Components, Wide View Components, and Custom Control
Components.
The SelectionSetName element is used when the formatting file defines a set of objects
that are
displayed by multiple views. For more information about how selection sets are
defined and
referenced, see Defining Sets of Objects.
Example
The following example shows how to specify the System.Serviceprocess.Servicecontroller
object for a list view. The same schema is used for table, wide, and custom views.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>
See Also
Creating a List View
Creating a Table View
TypeName Element
Schema
Configuration Element
ViewDefinitions Element
View Element
ViewSelectedBy Element
SelectionSetName Element
Syntax
XML
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
ViewSelectedBy Element Defines the .NET objects that are displayed by the view.
Text Value
Specify the name of the selection set that is defined by the Name element for the
selection set.
Remarks
You can use selection sets when you have a set of related objects that you want to
reference by
using a single name, such as a set of objects that are related through
inheritance. For more
information about defining and referencing selection sets, see
Defining Sets of Objects.
Example
The following example shows how to specify a selection set for a list view. The same
schema is used
for table, wide, and custom views.
XML
<View>
<Name>Name of View</Name>
<ViewSelectedBy>
<SelectionSetName>NameofSelectionSet</SelectionSetName>>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>
See Also
Defining Selection Sets
ViewSelectedBy Element
Schema
Configuration Element
ViewDefinitions Element
View Element
ViewSelectedBy Element
TypeName Element
Syntax
XML
<TypeName>FullyQualifiedTypeName</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
ViewSelectedBy Element Defines the .NET objects that are displayed by the view.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
For more information about how this element is used in different views, see Creating a
Table View,
Creating a List View, Creating a Wide View,
and Custom View Components.
Example
The following example shows how to specify the System.Serviceprocess.Servicecontroller
object for a list view. The same schema is used for table, wide, and custom views.
XML
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>
See Also
Creating a List View
ViewSelectedBy Element
Defines a wide (single value) list format for the view. This view displays a single property
value
or script value for each object.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
Syntax
XML
<WideControl>
<AutoSize/>
<ColumnNumber>PositiveInteger</ColumnNumber>
<WideEntries>...</WideEntries>
</WideControl>
the same
time.
Attributes
None.
Child Elements
Element Description
Element Description
WideControl
Specifies whether the column size and the number of columns are
adjusted based on the size of the data.
for WideControl
Specifies the number of columns displayed in the wide view.
Parent Elements
Element Description
View Element Defines a view that is used to display one or more .NET objects.
Remarks
When defining a wide view, you can add the AutoSize element or the ColumnNumber but
you cannot
add both.
In most cases, only one definition is required for each wide view, but it is possible to
have
multiple definitions if you want to use the same view to display different .NET
objects. In those
cases, you can provide a separate definition for each object or set of
objects.
For more information about the components of a wide view, see Wide View
Components.
Example
The following example shows a WideControl element that is used to display a property
of the System.Diagnostics.Process object.
XML
<View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>...</WideEntries>
</WideControl>
</View>
See Also
Autosize Element for WideControl
View Element
WideEntries Element
Specifies whether the column size and the number of columns are adjusted based on
the size of the
data.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
Autosize Element
Syntax
XML
<AutoSize/>
Attributes
None.
Child Elements
None
Parent Elements
Element Description
WideControl Element Defines a wide (single value) list format for the view.
Remarks
When defining a wide view, you can add the AutoSize element or the ColumnNumber
element, but you cannot add both.
For more information about the components of a wide view, see Creating a Wide View.
See Also
ColumnNumber Element for WideControl
WideControl Element
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
ColumnNumber Element
Syntax
XML
<ColumnNumber>PositiveInteger</ColumnNumber>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
WideControl Element Defines a wide (single value) list format for the view.
Text Value
Specify a positive integer value.
Remarks
When defining a wide view, you can add the AutoSize element or the ColumnNumber
element, but you
cannot add both.
For more information about the components of a wide view, see Creating a Wide View.
See Also
Autosize Element for WideControl
Provides the definitions of the wide view. The wide view must specify one or more
definitions.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
Syntax
XML
<WideEntries>
<WideEntry>...</WideEntry>
</WideEntries>
Attributes
None.
Child Elements
Element Description
Element Description
WideControl Element Defines a wide (single value) list format for the view.
Remarks
A wide view is a list format that displays a single property value or script value for each
object.
For more information about the components of a wide view, see Wide View
Components.
Example
The following example shows a WideEntries element that defines a single WideEntry
element. The
WideEntry element contains a single WideItem element that defines what
property or script value
is displayed in the view.
XML
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>...</WideItem>
<WideEntry>
</WideEntries>
</WideControl>
See Also
Creating a Wide View
WideControl Element
WideEntry Element
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
Syntax
XML
<WideEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<WideItem>...</WideItem>
</WideEntry>
Attributes
None.
Child Elements
Element Description
Element Description
Parent Elements
Element Description
Remarks
A wide view is a list format that displays a single property value or script value for each
object.
Unlike other types of views, you can specify only one item element for each view
definition. For
more information about the other components of a wide view, see
Creating a Wide View.
Example
The following example shows a WideEntry element that defines a single WideItem
element. The
WideItem element defines the property whose value is displayed in the
view.
XML
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
WideEntries Element
WideItem Element
Defines the .NET types that use this definition of the wide view or the condition that
must exist
for this definition to be used.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
Syntax
XML
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>
Attributes
None.
Child Elements
Element Description
for WideEntry
Specifies a .NET type that uses this wide view
definition.
Parent Elements
Element Description
Remarks
You must specify at least one type, selection set, or selection condition for a wide view
definition. There is no maximum limit to the number of child elements that you can use.
Selection conditions are used to define a condition that must exist for the definition to
be used,
such as when an object has a specific property or that a specific property value
or script value
evaluates to true . For more information about selection conditions, see
Defining Conditions for Displaying Data.
For more information about other components of a wide view, see Creating a Wide
View.
See Also
WideEntry Element
Defines the condition that must exist for this definition to be used. There is no limit to
the
number of selection conditions that can be specified for a wide entry definition.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
SelectionCondition Element
Syntax
XML
<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
Attributes
None.
Child Elements
Element Description
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this wide entry or the condition that
for WideEntry must exist for this entry to be used.
Remarks
Each wide entry must have at least one type name, selection set, or selection condition
defined.
When you are defining a selection condition, the following requirements apply:
The selection condition must specify a least one property name or a script block,
but cannot
specify both.
The selection condition can specify any number of .NET types or selection sets, but
cannot specify
both.
For more information about how to use selection conditions, see Defining Conditions
for when a View Entry or Item is Used.
For more information about other components of a wide view, see Creating a Wide
View.
See Also
Creating a Wide View
Specifies the .NET property that triggers the condition. When this property is present or
when it
evaluates to true , the condition is met, and the definition is used.
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
SelectionCondition Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
C#
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this
EntrySelectedBy for WideEntry definition to be used.
Text Value
Specify the .NET property name.
Remarks
The selection condition must specify at least one property name or a script to evaluate,
but cannot
specify both. For more information about how to use selection conditions,
see Defining Conditions for when Data is Displayed.
For more information about other components of a wide view, see Wide View.
See Also
Creating a Wide View
Specifies the script that triggers the condition. When this script is evaluated to true , the
condition is met, and the wide entry definition is used.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
SelectionCondition
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this
EntrySelectedBy for WideEntry definition to be used.
Text Value
Specify the script that is evaluated.
Remarks
The selection condition must specify at least one script or property name to evaluate,
but cannot
specify both. For more information about how to use selection conditions,
see Defining Conditions for when Data is Displayed.
For more information about other components of a wide view, see Wide View.
See Also
Creating a Wide View
Specifies the set of .NET types that trigger the condition. When any of the types in this
set are
present, the condition is met, and the object is displayed by using this definition
of the wide
view.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
SelectionCondition Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this
EntrySelectedBy for WideEntry definition to be used.
Text Value
Specify the name of the selection set.
Remarks
The selection condition can specify a selection set or .NET type, but cannot specify both.
For more
information about how to use selection conditions, see Defining Conditions
for when Data is Displayed.
Selection sets are common groups of .NET objects that can be used by any view that the
formatting
file defines. For more information about creating and referencing selection
sets, see Defining Sets of Objects.
For more information about other components of a wide view, see Creating a Wide
View.
See Also
Creating a Wide View
Specifies a .NET type that triggers the condition. When this type is present, the
definition is
used.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
SelectionCondition Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
SelectionCondition Element for Defines the condition that must exist for this wide
EntrySelectedBy for WideEntry entry to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
The selection condition can specify a .NET type or a selection set, but cannot specify
both. For
more information about how to use selection conditions, see Defining
Conditions for when Data is Displayed.
For more information about other components of a wide view, see Creating a Wide
View.
See Also
Creating a Wide View
Specifies a .NET type for the definition. The definition is used whenever this object is
displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
TypeName Element
Syntax
XML
<TypeName>Nameof.NetType</TypeName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this wide entry or the condition that
for WideEntry must exist for this entry to be used.
Text Value
Specify the fully qualified name of the .NET type, such as System.IO.DirectoryInfo .
Remarks
Each wide entry must specify one or more .NET types, a selection set, or the selection
condition
that must exist for the definition to be used.
For more information about other components of a wide view, see Creating a Wide
View.
See Also
Creating a Wide View
Specifies a set of .NET objects for the definition. The definition is used whenever one of
these
objects is displayed.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
EntrySelectedBy Element
SelectionSetName Element
Syntax
XML
<SelectionSetName>NameofSelectionSet</SelectionSetName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
EntrySelectedBy Element Defines the .NET types that use this wide entry or the condition that
for WideEntry must exist for this entry to be used.
Text Value
Specify the name of the selection set.
Remarks
Each definition must specify one type name, selection set, or selection condition.
Selection sets are typically used when you want to define a group of objects that are
used in
multiple views. For example, you might want to create a table view and a list
view for the same set
of objects. For more information about defining selection sets, see
Defining Sets of Objects for a View.
For more information about other components of a wide view, see Creating a Wide
View.
See Also
Creating a Wide View
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
WideItem Element
Syntax
XML
<WideItem>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToExecute</ScriptBlock>
<FormatString>FormatPattern</FormatString>
</WideItem>
Attributes
None.
Child Elements
Element Description
Element Description
PropertyName Element for Specifies the property of the object whose value is displayed
WideItem in the wide view.
ScriptBlock Element for WideItem Specifies the script whose value is displayed in the wide view.
Parent Elements
Element Description
Remarks
For more information about the components of a wide view, see Wide View.
Example
The following example shows a WideEntry element that defines a single WideItem
element. The
WideItem element defines the property or script whose value is displayed
in the view.
XML
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
See Also
FormatString Element for WideItem for WideControl
WideEntry Element
Specifies a format pattern that defines how the property or script value is displayed in
the view.
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
WideItem Element
FormatString Element
Syntax
XML
<FormatString>PropertyPattern</FormatString>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
WideItem Element for Defines the property or script whose value is displayed in a row of
WideControl the list view.
Text Value
Specify the pattern that is used to format the data. For example, you can use this pattern
to format
the value of any property that is of type System.Timespan:
{0:MMM}{0:dd}
{0:HH}:{0:mm}.
Remarks
Format strings can be used when creating table views, list views, wide views, or custom
views. For
more information about formatting a value displayed in a view, see
Formatting Displayed Data.
For more information about using format strings in wide views, see Creating a Wide
View.
Example
The following example shows how to define a formatting string for the value of the
StartTime
property.
XML
<WideItem>
<PropertyName>StartTime</PropertyName>
</WideItem>
See Also
Creating a Wide View
Specifies the property of the object whose value is displayed in the wide view.
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
WideItem Element
PropertyName Element
Syntax
XML
<PropertyName>.NetTypeProperty</PropertyName>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
Element Description
WideItem Element Defines the property or script whose value is displayed in the wide view.
Text Value
Specify the name of the property whose value is displayed.
Remarks
For more information about the components of a wide view, see Creating a Wide View.
Example
This example shows a wide view that displays the value of the ProcessName property of
the System.Diagnostics.Process
object.
XML
View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
See Also
WideItem Element
Schema
Configuration Element
ViewDefinitions Element
View Element
WideControl Element
WideEntries Element
WideEntry Element
WideItem Element
ScriptBlock Element
Syntax
XML
<ScriptBlock>ScriptToExecute</ScriptBlock>
Attributes
None.
Child Elements
None.
Parent Elements
Element Description
WideItem Defines the property or script block whose value is displayed in the wide
Element view.
Text Value
Specify the script whose value is displayed.
Remarks
For more information about the components of a wide view, see Creating a Wide View.
Example
This example shows a WideItem element that defines a script whose value is displayed in
the view.
XML
<WideItem>
<ScriptBlock>ScriptToExecute</ScriptBlock>
</WideItem>
See Also
WideItem Element
PowerShell scripts and functions should be fully documented whenever they are shared
with others.
The Get-Help cmdlet displays the script and function help topics in the
same format as it displays
help for cmdlets, and all of the Get-Help parameters work on
script and function help topics.
PowerShell scripts can include a help topic about the script and help topics about each
functions in
the script. Functions that are shared independently of scripts can include
their own help topics.
This document explains the format and correct placement of the help topics, and it
suggests
guidelines for the content.
Comment-Based Help
The help topic that describes a script or function can be implemented as a set of
comments within
the script or function. When writing comment-based help for a script
and for functions in a script,
pay careful attention to the rules for placing the comment-
based help. The placement determines
whether the Get-Help cmdlet associates the help
topic with the script or a function. For more
information about writing comment-based
help topics, see
about_Comment_Based_Help.
Online Help
You can post your help topics on the internet and then direct Get-Help to open the
topics. For
more information about writing comment-based help topics, see
Supporting
Online Help.
There is no established method for writing conceptual ("About") topics for scripts and
functions.
However, you can post conceptual topics on the internet list the topics and
their URLs in the
Related Links section of a command help topic.
For example, the following detailed description states that the New-Topic
command is a script.
This reminds users that they need to specify the path and full
name when they run it.
"The New-Topic script creates a blank conceptual topic for each topic name in
the input file..."
In a script help topic, explain how to use the script as a whole. If you are also
writing help
topics for functions in the script, mention the functions in your script
help topic and include
references to the function help topics in the Related Links
section of the script help topic.
Conversely, when a function is part of a script,
explain in the function help topic the role that
the function plays in the script and
how it might be used independently. Then list the script help
topic in the Related
Links section of the function help topic.
When writing examples for a script help topic, be sure to include the path to the
script file in
the example command. This reminds users that they must specify the
path explicitly, even when the
script is in the current directory.
In a function help topic, remind users that the function exists only in the current
session and,
to use it in other sessions, they need to add it, or add it a PowerShell
profile.
Get-Help displays the help topic for a script or function only when the script file
and help
topic files are saved in the correct locations. Therefore, it is not useful to
include
instructions for installing PowerShell, or saving or installing the script or
function in a script
or function help topic. Instead, include any installation
instructions in the document that you
use to distribute the script or function.
See Also
Writing Comment-Based Help Topics
Writing Comment-Based Help Topics
Article • 09/17/2021
You can write comment-based Help topics for functions and scripts by using special
Help comment keywords.
The Get-Help cmdlet displays comment-based Help in the same format in which it
displays the
cmdlet Help topics that are generated from XML files. Users can use all of
the parameters of
Get-Help , such as Detailed, Full, Example, and Online, to display
function and script Help.
You can also write XML-based Help topics for scripts and functions and use the Help
comment
keywords to redirect users to the XML-based topics or other topics.
In This Section
Syntax of Comment-Based Help
Describes the syntax of comment-based help.
Syntax Diagram
The syntax for comment-based Help is as follows:
# <help content>
-or -
<#
#>
Syntax Description
Comment-based Help is written as a series of comments. You can type a comment
symbol ( # ) before
each line of comments, or you can use the <# and #> symbols to
create a comment block. All the
lines within the comment block are interpreted as
comments.
A comment block must contain at least one help keyword. Some of the keywords, such
as EXAMPLE,
can appear many times in the same comment block. The Help content for
each keyword begins on the
line after the keyword and can span multiple lines.
PowerShell
<#
.Description
The Get-Function function displays the name and syntax of all functions
in the session.
#>
Note that the .EXTERNALHELP keyword takes precedence over all other comment-based
help keywords.
When .EXTERNALHELP is present, the
Get-Help cmdlet does not display
comment-based help, even when it cannot find a help file that matches the value of the
keyword.
.SYNOPSIS
A brief description of the function or script. This keyword can be used only once in each
topic.
.DESCRIPTION
A detailed description of the function or script. This keyword can be used only once in
each topic.
.PARAMETER <Parameter-Name>
The description of a parameter. You can include a .PARAMETER keyword for each
parameter in the
function or script.
The .PARAMETER keywords can appear in any order in the comment block, but the order
in which the
parameters appear in the Param statement or function declaration
determines the order in which the
parameters appear in Help topic. To change the order
of parameters in the Help topic, change the
order of the parameters in the Param
statement or function declaration.
You can also specify a parameter description by placing a comment in the Param
statement
immediately before the parameter variable name. If you use both a Param
statement comment and a
.PARAMETER keyword, the description associated with the
.PARAMETER keyword is used, and the
Param statement comment is ignored.
.EXAMPLE
A sample command that uses the function or script, optionally followed by sample
output and a
description. Repeat this keyword for each example.
.INPUTS
The Microsoft .NET Framework types of objects that can be piped to the function or
script. You can
also include a description of the input objects.
.OUTPUTS
The .NET Framework type of the objects that the cmdlet returns. You can also include a
description
of the returned objects.
.NOTES
Additional information about the function or script.
.LINK
The name of a related topic. Repeat this keyword for each related topic. This content
appears in the
Related Links section of the Help topic.
The .LINK keyword content can also include a Uniform Resource Identifier (URI) to an
online
version of the same Help topic. The online version opens when you use the
Online parameter of
Get-Help . The URI must begin with "http" or "https".
.COMPONENT
The name of the technology or feature that the function or script uses, or to which it is
related.
The Component parameter of Get-Help uses this value to filter the search
results returned by
Get-Help .
.ROLE
The name of the user role for the help topic. The Role parameter of Get-Help uses this
value
to filter the search results returned by Get-Help .
.FUNCTIONALITY
The keywords that describe the intended use of the function. The Functionality
parameter of
Get-Help uses this value to filter the search results returned by Get-Help .
.FORWARDHELPTARGETNAME <Command-Name>
Redirects to the Help topic for the specified command. You can redirect users to any
Help topic,
including Help topics for a function, script, cmdlet, or provider.
.FORWARDHELPCATEGORY <Category>
Specifies the Help category of the item in .FORWARDHELPTARGETNAME . Use this keyword to
avoid
conflicts when there are commands with the same name.
Alias
Cmdlet
HelpFile
Function
Provider
General
FAQ
Glossary
ScriptCommand
ExternalScript
Filter
All
.REMOTEHELPRUNSPACE <PSSession-variable>
Specifies a session that contains the Help topic. Enter a variable that contains a
PSSession. This
keyword is used by the Export-PSSession cmdlet to find the Help topics
for the exported commands.
The .EXTERNALHELP keyword takes precedence over all other comment-based help
keywords. When
.EXTERNALHELP is present, the Get-Help
cmdlet does not display
comment-based help, even when it cannot find a help file that matches the
value of the
keyword.
When the function is exported by a script module, the value of .EXTERNALHELP should be
a filename
without a path. Get-Help looks for the file in a locale-specific subdirectory of
the module
directory. There are no requirements for the filename, but a best practice is
to use the following
filename format: <ScriptModule>.psm1-help.xml .
When the function is not associated with a module, include a path and filename in the
value of the
.EXTERNALHELP keyword. If the specified path to the XML file contains UI-
culture-specific
subdirectories, Get-Help searches the subdirectories recursively for an
XML file with the name of
the script or function in accordance with the language
fallback standards established for Windows,
just as it does for all XML-based Help
topics.
For more information about the cmdlet Help XML-based Help file format, see
Writing
Windows PowerShell Cmdlet Help.
Placing Comment-Based Help in
Functions
Article • 09/17/2021
This topic explains where to place comment-based help for a function so that the Get-
Help cmdlet
associates the comment-based help topic with the correct function.
Before the Function keyword. When the function is in a script or script module,
there cannot be
more than one blank line between the last line of the comment-
based help and the Function
keyword. Otherwise, Get-Help associates the help
with the script, not with the function.
PowerShell
function MyProcess
<#
.Description
#>
Get-Process powershell
PowerShell
function MyFunction
Get-Process powershell
<#
.Description
#>
PowerShell
<#
.Description
#>
This topic explains where to place comment-based help for a script so that the Get-Help
cmdlet
associates the comment-based help topic with scripts and not with any functions
that might be in the
script.
Script Help can be preceded in the script only by comments and blank lines.
If the first item in the script body (after the Help) is a function declaration, there
must be at
least two blank lines between the end of the script Help and the
function declaration. Otherwise,
the Help is interpreted as being Help for the
function, not Help for the script.
PowerShell
<#
.Description
#>
param [string]$ComputerName
...
PowerShell
...
<#
.Description
#>
Autogenerated Elements
The Get-Help cmdlet automatically generates the following elements of a help topic.
You cannot
edit these elements directly, but in many cases you can change the results
by changing the source of
the element.
Name
The Name section of a function Help topic is taken from the function name in the
function
definition. The Name of a script Help topic is taken from the script filename. To
change the name
or its capitalization, change the function definition or the script
filename.
Syntax
The Syntax section of the Help topic is generated from the parameter list in the Param
statement of
the function or script. To add detail to the Help topic syntax, such as the
.NET type of a
parameter, add the detail to the parameter list. If you do not specify a
parameter type, the
Object type is inserted as the default value.
Parameter List
The Parameters section of the Help topic is generated from the parameter list in the
function or
script and from the descriptions that you add by using the .Parameters
keyword or comments in the
parameter list.
Parameters appear in the Parameters section in the same order that they appear in the
parameter
list. The spelling and capitalization of parameter names is also taken from the
parameter list; it
is not affected by the parameter name specified by the .Parameter
keyword.
Common Parameters
The common parameters are added to the syntax and parameter list of the Help topic,
even if they
have no effect. For more information about the common parameters, see
about_CommonParameters.
Remarks
The Remarks section of the Help topic is automatically generated from the function or
script name.
You cannot change or affect its content.
Examples of Comment-Based Help
Article • 09/17/2021
This topic includes example that demonstrate how to use comment-based help for
scripts and
functions.
PowerShell
function Add-Extension
$name
<#
.SYNOPSIS
.DESCRIPTION
.PARAMETER Name
.PARAMETER Extension
.INPUTS
.OUTPUTS
.EXAMPLE
File.txt
.EXAMPLE
File.doc
.EXAMPLE
File.doc
.LINK
.LINK
Set-Item
#>
The following output shows the results of a Get-Help command that displays the help
for the
Add-Extension function.
PowerShell
Output
NAME
Add-Extension
SYNOPSIS
SYNTAX
DESCRIPTION
PARAMETERS
-Name
Required? false
Position? 0
Default value
-Extension
Required? false
Position? 1
Default value
<CommonParameters>
"get-help about_commonparameters".
INPUTS
OUTPUTS
File.txt
File.doc
File.doc
RELATED LINKS
Set-Item
Notice the blank lines between the closing #> and the Param statement. In a script that
does
not have a Param statement, there must be at least two blank lines between the
final comment in
the Help topic and the first function declaration. Without these blank
lines, Get-Help associates
the Help topic with the function, instead of the script.
PowerShell
<#
.SYNOPSIS
.DESCRIPTION
The Update-Month.ps1 script updates the registry with new data generated
.PARAMETER InputPath
.PARAMETER OutputPath
Specifies the name and path for the CSV-based output file. By default,
MonthlyUpdates.ps1 generates a name from the date and time it runs, and
.INPUTS
.OUTPUTS
.EXAMPLE
PS> .\Update-Month.ps1
.EXAMPLE
.EXAMPLE
#>
function Get-Data { }
The following command gets the script Help. Because the script is not in a directory that
is listed
in the Path environment variable, the Get-Help command that gets the script
Help must specify the
script path.
PowerShell
Output
NAME
C:\ps-test\Update-Month.ps1
SYNOPSIS
SYNTAX
<String>] [<CommonParameters>]
DESCRIPTION
PARAMETERS
-InputPath
Required? true
Position? 0
Default value
-OutputPath
Required? false
Position? 1
Default value
<CommonParameters>
This cmdlet supports the common parameters: -Verbose, -
Debug,
"get-help about_commonparameters".
INPUTS
OUTPUTS
PS> .\Update-Month.ps1
C:\Reports\2009\January.csv
RELATED LINKS
PowerShell
function Add-Extension
param
[string]
$name,
[string]
$extension = "txt"
$name
<#
.SYNOPSIS
...
#>
The results are the same as the results for Example 1. Get-Help interprets the parameter
descriptions as though they were accompanied by the .Parameter keyword.
PowerShell
# .ExternalHelp C:\MyScripts\Update-Month-Help.xml
function Get-Data { }
The following example shows the use of the .ExternalHelp keyword in a function.
PowerShell
function Add-Extension
$name
# .ExternalHelp C:\ps-test\Add-Extension.xml
PowerShell
function help
<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
[CmdletBinding(DefaultParameterSetName='AllUsersView')]
param(
[Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
[System.String]
${Name},
...
The following command uses this feature. When a user types a Get-Help command for
the Help
function, Get-Help displays the Help topic for the Get-Help cmdlet.
PowerShell
Output
NAME
Get-Help
SYNOPSIS
...
PowerShell cmdlets can be useful, but unless your Help topics clearly explain what the
cmdlet does
and how to use it, the cmdlet may not get used or, even worse, it might
frustrate users. The
XML-based cmdlet Help file format enhances consistency, but great
help requires much more.
If you have never written cmdlet Help, review the following guidelines. The XML schema
required to
author the cmdlet Help topic is described in the following section. Start with
Creating the Cmdlet Help File. That topic includes a
description of the top-level XML
nodes.
Write well
Nothing replaces a well-written topic. If you are not a professional writer, find a writer or
editor
to help you. Another alternative is to copy your Help text into Microsoft Word
and use the grammar
and spelling checks to improve your work.
Write simply
Use simple words and phrases. Avoid jargon. Consider that many readers are equipped
only with a
foreign-language dictionary and your Help topic.
Write consistently
Help for related cmdlets should be similar (for example, get-x and set-x). Use the
standard
descriptions for standard parameters, like Force and InputObject. (Copy them
from Help for
the core cmdlets.) Use standard terms. For example, use "parameter", not
"argument", and use
"cmdlet" not "command" or "command-let."
See Also
How to Create the Cmdlet Help File
How to Add the Cmdlet Name and Synopsis to a Cmdlet Help Topic
This section describes how to create a valid XML file that contains content for Windows
PowerShell
cmdlet Help topics. This section discusses how to name the Help file, how to
add the appropriate XML
headers, and how to add nodes that will contain the different
sections of the cmdlet Help content.
7 Note
For a complete view of a Help file, open one of the dll-Help.xml files located in the
Windows
PowerShell installation directory. For example, the
Microsoft.PowerShell.Commands.Management.dll-Help.xml file contains content for
several of the
PowerShell cmdlets.
<PSSnapInAssemblyName>.dll-Help.xml
2. Add the following XML headers to the text file. Be aware that the file will be
validated against
the Microsoft Assistance Markup Language (MAML) schema.
Currently, PowerShell does not provide
any tools to validate the file.
schema="maml">
3. Add a Command node to the cmdlet Help file for each cmdlet in the assembly.
Each node within the
Command node relates to the different sections of the
cmdlet Help topic.
The following table lists the XML element for each node, followed by a descriptions
of each node.
Node Description
<details> Adds content for the NAME and SYNOPSIS sections of the
cmdlet Help topic. For more information, see How to Add the
Cmdlet Name and Synopsis.
Node Description
<maml:description> Adds content for the DESCRIPTION section of the cmdlet Help
topic. For more information, see How to Add the Detailed
Description to a Cmdlet Help Topic.
<command:syntax> Adds content for the SYNTAX section of the cmdlet Help topic.
For more information, see How to Add Syntax to a Cmdlet Help
Topic.
<command:parameters> Adds content for the PARAMETERS section of the cmdlet Help
topic. For more information, see How to Add Parameters to a
Cmdlet Help Topic.
<command:inputTypes> Adds content for the INPUTS section of the cmdlet Help topic.
For more information, see How to Add Input Types to a Cmdlet
Help Topic.
<command:returnValues> Adds content for the OUTPUTS section of the cmdlet Help topic.
For more information, see How to Add Return Values to a Cmdlet
Help Topic.
<maml:alertset> Adds content for the NOTES section of the cmdlet Help topic. For
more information, see How to add Notes to a Cmdlet Help Topic.
<command:examples> Adds content for the EXAMPLES section of the cmdlet Help topic.
For more information, see How to Add Examples to a Cmdlet
Help Topic.
<maml:relatedLinks> Adds content for the RELATED LINKS section of the cmdlet Help
topic. For more information, see How to Add Related Links to a
Cmdlet Help Topic.
Example
Here is an example of a Command node that includes the nodes for the various sections
of the
cmdlet Help topic.
XML
<command:command
xmlns:maml="http://schemas.microsoft.com/maml/2004/10"
xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10"
xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
</command:details>
<maml:description>
</maml:description>
<command:syntax>
</command:syntax>
<command:parameters>
</command:parameters>
<command:inputTypes>
</command:inputTypes>
<command:returnValues>
</command:returnValues>
<maml:alertSet>
</maml:alertSet>
<command:examples>
</command:examples>
<maml:relatedLinks>
</maml:relatedLinks>
</command:command>
See Also
How to Add the Cmdlet Name and Synopsis
This section describes how to add content that is displayed in the NAME and SYNOPSIS
sections of the cmdlet help. In the Help file, this content is added to the Command node
for each
cmdlet.
7 Note
For a complete view of a Help file, open one of the dll-Help.xml files located in the
PowerShell
installation directory. For example, the
Microsoft.PowerShell.Commands.Management.dll-Help.xml
file contains content for
In the synopsis do not repeat the cmdlet name. Informing the user that the Get-
Server cmdlet
gets a server is brief, but not informative. Instead, use synonyms
and add details to the
description.
Use simple verbs like "get", "create", and "change" in the synopsis. Avoid using
"set" because it
is vague, and fancy words such as "modify."
Write in active voice. For example, "Use the TimeSpan object..." is much clearer
than "the
TimeSpan object can be used to..."
Avoid the verb "display" when describing cmdlets that get objects. Although
Windows PowerShell
displays cmdlet data, it is important to introduce users to the
concept that the cmdlet returns
.NET Framework objects whose data may not be
displayed. If you emphasize the display, the user
might not realize that the cmdlet
may have returned many other useful properties and methods that
are not
displayed.
See Also
Windows PowerShell SDK
How to Add a Cmdlet Description
Article • 09/17/2021
This section describes how to add content that is displayed in the DESCRIPTION section
of the cmdlet
Help. In the Help file, this content is added to the Command node for
each cmdlet.
7 Note
For a complete view of a Help file, open one of the dll-Help.xml files located in the
PowerShell
installation directory. For example, the
Microsoft.PowerShell.Commands.Management.dll-Help.xml
file contains content for
To Add a Description
Begin by explaining the basic features of the cmdlet in more detail. In many cases,
you can
explain the terms used in the cmdlet name and illustrate unfamiliar
concepts with an example. For
example, if the cmdlet appends data to a file,
explain that it adds data to the end of an existing
file.
To find all of the features of the cmdlet, review the parameter list. Describe the
primary
function of the cmdlet, and then include other functions and features. For
example, if the main
function of the cmdlet is to change one property, but the
cmdlet can change all of the properties,
say so in the detailed description. If the
cmdlet parameters let the users solicit information in
different ways, explain it.
Include information on ways that users can use the cmdlet, in addition to the
obvious uses. For
example, you can use the object that the Get-Host cmdlet
retrieves to change the color of text
in the Windows PowerShell command window.
Example: "The Get-Acl cmdlet gets objects that represent the security descriptor
of a file or
resource. The security descriptor contains the access control lists (ACLs)
of the resource. The
ACL specifies the permissions that users and user groups have
to access the resource."
The detailed description should describe the cmdlet, but it should not describe
concepts that the
cmdlet uses. Place concept definitions in Additional Notes.
See Also
Windows PowerShell SDK
How to Add Syntax to a Cmdlet Help
Topic
Article • 09/20/2021
Before you start to code the XML for the syntax diagram in the cmdlet Help file, read
this section
to get a clear picture of the kind of data you need to provide, such as the
parameter attributes,
and how that data is displayed in the syntax diagram..
Parameter Attributes
Required
If true, the parameter must appear in all commands that use the parameter set.
If false, the parameter is optional in all commands that use the parameter set.
Position
If named, the parameter name is required.
If positional, the parameter name is optional. When it is omitted, the parameter
value must be
in the specified position in the command. For example, if the
value is position="1", the
parameter value must be the first or only unnamed
parameter value in the command.
Pipeline Input
If true (ByValue), you can pipe input to the parameter. The input is associated
with ("bound
to") the parameter even if the property name and the object type
do not match the expected type.
The PowerShell parameter binding
components try to convert the input to the correct
type and fail the command
only when the type cannot be converted. Only one parameter in a
parameter set
can be associated by value.
If true (ByPropertyName), you can pipe input to the parameter. However, the
input is associated
with the parameter only when the parameter name matches
the name of a property of the input
object. For example, if the parameter name
is Path , objects piped to the cmdlet are associated
with that parameter only
when the object has a property named path.
If true (ByValue, ByPropertyName), you can pipe input to the parameter either
by property name
or by value. Only one parameter in a parameter set can be
associated by value.
If false, you cannot pipe input to this parameter.
Globbing
If true, the text that the user types for the parameter value can include wildcard
characters.
If false, the text that the user types for the parameter value cannot include
wildcard
characters.
The Required attribute of a parameter value is different from the Required attribute of a
parameter.
The required attribute of a parameter indicates whether the parameter (and its value)
must be
included when invoking the cmdlet. In contrast, the required attribute of a
parameter value is used
only when the parameter is included in the command. It
indicates whether that particular value must
be used with the parameter.
Typically, parameter values that are placeholders are required and parameter values that
are literal
are not required, because they are one of several values that might be used
with the parameter.
SYNTAX
Get-Tech
2. List all the parameters of the cmdlet. Type a hyphen ( - ) (ASCII 45) before each
parameter name.
Separate the parameters into parameter sets (some cmdlets may
have only one parameter set). In
this example the Get-Tech cmdlet has two
parameter sets.
SYNTAX
List the default parameter set first. The default parameter is specified by the cmdlet
class.
For each parameter set, list its unique parameter first, unless there are positional
parameters
that must appear first. In the previous example, the Name and ID
parameters are unique parameters
for the two parameter sets (each parameter set
must have one parameter that is unique to that
parameter set). This makes it easier
for users to identify what parameter they need to supply for
the parameter set.
List the parameters in the order that they should appear in the command. If the
order does not
matter, list related parameters together, or list the most frequently
used parameters first.
Be sure to list the WhatIf and Confirm parameters if the cmdlet supports
ShouldProcess.
Do not list the common parameters (such as Verbose, Debug, and ErrorAction) in
your syntax
diagram. The Get-Help cmdlet adds that information for you when it
displays the Help topic.
SYNTAX
Abbreviate types as long as their meaning is clear, such as string for System.String
and int
for System.Int32.
List all values of enumerations, such as the -type parameter in the previous
example, which can
be set to basic or advanced.
Switch parameters, such as -list in the previous example, do not have values.
SYNTAX
SYNTAX
7. If a parameter value can contain multiple values, such as a list of names in the
Name parameter,
add a pair of square brackets directly following the parameter
value.
SYNTAX
8. If the user can choose from parameters or parameter values, such as the Type
parameter, enclose
the choices in curly brackets and separate them with the
exclusive OR symbol(;).
SYNTAX
9. If the parameter value must use specific formatting, such as quotation marks or
parentheses, show
the format in the syntax.
SYNTAX
The following example shows a syntax node that has syntax item nodes for two
parameter sets.
XML
<command:syntax>
<command:syntaxItem>
...
...
</command:syntaxItem>
<command:syntaxItem>
...
...
</command:syntaxItem>
</command:syntax>
XML
<command:syntax>
<command:syntaxItem>
<maml:name>Cmdlet-Name</maml:name>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Cmdlet-Name</maml:name>
</command:syntaxItem>
</command:syntax>
Adding Parameters
Each parameter added to the syntax item node is specified within a pair of
<command:parameter>
tags. You need a pair of <command:parameter> tags for each
parameter included in the parameter
set, with the exception of the common parameters
that are provided by PowerShell.
The attributes of the opening <command:parameter> tag determine how the parameter
appears in the
syntax diagram. For information on parameter attributes, see
Parameter
Attributes.
7 Note
The following example includes a syntax item node for a parameter set with two
parameters.
XML
<command:syntaxItem>
<maml:name>Cmdlet-Name</maml:name>
<maml:name>ParameterName1</maml:name>
<command:parameterValue required="true">
string[]
</command:parameterValue>
</command:parameter>
pipelineInput="true (ByPropertyName)">
<maml:name>ParameterName2</maml:name>
<command:parameterValue required="true">
int32[]
</command:parameterValue>
</command:parameter>
</command:syntaxItem>
This section describes how to add content that is displayed in the PARAMETERS section
of the
cmdlet Help topic. The PARAMETERS section of the Help topic lists each of the
parameters of the
cmdlet and provides a detailed description of each parameter.
The content of the PARAMETERS section should be consistent with the content of the
SYNTAX
section of the Help topic. It is the responsibility of the Help author to make
sure that both the
Syntax and Parameters node contain similar XML elements.
7 Note
For a complete view of a Help file, open one of the dll-Help.xml files located in the
PowerShell
installation directory. For example, the
Microsoft.PowerShell.Commands.Management.dll-Help.xml
file contains content for
To Add Parameters
1. Open the cmdlet Help file and locate the Command node for the cmdlet you are
documenting. If
you are adding a new cmdlet you will need to create a new
Command node. Your Help file will
contain a Command node for each cmdlet that
you are providing Help content for. Here is an
example of a blank Command node.
XML
<command:command>
</command:command>
2. Within the Command node, locate the Description node and add a Parameters
node as
shown below. Only one Parameters node is allowed, and it should
immediately follow the
Syntax node.
XML
<command:command>
<command:details></command:details>
<maml:description></maml:description>
<command:syntax></command:syntax>
<command:parameters>
</command:parameters>
</command:command>
3. Within the Parameters node, add a Parameter node for each parameter of the
cmdlet as shown
below.
XML
<command:parameters>
<command:parameter></command:parameter>
<command:parameter></command:parameter>
<command:parameter></command:parameter>
</command:parameters>
Because these are the same XML tags that are used in the Syntax node, and
because the
parameters specified here must match the parameters specified by the
Syntax node, you can
copy the Parameter nodes from the Syntax node and paste
them into the Parameters
node. However, be sure to copy only one instance of a
Parameter node, even if the parameter
is specified in multiple parameter sets in
the syntax.
4. For each Parameter node, set the attribute values that define the characteristics of
each
parameter. These attributes include the following: required, globbing,
pipelineinput, and
position.
XML
<command:parameters>
pipelineInput="false" position="named">
</command:parameter>
pipelineInput="false" position="named">
</command:parameter>
</command:parameters>
5. For each Parameter node, add the name of the parameter. Here is an example of
the parameter
name added to the Parameter node.
XML
<command:parameters>
pipelineInput="false" position="named">
</command:parameter>
</command:parameters>
6. For each Parameter node, add the description of the parameter. Here is an
example of the
parameter description added to the Parameter node.
XML
<command:parameters>
pipelineInput="false" position="named">
<maml:description>
</maml:description>
</command:parameter>
</command:parameters>
7. For each Parameter node, add the .NET type of the parameter. The parameter type
is displayed
along with the parameter name.
Here is an example of the parameter .NET type added to the Parameter node.
XML
<command:parameters>
pipelineInput="false" position="named">
<maml:description>
</maml:description>
</command:parameter>
</command:parameters>
8. For each Parameter node, add the default value of the parameter. The following
sentence is
added to the parameter description when the content is displayed:
DefaultValue is the
default.
Here is an example of the parameter default value is added to the Parameter node.
XML
<command:parameters>
pipelineInput="false" position="named">
<maml:description>
</maml:description>
</command:parameter>
</command:parameters>
9. For each Parameter that has multiple values, add a possibleValues node.
XML
<dev:possibleValues>
<dev:possibleValue>
<dev:value>Unknown</dev:value>
<maml:description>
<maml:para></maml:para>
</maml:description>
</dev:possibleValue>
<dev:possibleValue>
<dev:value>String</dev:value>
<maml:description>
<maml:para></maml:para>
</maml:description>
</dev:possibleValue>
</dev:possibleValues>
The attributes of the parameter are not displayed in all views of the cmdlet Help
topic. However,
they are displayed in a table following the parameter description
when the user asks for the
Full ( Get-Help <cmdletname> -Full ) or Parameter ( Get-
Help <cmdletname> -Parameter )
view of the topic.
The parameter description is one of the most important parts of a cmdlet Help
topic. The
description should be brief, as well as thorough. Also, remember that if
the parameter description
becomes too long, such as when two parameters
interact with each other, you can add more content
in the NOTES section of the
cmdlet Help topic.
Because the parameter values are expressed as .NET objects, users need more
information about
these values than they would in a traditional command-line
Help. Tell the user what type of data
the parameter is designed to accept, and
include examples.
The default value of the parameter is the value that is used if the parameter is not
specified on
the command line. Note that the default value is optional, and is not
needed for some parameters,
such as required parameters. However, you should specify
a default value for most optional
parameters.
The default value helps the user to understand the effect of not using the parameter.
Describe the
default value very specifically, such as the "Current directory" or the
"PowerShell installation
directory ( $PSHOME )" for an optional path. You can also write a
sentence that describes the
default, such as the following sentence used for the
PassThru parameter: "If PassThru is not
specified, the cmdlet does not pass objects
down the pipeline." Also, because the value is displayed
opposite the field name Default
value, you do not need to include the term "default value" in
the entry.
The default value of the parameter is not displayed in all views of the cmdlet Help topic.
However,
it is displayed in a table (along with the parameter attributes) following the
parameter description
when the user asks for the Full ( Get-Help <cmdletname> -Full ) or
Parameter
( Get-Help <cmdletname> -Parameter ) view of the topic.
XML
<command:parameters>
pipelineInput="false" position="named">
<maml:description>
</maml:description>
<command:parameterValue required="true">
Value
</command:parameterValue>
</command:parameter>
</command:parameters>
If the parameter has multiple values or values of an enumerated type, you can use an
optional
<dev:possibleValues> node. This node allows you to specify a name and
description for multiple
values.
Be aware that the descriptions of the enumerated values do not appear in any of the
default Help
views displayed by the Get-Help cmdlet, but other Help viewers may
display this content in their
views.
The following XML shows a <dev:possibleValues> node with two values specified.
XML
<command:parameters>
pipelineInput="false" position="named">
<maml:description>
</maml:description>
<command:parameterValue required="true">
Value
</command:parameterValue>
<dev:possibleValues>
<dev:possibleValue>
<maml:description>
</maml:description>
<dev:possibleValue>
<dev:possibleValue>
<maml:description>
</maml:description>
<dev:possibleValue>
</dev:possibleValues>
</command:parameter>
</command:parameters>
This section describes how to add an INPUTS section to a PowerShell cmdlet Help topic.
The
INPUTS section lists the .NET classes of objects that the cmdlet accepts as input
from the
pipeline, either by value or by property name.
There is no limit to the number of classes that you can add to an INPUTS section. The
input
types are enclosed in a <command:inputTypes> node, with each class enclosed in a
<command:inputType> element.
Beginning in PowerShell 3.0, the Get-Help cmdlet displays the content of the
<maml:uri> element.
This element lets you direct users to topics that describe the .NET
class.
XML
<command:inputTypes>
<command:inputType>
<dev:type>
<maml:description/>
</dev:type>
<maml:description>
</maml:description>
</command:inputType>
</command:inputTypes>
XML
<command:inputTypes>
<command:inputType>
<dev:type>
<maml:name>System.DateTime</maml:name>
<maml:uri>https://learn.microsoft.com/dotnet/api/system.datetime</maml:uri>
<maml:description/>
</dev:type>
<maml:description>
<maml:description>
</command:inputType>
</command:inputTypes>
This section describes how to add an OUTPUTS section to a PowerShell cmdlet Help
topic. The
OUTPUTS section lists the .NET classes of objects that the cmdlet returns or
passes down the
pipeline.
There is no limit to the number of classes that you can add to the OUTPUTS section. The
return
types of a cmdlet are enclosed in a <command:returnValues> node, with each class
enclosed in a
<command:returnValue> element.
If a cmdlet does not generate any output, use this section to indicate that there is no
output. For
example, in place of the class name, write None and provide a brief
explanation. If the cmdlet
generates output conditionally, use this node to explain the
conditions and describe the conditional
output.
Beginning in PowerShell 3.0, the Get-Help cmdlet displays the content of the
<maml:uri> element.
This element lets you direct users to topics that describe the .NET
class.
XML
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:description/>
</dev:type>
<maml:description>
</maml:description>
</command: returnValue>
</command: returnValues>
XML
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:description/>
</dev:type>
<maml:description>
</maml:description>
</command: returnValue>
</command: returnValues>
This section describes how to add a NOTES section to a PowerShell cmdlet Help topic.
The
NOTES section is used to explain details that do not fit easily into the other
structured
sections, such as a more detailed explanation of a parameter. This content
could include comments on
how the cmdlet works with a specific provider, some
unique, yet important, uses of the cmdlet, or
ways to avoid possible error conditions.
The NOTES section is defined using a single <maml:alertset> node. There are no limits
to the
number of notes that you can add to a Notes section. For each note, add a pair of
<maml:alert>
tags to the <maml:alertset> node. The content of each note is added
XML
<maml:alertSet>
<maml:alert>
<maml:para>Note 1</maml:para>
<maml:para>Note a</maml:para>
</maml:alert>
<maml:alert>
<maml:para>Note 2</maml:para>
</maml:alert>
</maml:alertSet>
Avoid aliases and partial parameter names, even though they work in PowerShell.
In the example description, explain the rational for the construction of the
command. Explain why
you chose particular parameters and values, and how you
use variables.
If the command uses properties and methods of objects, especially properties that
do not appear in
the default display, use the example as an opportunity tell the
user about the object.
XML
<command:examples>
<command:example>
</command:example>
</command:examples>
XML
<command:examples>
<command:example>
</command:example>
</command:examples>
XML
<command:examples>
<command:example>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
</command:example>
</command:examples>
XML
<command:examples>
<command:example>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
</command:example>
</command:examples>
Adding a Description
The following XML shows how to add a description for the example. PowerShell uses a
single set of <maml:para> tags for the description, even though multiple <maml:para>
tags can be
used.
XML
<command:examples>
<command:example>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
<dev:remarks>
</dev:remarks>
</command:example>
</command:examples>
XML
<command:examples>
<command:example>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
<dev:remarks>
<maml:para></maml:para>
<maml:para></maml:para>
</dev:remarks>
</command:example>
</command:examples>
This section describes how to add references to other content that is related to a
PowerShell cmdlet
Help topic. Because these references appear in a command window,
they do not link directly to the
referenced content.
In the cmdlet Help topics that are included in PowerShell, these links reference other
cmdlets,
conceptual content ( about_ ), and other documents and Help files that are not
related to
PowerShell.
The following XML shows how to add a RelatedLinks node that contains two references
to related
topics.
XML
<maml:relatedLinks>
<maml:navigationLink>
<maml:linkText>Topic-name</maml:linkText>
</maml:navigationLink>
<maml:navigationLink>
<maml:linkText>Topic-name</maml:linkText>
</maml:navigationLink>
PowerShell modules can include Help topics about the module and about the module
members, such as
cmdlets, providers, functions and scripts. The Get-Help cmdlet
displays the module Help topics in
the same format as it displays Help for other
PowerShell items, and users use standard Get-Help
commands to get the Help topics.
This document explains the format and correct placement of module Help topics, and it
suggests
guidelines for module Help content.
Cmdlet Help. The Help topics that describe cmdlets in a module are XML files that
use the
command help schema
Provider Help. The Help topics that describe providers in a module are XML files
that use the
provider help schema.
Function Help. The Help topics that describe functions in a module can be XML
files that use
the command help schema or comment-based Help topics within the
function, or the script or script
module
Script Help. The Help topics that describe scripts in a module can be XML files that
use the
command help schema or comment-based Help topics in the script or
script module.
Conceptual ("About") Help. You can use a conceptual ("about") Help topic to
describe the
module and its members and to explain how the members can be
used together to perform tasks.
Conceptual Help topics are text files with Unicode
(UTF-8) encoding. The filename must use the
about_<name>.help.txt format, such
as about_MyModule.help.txt . By default, PowerShell includes
over 100 of these
conceptual About Help topics, and they are formatted like the following example.
Output
TOPIC
SHORT DESCRIPTION
LONG DESCRIPTION
EXAMPLES
Examples of how to use the module or how the subject feature works
in practice.
KEYWORDS
Terms or titles on which you might expect your users to search for
the information in this topic.
SEE ALSO
For example, the following directory structure diagram shows the location of the Help
topics for the
SampleModule module.
<ModulePath>
\SampleModule
\<en-US>
\about_SampleModule.help.txt
\SampleModule.dll-help.xml
\SampleNestedModule.dll-help.xml
\<fr-FR>
\about_SampleModule.help.txt
\SampleModule.dll-help.xml
\SampleNestedModule.dll-help.xml
7 Note
In the example, the <ModulePath> placeholder represents one of the paths in the
PSModulePath
environment variable, such as $HOME\Documents\Modules ,
You can provide module Help topics in different languages. The Get-Help cmdlet
automatically
displays module Help topics in the language that is specified for the
current user in the Regional
and Language Options item in Control Panel. In Windows
Vista and later versions of Windows,
Get-Help searches for the Help topics in language-
specific subdirectories of the module directory
in accordance with the language fallback
standards established for Windows.
If the module does not contain help topics and there are no help topics for the
commands in the
module on the user's computer, Get-Help displays auto-generated
help. The auto-generated help
includes the command syntax, parameters, and input and
output types, but does not include any
descriptions. The auto-generated help includes
text that directs the user to try to use the
Update-Help cmdlet to download help for the
command from the internet or a file share. It also
recommends using the Online
parameter of the Get-Help cmdlet to get the online version of the
help topic.
Users behind firewalls and those without internet access can use Updatable Help, as
well.
Administrators with internet access use the Save-Help cmdlet to download and
install the newest
help files to a file share. Then, users use the Path parameter of the
Update-Help cmdlet to
get the newest help files from the file share.
Module authors can include help files in the module and use Updatable Help to update
the help files,
or omit help files from the module and use Updatable Help both to install
and to update them.
For more information about Updatable Help, see Supporting Updatable Help.
The Get-Help cmdlet uses the value of the HelpUri property of the cmdlet or function to
find
the online version of the help topic.
Beginning in PowerShell 3.0, you can help users find the online version of cmdlet and
function help
topics by defining the HelpUri attribute on the cmdlet class or the HelpUri
property of the
CmdletBinding attribute. The value of the attribute is the value of the
HelpUri property of
the cmdlet or function.
See Also
Writing a PowerShell Module
This topic explains how to name an XML-based help file so that the
Get-Help cmdlet can
find it. The name
requirements differ for each command type.
<AssemblyName>.dll-help.xml
The assembly name format is required even when the assembly is a nested module.
<AssemblyName>.dll-help.xml
The assembly name format is required even when the assembly is a nested module.
Otherwise,
the Get-Help cmdlet cannot find the help file.
There are no technical requirements for the name of a function help file. However, a
best practice
is to name the help file for the script module in which the function is
defined. For example, the
following function is defined in the MyModule.psm1 file.
C#
#.ExternalHelp MyModule.psm1-help.xml
<FileName>.cdxml-help.xml
CIM commands are defined in CDXML files that can be included in modules as nested
modules. When the
CIM command is imported into the session as a function, PowerShell
adds an .ExternalHelp
comment keyword to the function definition that associates the
function with an XML help file that
is named for the CDXML file in which the CIM
command is defined.
<ScriptModule>.psm1-help.xml
Because the .ExternalHelp comment keyword is ignored, the Get-Help cmdlet can find
help for
script workflows only when they are included in modules.
Supporting Updatable Help
Article • 09/17/2021
The Windows PowerShell Updatable Help System, introduced in Windows 8 and Windows
Server 2012,
is designed to ensure that users always have the newest help topics at the
command prompt on their
local computer. Along with Windows PowerShell online help,
Updatable Help provides a complete help
solution for users. This section describes the
Updatable Help System and explains how module authors
can support Updatable Help
for their modules.
See Also
Supporting Online Help
This document provides a basic introduction to the design and operation of the
PowerShell Updatable
Help feature. It is designed for module authors and others who
deliver Windows PowerShell help
topics to users.
Introduction
PowerShell help topics are an integral part of the PowerShell experience. Like PowerShell
modules,
help topics are continually updated and improved by the authors and by the
contributions of the
community of PowerShell users.
The Updatable Help feature, introduced in Windows PowerShell 3.0, ensures that users
have the
newest versions of help topics at the command prompt, even for built-in
PowerShell commands, without
downloading new modules or running Windows Update.
Updatable Help makes updating simple by providing
cmdlets that download the newest
versions of help topics from the internet and install them in the
correct subdirectories
on the user's local computer. Even users who are behind firewalls can use the
new
cmdlets to get updated help from an internal file share.
Enhanced Online help. Easy access to online help no longer requires help files. The
Online
parameter of the Get-Help cmdlet now gets the URL of an online help topic
from the value of the
HelpUri property of any command, if it cannot find the
online help URL in a help file. You can
populate the HelpUri property by adding a
HelpUri attribute to the code of cmdlets,
functions, and CIM commands, or by
using the .Link comment-based help directive in workflows
and scripts.
To make our help files updatable, the Windows PowerShell modules in Windows 8
and Windows Server
vNext do not come with help files. Users can use Updatable
Help to install help files and update
them. Authors of other modules can include
help files in modules or omit them. Support for
Updatable Help is optional, but
recommended.
Updatable Help Authoring: Step-by-
Step
Article • 11/29/2022
The following steps provide an overview of the process of supporting Updatable Help.
For example:
PowerShell
@{
RootModule = TestModule.psm1
ModuleVersion = '2.0'
HelpInfoURI = 'https://go.microsoft.com/fwlink/?LinkID=0123'
7 Note
Use a tool, such as MakeCab.exe , to create a CAB file that contains the help files for your
module. Create a separate CAB file for the help files in each supported UI culture. For
more
information, see How to Prepare Updatable Help CAB Files.
This topic explains how Updatable Help processes the HelpInfo XML file and CAB files
for each
module, and installs updated help for users.
1. Update-Help gets the remote HelpInfo XML file from the location specified by the
value of the
HelpInfoURI key in the module manifest and validates the file against
the schema. (To view
the schema, see HelpInfo XML Schema.) Then Update-Help
looks for a
local HelpInfo XML file for the module in the module directory on the
user's computer.
2. Update-Help compares the version number of the help files for the specified UI
culture in the
remote and local HelpInfo XML files for the module. If the version
number on the remote file is
greater than version number on the local file, or if the
there is no local HelpInfo XML file for
the module, Update-Help prepares to
download new help files.
3. Update-Help selects the CAB file for the module from the location specified by the
HelpContentUri element in the remote HelpInfo XML file. It uses the module
name, module GUID,
and UI culture to identify the CAB file.
4. Update-Help downloads the CAB file, unpacks it, validates the help content files,
and saves the
help content files in the language-specific subdirectory of the
module directory on the user's
computer.
5. Update-Help creates a local HelpInfo XML file by copying the remote HelpInfo XML
file. It edits
the local HelpInfo XML file so that it includes elements only for the CAB
file that it installed.
Then it saves the local HelpInfo XML file in the module
directory and concludes the update.
The Save-Help cmdlet performs the following actions in response to a command to save
the help
files for a module in a file share that is specified by the DestinationPath
parameter.
1. Save-Help gets the remote HelpInfo XML file from the location specified by the
value of the
HelpInfoURI key in the module manifest and validates the file against
the schema. (To view
the schema, see HelpInfo XML Schema.) Then Save-Help
looks for a
local HelpInfo XML file in the directory that is specified by the
DestinationPath parameter
in the Save-Help command.
2. Save-Help compares the version number of the help files for the specified UI
culture in the
remote and local HelpInfo XML files for the module. If the version
number on the remote file is
greater than version number on the local file, or if the
there is no local HelpInfo XML file for
the module in the DestinationPath directory,
Save-Help prepares to download new help files.
3. Save-Help selects the CAB file for the module from the location specified by the
HelpContentUri element in the remote HelpInfo XML file. It uses the module
name, module GUID,
and UI culture to identify the CAB file.
4. Save-Help downloads the CAB file and saves it in the DestinationPath directory. (It
does
not create any language-specific subdirectories.)
5. Save-Help creates a local HelpInfo XML file by copying the remote HelpInfo XML
file. It edits
the local HelpInfo XML file so that it includes elements only for the CAB
file that it saved.
Then it saves the local HelpInfo XML file in the DestinationPath
directory and concludes the
update.
6. Update-Help gets the remote HelpInfo XML file from the SourcePath directory.
Then it looks
for a local HelpInfo XML file in the module directory on the user's
computer.
7. Update-Help compares the version number of the help files for the specified UI
culture in the
remote and local HelpInfo XML files for the module. If the version
number on the remote file is
greater than version number on the local file, or if the
there is no local HelpInfo XML file,
Update-Help prepares to install new help files.
8. Update-Help selects the CAB file for the module from SourcePath directory. It uses
the
module name, module GUID, and UI culture to identify the CAB file.
9. Update-Help unpacks the CAB file, validates the help content files, and saves the
help content
files in the language-specific subdirectory of the module directory on
the user's computer.
10. Update-Help creates a local HelpInfo XML file by copying the remote HelpInfo XML
file. It edits
the local HelpInfo XML file so that it includes elements only for the CAB
file that it installed.
Then it saves the local HelpInfo XML file in the module
directory and concludes the update.
How to Create a HelpInfo XML File
Article • 09/17/2021
This topics in this section explains how to create and populate a help information file,
commonly
known as a "HelpInfo XML file," for the PowerShell Updatable Help feature.
Each module has just one HelpInfo XML file, even if the module includes multiple help
files for
multiple UI cultures. The module author creates the HelpInfo XML file and
places it in the internet
location that is specified by the HelpInfoUri key in the module
manifest. When the module help
files are updated and uploaded, the module author
updates the HelpInfo XML file and replaces the
original HelpInfo XML file with the new
version.
It is critical that the HelpInfo XML file is carefully maintained. If you upload new files, but
forget to increment the version numbers, Updatable Help will not download the new
files to users'
computers. if you add help files for a new UI culture, but don't update the
HelpInfo XML file or
place it in the correct location, Updatable Help will not download
the new files.
In this section
This section includes the following topics.
See Also
Supporting Updatable Help
HelpInfo XML Schema
Article • 07/18/2022
This topic contains the XML schema for Updatable Help Information files, commonly
known as "HelpInfo
XML files."
XML
<schema elementFormDefault="qualified"
targetNamespace="http://schemas.microsoft.com/powershell/help/2010/05"
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="HelpInfo">
<complexType>
<sequence>
<complexType>
<sequence>
<complexType>
<sequence>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
UICulture - Represents a set of help files for the module in a specified UI culture.
Add a
UICulture element for each UI culture in which the help files are written.
UICultureName - Contains the language code for the UI culture in which the help
files are
written.
<HelpInfo xmlns="http://schemas.microsoft.com/powershell/help/2010/05">
<HelpContentURI>https://go.microsoft.com/fwlink/?
LinkID=141553</HelpContentURI>
<SupportedUICultures>
<UICulture>
<UICultureName>de-DE</UICultureName>
<UICultureVersion>2.15.0.10</UICultureVersion>
</UICulture>
<UICulture>
<UICultureName>en-US</UICultureName>
<UICultureVersion>3.2.0.7</UICultureVersion>
</UICulture>
<UICulture>
<UICultureName>it-IT</UICultureName>
<UICultureVersion>1.1.0.5</UICultureVersion>
</UICulture>
<UICulture>
<UICultureName>ja-JP</UICultureName>
<UICultureVersion>3.2.0.4</UICultureVersion>
</UICulture>
</SupportedUICultures>
</HelpInfo>
This topic explains the required name format for the Updatable Help Information files,
commonly
known as HelpInfo XML files.
<ModuleName>_<ModuleGUID>_HelpInfo.xml
<ModuleName> - The value of the Name property of the ModuleInfo object that the
For example, if the module name is "TestModule" and the module GUID is
9cabb9ad-
f2ac-4914-a46b-bfc1bebf07f9, the name of the HelpInfo XML file for the module would
be:
TestModule_9cabb9ad-f2ac-4914-a46b-bfc1bebf07f9_HelpInfo.xml
How to Set HelpInfo XML Version
Numbers
Article • 09/17/2021
This topic explains how to set and increase the version numbers in an Updatable Help
Information
file, commonly known as a "HelpInfo XML file."
The HelpInfo XML file uses the 4-part version number that is defined in the
System.Version class
of the Microsoft .NET Framework. The format is N1.N2.N3.N4 .
Module authors can use any version
numbering scheme that is permitted by the
System.Version class. Updatable Help requires only
that the version number for a UI
culture increase when a new version of the CAB file for that UI
culture is uploaded to the
location that is specified by the HelpContentURI element in the
HelpInfo XML file.
The following example shows the elements of the HelpInfo XML file for the German (de-
DE) UI culture
when the version is 2.15.0.10.
XML
<UICulture>
<UICultureName>de-DE</UICultureName>
<UICultureVersion>2.15.0.10</UICultureVersion>
</UICulture>
The version number for a UI culture reflects the version of the CAB file for that UI
culture. The
version number applies to the entire CAB file. You cannot set different
version numbers for
different files in the CAB file. The version number for each UI
culture is evaluated independently
and need not be related to the version numbers for
other UI cultures that the module supports.
How to Prepare Updatable Help CAB
Files
Article • 09/17/2021
This topic explains the contents and use of cabinet (1) files in Windows PowerShell
Updatable
Help.
See Also
Supporting Updatable Help
How to Create and Upload CAB Files
Article • 10/27/2022
This topic explains how to create Updatable Help CAB files and upload them to the
location where the
Updatable Help cmdlets can find them.
1. Organize the help files for the module by UI culture. Each Updatable Help CAB file
contains the
help files for one module in one UI culture. You can deliver multiple
help CAB files for the
module, each for a different UI culture.
2. Verify that help files include only the file types permitted for Updatable Help and
validate them
against a help file schema. If the Update-Help cmdlet encounters a
file that's invalid or is
not a permitted type, it doesn't install the invalid file and
stops installing files from the
CAB. For a list of permitted file types, see
File Types
Permitted in an Updatable Help CAB File.
3. Include all the help files for the module in the UI culture, not only files that are new
or have
changed. If the CAB file is incomplete, users who download help files for
the first time or do
not download every update, won't have all the help files.
4. Use a utility that creates cabinet files, such as MakeCab.exe . PowerShell doesn't
include
cmdlets that create CAB files.
6. Upload the CAB files for the module to the location that's specified by the
HelpContentUri
element in the HelpInfo XML file for the module. Then upload the
HelpInfo XML file to the
location that's specified by the HelpInfoUri key of the
module manifest. The
HelpContentUri and HelpInfoUri can point to the same
location.
U Caution
The value of the HelpInfoUri key and the HelpContentUri element must begin with
http or
https . The value must a URL path pointing to the location (folder)
containing the updateable
help. The URL must end with / . The URL must not
include a filename.
How to Name an Updatable Help CAB
File
Article • 09/17/2021
This topic explains the required name format for the Updatable Help cabinet ( .CAB ) files.
<ModuleName>_<ModuleGUID>_<UICulture>_HelpContent.cab
<ModuleName> -The value of the Name property of the ModuleInfo object that the
Get-Module cmdlet returns.
<ModuleGUID> - The value of the GUID key in the module manifest.
<UICulture> - The UI culture of the help files in the CAB file. This value must match
the value
of one of the UICulture elements in the HelpInfo XML file for the module.
TestModule_9cabb9ad-f2ac-4914-a46b-bfc1bebf07f9_en-US_HelpContent.cab
File Types Permitted in an Updatable
Help CAB File
Article • 09/17/2021
Uncompressed CAB file content is limited to 1 GB by default. To bypass this limit, users
have to use
the Force parameter of the
Update-Help and
Save-Help cmdlets.
To assure the security of help files that are downloaded from the internet, an Updatable
Help CAB
file can include only the file types listed below. The
Update-Help cmdlet
validates all files
against the help topic schemas. If the Update-Help cmdlet encounters a
file that is invalid or is
not a permitted type, it does not install the invalid file and stops
installing files from the CAB
on the user's computer.
This topic explains how to update help files for a module that supports Updatable Help.
When all verbose messages are resolved, run an Update-Help command with the Debug
parameter.
This parameter should detect any remaining problems with the Updatable
Help files.
Supporting Online Help
Article • 09/17/2021
Beginning in PowerShell 3.0, there are two ways to support the Get-Help Online feature
for
PowerShell commands. This topic explains how to implement this feature for
different command types.
With the advent of Updatable Help in PowerShell 3.0, online help still plays a vital role.
In
addition to the flexible user experience, online help provides help to users who do
not or cannot
use Updatable Help to download help topics.
For example, the following command opens the online help topic for the Invoke-
Command cmdlet.
PowerShell
To implement Get-Help -Online , the Get-Help cmdlet looks for a Uniform Resource
Identifier (URI)
for the online version help topic in the following locations.
The first link in the Related Links section of the help topic for the command. The
help topic
must be installed on the user's computer. This feature was introduced in
PowerShell 2.0.
The HelpUri property of any command. The HelpUri property is accessible even
when the help
topic for the command is not installed on the user's computer. This
feature was introduced in
PowerShell 3.0.
Get-Help looks for a URI in the first entry in the Related Links section before
getting the
HelpUri property value. If the property value is incorrect or has
changed, you can override it
by entering a different value in the first related link.
However, the first related link works
only when the help topics are installed on the
user's computer.
To support this feature, the URI must appear in the maml:uri element under the first
maml:relatedLinks/maml:navigationLink element in the maml:relatedLinks element.
The following XML shows the correct placement of the URI. The Online version: text in
the
maml:linkText element is a best practice, but it is not required.
XML
<maml:relatedLinks>
<maml:navigationLink>
<maml:linkText>Online version:</maml:linkText>
<maml:uri>https://go.microsoft.com/fwlink/?LinkID=113279</maml:uri>
</maml:navigationLink>
<maml:navigationLink>
<maml:linkText>about_History</maml:linkText>
<maml:uri/>
</maml:navigationLink>
</maml:relatedLinks>
The following code shows the HelpUri attribute of the Get-History cmdlet class.
C#
The following code shows the HelpUri attribute of the New-Calendar function
PowerShell
function New-Calendar {
[CmdletBinding(SupportsShouldProcess=$true,
HelpURI="https://go.microsoft.com/fwlink/?LinkID=01122")]
The following code shows the HelpUri attribute of the Start-Debug CIM command
XML
PowerShell
# .ExternalHelp "https://go.microsoft.com/fwlink/?LinkID=138338"
This section explains how to populate the DYNAMIC PARAMETERS section of a provider
help topic.
Dynamic parameters are parameters of a cmdlet or function that are available only
under specified
conditions.
The dynamic parameters that are documented in a provider help topic are the dynamic
parameters that
the provider adds to the cmdlet or function when the cmdlet or
function is used in the provider
drive.
Dynamic parameters can also be documented in custom cmdlet help for a provider.
When writing both
provider help and custom cmdlet help for a provider, include the
dynamic parameter documentation in
both documents.
If a provider does not implement any dynamic parameters, the provider help topic
contains an empty
DynamicParameters element.
the Tasks
element and before the RelatedLinks element.
For example:
XML
<providerHelp>
<Tasks>
</Tasks>
<DynamicParameters>
</DynamicParameters>
<RelatedLinks>
</RelatedLinks>
</providerHelp>
For example:
XML
<DynamicParameters/>
<DynamicParameter>
</DynamicParameter>
</DynamicParameters>
For example, the following XML documents the Encoding dynamic parameter that
the Windows
PowerShell FileSystem provider adds to the Add-Content , Get-
Content , Set-Content cmdlets.
XML
<DynamicParameters/>
<DynamicParameter>
</DynamicParameters>
For example, the following XML shows that the .NET type of the Encoding dynamic
parameter is
the FileSystemCmdletProviderEncoding
enumeration.
XML
<DynamicParameters/>
<DynamicParameter>
<Type>
<Name>
Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding </Name>
<Type>
...
</DynamicParameters>
5. Add the Description element, which contains a brief description of the dynamic
parameter. When
composing the description, use the guidelines prescribed for all
cmdlet parameters in
How to Add Parameter Information.
For example, the following XML includes the description of the Encoding dynamic
parameter.
XML
<DynamicParameters/>
<DynamicParameter>
<Type>
<Name>
Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding </Name>
<Type>
...
</DynamicParameters>
6. Add the PossibleValues element and its child elements. Together, these elements
describe the
values of the dynamic parameter. This element is designed for
enumerated values. If the dynamic
parameter does not take a value, such as is the
case with a switch parameter, or the values
cannot be enumerated, add an empty
PossibleValues element.
The following table lists and describes the PossibleValues element and its child
elements.
For example, the following XML shows one PossibleValue element of the
Encoding dynamic
parameter.
XML
<DynamicParameters/>
<DynamicParameter>
...
<PossibleValues>
<PossibleValue>
<Description>
</Description>
</PossibleValue>
...
</PossibleValues>
</DynamicParameters>
Example
The following example shows the DynamicParameters element of the Encoding dynamic
parameter.
XML
<DynamicParameters/>
<DynamicParameter>
<Type>
<Name>
Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding </Name>
<Type>
<PossibleValues>
<PossibleValue>
<Description>
</Description>
</PossibleValue>
<PossibleValue>
<Description>
</Description>
</PossibleValue>
</PossibleValues>
</DynamicParameters>
This section explains how to populate the SEE ALSO section of a provider help topic.
The SEE ALSO section consists of a list of topics that are related to the provider or might
help
the user better understand and use the provider. The topic list can include cmdlet
help, provider
help and conceptual ("about") help topics in Windows PowerShell. It can
also include references to
books, paper, and online topics, including an online version of
the current provider help topic.
When you refer to online topics, provide the URI or a search term in plain text. The Get-
Help
cmdlet does not link or redirect to any of the topics in the list. Also, the Online
parameter of
the Get-Help cmdlet does not work with provider help.
The See Also section is created from the RelatedLinks element and the tags that it
contains.
The following XML shows how to add the tags.
For example:
XML
<providerHelp>
<RelatedLinks>
</RelatedLinks>
</providerHelp>
2. For each topic in the SEE ALSO section, within the RelatedLinks element, add a
navigationLink element. Then, within each navigationLink element, add one
linkText element
and one uri element. If you are not using the uri element, you
For example:
XML
<providerHelp>
<RelatedLinks>
<navigationLink>
<linkText> </linkText>
<uri> </uri>
</navigationLink>
</RelatedLinks>
</providerHelp>
3. Type the topic name between the linkText tags. If you are providing a URI, type it
between the
uri tags. To indicate the online version of the current provider help
topic, between the
linkText tags, type "Online version:" instead of the topic name.
Typically, the "Online
version:" link is the first topic in the SEE ALSO topic list.
The following example include three SEE ALSO topics. The first refer to the online
version of the
current topic. The second refers to a Windows PowerShell cmdlet
help topic. The third refers to
another online topic.
XML
<providerHelp>
<RelatedLinks>
<navigationLink>
<uri>http://www.fabrikam.com/help/myFunction.htm</uri>
</navigationLink>
<navigationLink>
<uri/>
</navigationLink>
<navigationLink>
<uri>https://go.microsoft.com/fwlink/?LinkID=89597<uri/>
</navigationLink>
</RelatedLinks>
</providerHelp>
PowerShell uses its PSObject object to extend the types of objects in two ways. First,
the
PSObject object provides a way to show different views of specific object types. This is
referred to as showing an adapted view of an object. Second, the PSObject object
provides a way
to add members to existing object. Together, by wrapping an existing
object, referred to as the base
object, the PSObject object provides an extended type
system (ETS) that script and cmdlet
developers can use to manipulate .NET objects
within the shell.
First, some .NET Objects do not have the necessary default behavior for acting as the
data between
cmdlets.
Some .NET objects are "meta" objects (for example: WMI Objects, ADO objects,
and XML objects)
whose members describe the data they contain. However, in a
scripting environment it is the
contained data that is most interesting, not the
description of the contained data. ETS resolves
this issue by introducing the notion
of Adapters that adapt the underlying .NET object to have the
expected default
semantics.
Some .NET Object members are inconsistently named, provide an insufficient set of
public members,
or provide insufficient capability. ETS resolves this issue by
introducing the ability to extend
the .NET object with additional members.
Second, the PowerShell scripting language is typeless in that a variable does not need to
be
declared of a particular type. That is, the variables a script developer creates are by
nature
typeless. However, the PowerShell system is "type-driven" in that it depends on
having a type name
to operate against for basic operations such as outputting results or
sorting.
Therefore a script developer must have the ability to state the type of one of their
variables and
build up their own set of dynamically typed "objects" that contain
properties and methods and can
participate in the type-driven system. ETS solves this
problem by providing a common object for the
scripting language that has the ability to
state its type dynamically and to add members
dynamically.
Fundamentally, ETS resolves the issue mentioned previously by providing the PSObject
object,
which acts as the basis of all object access from the scripting language and
provides a standard
abstraction for the cmdlet developer.
Cmdlet Developers
For the cmdlet developers, ETS provides the following support:
The abstractions to work against objects in a generic way using the PSObject
object. ETS also
provides the ability to drill past these abstractions if required.
The mechanisms to create a default behavior for formatting, sorting, serialization,
and other
system manipulations of their object type using a well-known set of
extended members.
The means to operate against any object using the same semantics as the script
language using a
LanguagePrimitives object.
The means to dynamically "type" a hash table so that the rest of the system can
operate against it
effectively.
Script Developers
For the script developers, ETS provides the following support:
The ability to reference any underlying object type using the same syntax ( $a.x ).
The ability to access beyond the abstraction provided by the PSObject object (such
as
accessing only adapted members, or accessing the base object itself).
The ability to define well-known members that control the formatting, sorting,
serialization, and
other manipulations of an object instance or type.
The means to name an object as a specific type and thus control the inheritance of
its type-based
members.
The ability to add, remove, and modify extended members.
The ability to manipulate the PSObject object itself if required.
Calling the PSObject .#ctor constructor creates a new PSObject object with a base-
object
of PSCustomObject. A base-object of this type indicates that the PSObject
object has no
meaningful base-object. However, a PSObject object with this type
of base-object does provide
a property bag that cmdlet developers can find
helpful by adding extended-members.
Developers can also specify the object type-name, which allows this object to share its
extended-members with other PSObject objects of the same type-name.
In this case, the type-name for the created object is a collection of the derivation
hierarchy of
the base-object. For example, the type-name for the PSObject that
contains a ProcessInfo
base-object would include the following names:
System.Diagnostics.Process
System.ComponentModel.Component
System.MarshalByRefObject
System.Object
If the supplied object is of type System.Object, the supplied object is used as the
base-object
for the new PSObject object. If the supplied object is already an
PSObject object, the
supplied object is returned as is.
Base-object members
If the base-object is specified when constructing the PSObject objects, then the
members of the
base-object are made available through the Members property.
Adapted members
When a base-object is a meta-object, one that contains data in a generic fashion whose
properties
"describe" their contained data, ETS adapts those objects to a view that
allows for direct access to
the data through adapted members of the PSObject object.
Adapted members and base-object members
are accessed through the Members
property.
Extended members
In addition to the members made available from the base-object or those adapted
members created by
PowerShell, an PSObject may also define extended members that
extend the original base-object
with additional information that is useful in the scripting
environment.
For example, all the core cmdlets provided by PowerShell, such as the Get-Content and
Set-Content
cmdlets, take a path parameter. To ensure that these cmdlets, and others,
can work against objects
of different types, a Path member can be added to those
objects so that they all state their
information in a common way. This extended Path
member ensures that the cmdlets can work against all
those types even though there
base class might not have a Path member.
Extended members, adapted members, and base-object members are all accessed
through the
Members property.
Extended Type System class members
Article • 09/17/2021
ETS refers to a number of different kinds of members whose types are defined by the
PSMemberTypes enumeration. These member types include properties, methods,
members, and member
sets that are each defined by their own CLR type. For example, a
NoteProperty is defined by its
own PSNoteProperty type. These individual CLR types
have both their own unique properties and
common properties that are inherited from
the
PSMemberInfo class.
Name property: The name of the member. This name can be defined by the base-
object or defined
by PowerShell when adapted members or extended members are
exposed.
Value property: The value returned from the particular member. Each member type
defines how it
handles its member value.
TypeNameOfValue property: This is the name of the CLR type of the value that is
returned by
the Value property.
Accessing members
Collections of members can be accessed through the Members, Methods, and
Properties
properties of the PSObject object.
ETS properties
ETS properties are members that can be treated as a property. Essentially, they can
appear on the
left-hand side of an expression. They include alias properties, code
properties, PowerShell
properties, note properties, and script properties. For more
information about these types of
properties, see ETS properties.
ETS methods
ETS methods are members that can take arguments, may return results, and cannot
appear on the
left-hand side of an expression. They include code methods, PowerShell
methods, and script methods.
For more information about these types of methods, see
ETS methods.
ETS member sets
Article • 09/17/2021
Member sets allow you to partition the members of the PSObject object into two
subsets so that
the members of the subsets can be referenced together by their subset
name. The two types of subsets
include property sets and member sets. For example of
how PowerShell uses member sets, there is a
specific property set named
DefaultDisplayPropertySet that is used to determine, at runtime,
which properties to
display for a given PSObject object.
Property Sets
Property sets can include any number of properties of an PSObject type. In general, a
property
set can be used whenever a collection of properties (of the same type) is
needed. The property set
is created by calling the
PSPropertySet(System.String,System.Collections.Generic.IEnumerable{System.String})
constructor
with the name of the property set and the names of the referenced
properties. The created
PSPropertySet object can then be used as an alias that points to
the properties in the set. The
PSPropertySet class has the following
properties and
methods.
IsInstance property: Gets a Boolean value that indicates the source of the
property.
MemberType property: Gets the type of properties in the property set.
Name property: Gets the name of the property set.
ReferencedPropertyNames property: Gets the names of the properties in the
property set.
TypeNameOfValue property: Gets a PropertySet enumeration constant that
defines this set as
a property set.
Value property: Gets or sets the PSPropertySet object.
PSPropertySet.Copy method: Makes an exact copy of the PSPropertySet object.
PSMemberSet.ToString method: Converts the PSPropertySet object to a string.
Member Sets
Member sets can include any number of extended members of any type. The member
set is created by
calling the
PSMemberSet(System.String,System.Collections.Generic.IEnumerable{System.Management.
Automation.PSMemberInfo})
constructor with the name of the member set and the names
of the referenced members. The created
PSPropertySet object can then be used as an
alias that points to the members in the set. The
PSMemberSet class has the following
properties and methods.
IsInstance property: Gets a Boolean value that indicates the source of the member.
Members property: Gets all the members of the member set.
MemberType property: Gets a MemberSet enumeration constant that defines this
set as a
member set.
Methods property: Gets the methods included in the member set.
Properties property: Gets the properties included in the member set.
TypeNameOfValue property: Gets a MemberSet enumeration constant that
defines this set as a
member set.
Value property: Gets the PSMemberSet object.
PSMemberSet.Copy method: Makes an exact copy of the PSMemberSet object.
Properties are members that can be treated as a property. Essentially, they can appear
on the
left-hand side of an expression. The properties that are available include alias,
code, note, and
script properties.
Alias Property
An alias property is a property that references another property that the PSObject
object
contains. It is used primarily to rename the referenced property. However, it may
also be used to
convert the referenced property's value to another type. With respect to
ETS, this type of property
is always an extended-member and is defined by the
PSAliasProperty class. The class includes the following properties.
ConversionType property: The CLR type used to convert the referenced member's
value.
IsGettable property: Indicates whether the value of the referenced property can be
retrieved.
This property is dynamically determined by examining the IsGettable
property of the referenced
property.
IsSettable property: Indicates whether the value of the referenced property can be
set. This
property is dynamically determined by examining the IsSettable property
of the referenced
property.
MemberType property: An AliasProperty enumeration constant that defines this
property as
an alias property.
ReferencedMemberName property: The name of the referenced property that this
alias refers to.
TypeNameOfValue property: The full name of the CLR type of the referenced
property's value.
Value property: The value of the referenced property.
Code Property
A code property is a property that is a getter and setter that is defined in a CLR
language. In
order for a code property to become available, a developer must write the
property in some CLR
language, compile, and ship the resultant assembly. This assembly
must be available in the runspace
where the code property is desired. With respect to
ETS, this type of property is always an
extended-member and is defined by the
PSCodeProperty class. The class includes
the following properties.
GetterCodeReference property: The method used to get the value of the code
property.
IsGettable property: Indicates whether the value of the code property can be
retrieved, that
the SetterCodeReference property: The method used to set the
value of the code property.
IsSettable property: Indicates whether the value of the code property can be set,
that the
SetterCodeReference property is not null.
MemberType property: A CodeProperty enumeration constant that defines this
property as a
code property.
SetterCodeReference property: The method used to get the value of the code
property.
TypeNameOfValue property: The CLR type of the code property value that is
returned by the
properties get operation.
Value property: The value of the code property. When this property is retrieved,
the getter
code in the GetterCodeReference property is invoked, passing the
current PSObject object and
returning the value returned by the invocation. When
this property is set, the setter code in the
SetterCodeReference property is
invoked, passing the current PSObject object as the first
argument and the object
used to set the value as the second argument.
Note Property
A Note property is a property that has a name/value pairing. With respect to ETS, this
type of
property is always an extended-member and is defined by the
PSNoteProperty
class. The class includes
the following properties.
IsGettable property: Indicates whether the value of the note property can be
retrieved.
IsSettable property: Indicates whether the value of the note property can be set.
MemberType property: A NoteProperty enumeration constant that defines this
property as a
note property.
TypeNameOfValue property: The fully-qualified type name of the object returned
by the note
property's get operation.
Value: The value of the note property.
PowerShell property
A PowerShell property is a property defined on the base object or a property that is
made available
through an adapter. It can refer to both CLR fields as well as CLR
properties. With respect to ETS,
this type of property can be either a base-member or an
adapter-member and is defined by the
PSProperty class. The class includes the
following
properties.
IsGettable property: Indicates whether the value of the base or adapted property
can be
retrieved.
IsSettable property: Indicates whether the value of the base or adapted property
can be set.
MemberType property: A Property enumeration constant that defines this property
as a
PowerShell property.
TypeNameOfValue property: The fully-qualified name of the property value type.
For example,
for a property whose value is a string, its property value type is
System.String.
Value property: The value of the property. If the get or set operation is called on a
property
that does not support that operation, an GetValueException or
SetValueException exception
is thrown
GetterScript property: The script used to retrieve the script property value.
IsGettable property: Indicates whether the GetterScript property exposes a script
block.
IsSettable property: Indicates whether the SetterScript property exposes a script
block.
MemberType property: An ScriptProperty enumeration constant that identifies this
property as a
script property.
SetterScript property: The script used to set the script property value.
TypeNameOfValue property: The fully-qualified type name of the object returned
by the getter
script. In this case System.Object is always returned.
Value property: The value of the script property. A get invokes the getter script and
returns
the value provided. A set invokes the setter script.
ETS class methods
Article • 09/17/2021
ETS methods are members that can take arguments, may return results, and cannot
appear on the
left-hand side of an expression. The methods that are available within ETS
include code, Windows
PowerShell, and script methods.
7 Note
From scripts, methods are accessed using the same syntax as other members with
the addition of
parenthesis at the end of the method name.
Code Methods
A code method is an extended member that is defined in a CLR language. It provides
similar
functionality to a method defined on a base object; however, a code method
may be added dynamically
to an PSObject object. In order for a code method to
become available, a developer must write
the property in some CLR language, compile,
and ship the resultant assembly. This assembly must be
available in the runspace where
the code method is desired. Be aware that a code method
implementation must be
thread safe. Access to these methods is done through
PSCodeMethod objects that
provides the
following public methods and properties.
method.
PSCodeMethod.ToString method: Converts the PSCodeMethod object to a string.
Script Methods
A script method is an extended member that is defined in the PowerShell language. It
provides
similar functionality to a method defined on a base object; however, a script
method may be added
dynamically to an PSObject object. Access to these methods is
done through
PSScriptMethod objects that provides the
following public methods and
properties.
method.
PSScriptMethod.ToString method: Converts the PSScriptMethod object to a string.
PSMemberInfo.IsInstance property: Gets a Boolean value that indicates the source
of the
member.
PSScriptMethod.MemberType property: Gets a PSMemberTypes.ScriptMethod
enumeration constant
that identifies this method as a script method.
PSMemberInfo.Name property: Gets the name of the underlying code method.
PSScriptMethod.OverloadDefinitions property: Gets the definitions of all the
overloads of the
underlying script method.
PSScriptMethod.TypeNameOfValue property: Gets the ETS type of this method.
PSScriptMethod.Script property: Gets the script used to invoke the method.
PSMemberInfo.Value property: Gets the PSScriptMethod object.
ETS type converters
Article • 09/17/2021
ETS uses two basic types of type converters when a call is made to the
LanguagePrimitives.ConvertTo(System.Object, System.Type) method. When this method
is called,
PowerShell attempts to perform the type conversion using its standard
PowerShell language converters
or a custom converter. If PowerShell cannot perform the
conversion, it throws an
PSInvalidCastException exception.
From To Returns
(valueToConvert) (resultType)
Integer System.Enum Converts the integer to the constant if the integer is defined
by the enumeration. If the integer is not defined an
PSInvalidCastException exception is thrown.
Custom conversions
If PowerShell cannot convert the type using a standard PowerShell language converter, it
then checks
for custom converters. PowerShell looks for several types of custom
converters in the order
described in this section. Be aware that references to the
valueToConvert and resultType
parameters refer to parameters of the
ConvertTo(System.Object, System.Type) method. If a custom
converter throws an
exception, then no further attempt is made to convert the object and that
exception is
wrapped in a PSInvalidCastException exception which is then thrown.
Parse converter
If the valueToConvert parameter is a string, and the object type of the resultType
parameter
has a Parse method, then the Parse method is called to convert the string.
Constructor converter
If the object type of the resultType parameter has a constructor that has a single
parameter
that is the same type as the object of the valueToConvert parameter, then
this constructor is
called.
Implicit cast operator converter
If the valueToConvert parameter has an implicit cast operator that converts to
resultType,
then its cast operator is called. If the resultType parameter has an implicit
cast operator that
converts from valueToConvert, then its cast operator is called.
Errors can occur in ETS during the initialization of type data and when accessing a
member of an
PSObject object or using one of the utility classes such as
LanguagePrimitives.
Runtime errors
With one exception, when casting, all exceptions thrown from ETS during runtime are
either an
ExtendedTypeSystemException exception or an exception derived from the
ExtendedTypeSystemException class. This allows script developers to trap these
exceptions using
the Trap statement in their script.
Casting errors
When an invalid cast is attempted, an PSInvalidCastException is thrown. Because this
exception
derives from System.InvalidCastException, it is not able to be directly trapped
from script. Be
aware that the entity attempting the cast would need to wrap
PSInvalidCastException in an
PSRuntimeException for this to be trappable by scripts. If
an attempt is made to set the value
of an PSPropertySet, PSMemberSet,
PSMethodInfo, or a member of the
ReadOnlyPSMemberInfoCollection`1, a
NotSupportedException is thrown.
Initialization errors
Errors may occur when initializing types.ps1xml . Typically, these errors are displayed
when the
PowerShell runtime starts. However, they can also be displayed when a
module is loaded.
Windows PowerShell Programmer's
Guide
Article • 09/17/2021
A powerful Windows PowerShell runtime (execution engine) with its own parser
and a mechanism for
automatically binding command parameters.
Utilities for formatting and displaying command results using a command line
interpreter (CLI).
At little cost, you can represent a .NET object by a rich command or set of
commands that will
offer a complete command-line experience to the
administrator.
The next section covers the key Windows PowerShell concepts and terms.
Familiarize yourself with
these concepts and terms before starting development.
For more information about cmdlets, see Writing a Windows PowerShell Cmdlet.
If you expose a data store that the user will need to access, you might need to write
your own
Windows PowerShell provider, as described in
Creating Windows PowerShell
Providers. For more
information aboutWindows PowerShell providers, see
How
Windows PowerShell Works .
Host Application
Windows PowerShell includes the default host application powershell.exe, which is a
console
application that interacts with the user and hosts the Windows PowerShell
runtime using a console
window.
Only rarely will you need to write your own host application for Windows PowerShell,
although
customization is supported. One case in which you might need your own
application is when you have a
requirement for a GUI interface that is richer than the
interface provided by the default host
application. You might also want a custom
application when you are basing your GUI on the command
line. For more information,
see
How to Create a Windows PowerShell Host Application.
Using ETS, you can create flexible new "types" that are compatible with the
Windows PowerShell
language. If you are a .NET developer, you are able to work
with objects using the same semantics
as the Windows PowerShell language
applies to scripting, for example, to determine if an object
evaluates to true .
For more information about ETS and how Windows PowerShell uses objects, see
Windows PowerShell Object Concepts.
Programming for Windows PowerShell
Windows PowerShell defines its code for commands, providers, and other program
modules using the
.NET Framework. You are not confined to the use of Microsoft Visual
Studio in creating customized
modules for Windows PowerShell, although the samples
provided in this guide are known to run in this
tool. You can use any .NET language that
supports class inheritance and the use of attributes. In
some cases, Windows PowerShell
APIs require the programming language to be able to access generic
types.
Programmer's Reference
For reference when developing for Windows PowerShell, see the
Windows PowerShell
SDK.
How to Create a This section describes how to build a Windows PowerShell provider for
Windows PowerShell Windows PowerShell.
Provider
How to Create a This section describes how to write a host application that manipulates
Windows PowerShell a runspace and how to write a host application that implements its own
Host Application custom host.
How to Create a This section describes how to create a snap-in that is used to register
Windows PowerShell all cmdlets and providers in an assembly and how to create a custom
Snap-in snap-in.
How to Create a This section describes how to create a console shell that is not
Console Shell extensible.
Windows PowerShell This section contains conceptual information that will help you
Concepts understand Windows PowerShell from the viewpoint of a developer.
See Also
Windows PowerShell SDK
How to Create a Windows PowerShell
Provider
Article • 09/17/2021
To the developer, the Windows PowerShell provider is the interface between the user
and the data
that the user needs to access. From this perspective, each type of provider
described in this
section supports a set of specific base classes and interfaces that allow
the Windows PowerShell
runtime to expose certain cmdlets to the user in a common
way.
PS>get-help about_providers
In This Section
The following table lists topics that include code examples that build on each other.
Starting with
the second topic, the basic Windows PowerShell provider can be initialized
and uninitialized by the
Windows PowerShell runtime, the next topic adds functionality
for accessing the data, the next topic
adds functionality for manipulating the data (the
items in the stored data), and so on.
Topic Definition
Designing Your This topic discusses things you should consider before implementing a
Windows Windows PowerShell provider. It summarizes the Windows PowerShell
PowerShell provider base classes and interfaces that are used.
Provider
Creating a Basic This topic shows how to create a Windows PowerShell provider that allows
Windows the Windows PowerShell runtime to initialize and uninitialize the provider.
PowerShell
Provider
Creating a This topic shows how to create a Windows PowerShell provider that allows
Windows the user to access a data store through a Windows PowerShell drive.
PowerShell Drive
Provider
Creating a This topic shows how to create a Windows PowerShell provider that allows
Windows the user to manipulate the items in a data store.
PowerShell Item
Provider
Topic Definition
Creating a This topic shows how to create a Windows PowerShell provider that allows
Windows the user to work on multilayer data stores.
PowerShell
Container Provider
Creating a This topic shows how to create a Windows PowerShell provider that allows
Windows the user to navigate the items of a data store in a hierarchical manner.
PowerShell
Navigation
Provider
Creating a This topic shows how to create a Windows PowerShell provider that allows
Windows the user to manipulate the content of items in a data store.
PowerShell
Content Provider
Creating a This topic shows how to create a Windows PowerShell provider that allows
Windows the user to manipulate the properties of items in a data store.
PowerShell
Property Provider
See Also
How Windows PowerShell Works
For more information about Windows PowerShell paths, see How Windows PowerShell
Works.
Each Windows PowerShell provider base class makes available a set of cmdlets. This
section describes
the cmdlets, but it does not describe their parameters.
Using the session state, the Windows PowerShell runtime makes several location
cmdlets available to
certain Windows PowerShell providers, such as the Get-Location ,
Set-Location , Pop-Location ,
and Push-Location cmdlets. You can use the Get-Help
7 Note
Cmdlet Definition
New-PSDrive Creates a new drive for the session, and streams drive information.
Cmdlet Definition
Cmdlet Definition
Clear- Clears the current content of items at the specified location, and replaces it with the
Item "clear" value specified by the provider. This cmdlet does not pass an output object
through the pipeline unless its PassThru parameter is specified.
Get- Retrieves items from the specified location, and streams the resultant objects.
Item
Invoke- Invokes the default action for the item at the specified path.
Item
Set- Sets an item at the specified location with the indicated value. This cmdlet does not
Item pass an output object through the pipeline unless its PassThru parameter is specified.
Resolve- Resolves the wildcards for a Windows PowerShell path, and streams path information.
Path
Test- Tests for the specified path, and returns true if it exists and false otherwise. This
Path cmdlet is implemented to support the IsContainer parameter for the
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject* method.
Cmdlet Definition
Copy- Copies items from one location to another. This cmdlet does not pass an output
Item object through the pipeline unless its PassThru parameter is specified.
Get- Retrieves the child items at the specified location, and streams them as objects.
Childitem
New-Item Creates new items at the specified location, and streams the resultant object.
Rename- Renames an item at the specified location. This cmdlet does not pass an output
Item object through the pipeline unless its PassThru parameter is specified.
Cmdlet Definition
Combine- Combines two paths into a single path, using a provider-specific delimiter between
Path paths. This cmdlet streams strings.
Move- Moves items to the specified location. This cmdlet does not pass an output object
Item through the pipeline unless its PassThru parameter is specified.
A related cmdlet is the basic Parse-Path cmdlet furnished by Windows PowerShell. This
cmdlet can be
used to parse a Windows PowerShell path to support the Parent
parameter. It streams the parent
path string.
IContentCmdletProvider
The
System.Management.Automation.Provider.Icontentcmdletprovider
interface defines
a content provider that performs operations on the content of a data item. The
following table lists the cmdlets exposed by this interface.
Cmdlet Definition
Cmdlet Definition
Add- Appends the indicated value lengths to the contents of the specified item. This cmdlet
Content does not pass an output object through the pipeline unless its PassThru parameter is
specified.
Clear- Sets the content of the specified item to the "clear" value. This cmdlet does not pass an
Content output object through the pipeline unless its PassThru parameter is specified.
Get- Retrieves the contents of the specified items and streams the resultant objects.
Content
Set- Replaces the existing content for the specified items. This cmdlet does not pass an
Content output object through the pipeline unless its PassThru parameter is specified.
IPropertyCmdletProvider
The
System.Management.Automation.Provider.Ipropertycmdletprovider
interface
defines a property Windows PowerShell provider that performs operations on the
properties
of items in the data store. The following table lists the cmdlets exposed by
this interface.
7 Note
Cmdlet Definition
Clear- Sets properties of the specified items to the "clear" value. This cmdlet does not
ItemProperty pass an output object through the pipeline unless its PassThru parameter is
specified.
Get- Retrieves properties from the specified items and streams the resultant objects.
ItemProperty
Set- Sets properties of the specified items with the indicated values. This cmdlet does
ItemProperty not pass an output object through the pipeline unless its PassThru parameter is
specified.
IDynamicPropertyCmdletProvider
The
System.Management.Automation.Provider.Idynamicpropertycmdletprovider
interface, derived from
System.Management.Automation.Provider.Ipropertycmdletprovider,
defines a provider
that specifies dynamic parameters for its supported cmdlets. This type of
provider
handles operations for which properties can be defined at run time, for example, a new
property operation. Such operations are not possible on items having statically defined
properties.
The following table lists the cmdlets exposed by this interface.
Cmdlet Definition
Copy- Copies a property from the specified item to another item. This cmdlet does not
ItemProperty pass an output object through the pipeline unless its PassThru parameter is
specified.
Move- Moves a property from the specified item to another item. This cmdlet does not
ItemProperty pass an output object through the pipeline unless its PassThru parameter is
specified.
New- Creates a property on the specified items and streams the resultant objects.
ItemProperty
Rename- Renames a property of the specified items. This cmdlet does not pass an output
ItemProperty object through the pipeline unless its PassThru parameter is specified.
ISecurityDescriptorCmdletProvider
The
System.Management.Automation.Provider.Isecuritydescriptorcmdletprovider
interface adds security descriptor functionality to a provider. This interface allows the
user to
get and set security descriptor information for an item in the data store. The
following table lists
the cmdlets exposed by this interface.
Cmdlet Definition
Get- Retrieves the information contained in an access control list (ACL), which is part of a
Acl security descriptor used to guard operating system resources, for example, a file or an
object.
See Also
Creating Windows PowerShell Providers
This topic is the starting point for learning how to create a Windows PowerShell
provider. The basic
provider described here provides methods for starting and stopping
the provider, and although this
provider does not provide a means to access a data
store or to get or set the data in the data
store, it does provide the basic functionality
that is required by all providers.
As mentioned previously, the basic provider described here implements methods for
starting and
stopping the provider. The Windows PowerShell runtime calls these
methods to initialize and
uninitialize the provider.
7 Note
provider samples
run.
7 Note
The class for a Windows PowerShell provider must be explicitly marked as public.
Classes not
marked as public will default to internal and will not be found by the
Windows PowerShell runtime.
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
You can set attribute keywords to further declare the class if necessary. Notice that the
System.Management.Automation.Provider.Cmdletproviderattribute
attribute declared
here includes two parameters. The first attribute parameter specifies the
default-friendly
name for the provider, which the user can modify later. The second parameter
specifies
the Windows PowerShell-defined capabilities that the provider exposes to the Windows
PowerShell runtime during command processing. The possible values for the provider
capabilities are
defined by the
System.Management.Automation.Provider.Providercapabilities
enumeration. Because
this is a base provider, it supports no capabilities.
7 Note
The fully qualified name of the Windows PowerShell provider includes the assembly
name and other
attributes determined by Windows PowerShell upon registration of
the provider.
A Windows PowerShell provider can also maintain connection-based state. For more
information about
maintaining connection state, see
Creating a PowerShell Drive
Provider.
Initializing the Provider
To initialize the provider, the Windows PowerShell runtime calls the
System.Management.Automation.Provider.Cmdletprovider.Start*
method when
Windows PowerShell is started. For the most part, your provider can use the default
implementation of this method, which simply returns the
System.Management.Automation.Providerinfo
object that describes your provider.
However, in the case where you want to add additional
initialization information, you
should implement your own
System.Management.Automation.Provider.Cmdletprovider.Start*
method that returns a
modified version of the
System.Management.Automation.Providerinfo
object that is
passed to your provider. In general, this method should return the provided
System.Management.Automation.Providerinfo
object passed to it or a modified
System.Management.Automation.Providerinfo
object that contains other initialization
information.
This basic provider does not override this method. However, the following code shows
the default implementation of this method:
This basic provider does not override this method. However, the following code shows
the default implementation of this method:
This basic provider does not override this method. However, the following code shows
the default
implementation of this method:
Code Sample
For complete sample code, see
AccessDbProviderSample01 Code Sample.
PowerShell
Get-PSProvider
Output
AccessDb None {}
See Also
Creating Windows PowerShell Providers
This topic describes how to create a Windows PowerShell drive provider that provides a
way to access
a data store through a Windows PowerShell drive. This type of provider is
also referred to as
Windows PowerShell drive providers. The Windows PowerShell drives
used by the provider provide the
means to connect to the data store.
The Windows PowerShell drive provider described here provides access to a Microsoft
Access database.
For this provider, the Windows PowerShell drive represents the
database (it is possible to add any
number of drives to a drive provider), the top-level
containers of the drive represent the tables in
the database, and the items of the
containers represent the rows in the tables.
C#
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
For this drive provider, state information includes the connection to the database that is
kept as
part of the drive information. Here is code that shows how this information is
stored in the
System.Management.Automation.PSDriveinfo
object that describes the
drive:
C#
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
Creating a Drive
To allow the Windows PowerShell runtime to create a drive, the drive provider must
implement the
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive*
method. The
following code shows the implementation of the
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive*
method for
this drive provider:
C#
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
Create a drive and populate the connection member, in support of the New-
PSDrive cmdlet.
Validate the
System.Management.Automation.PSDriveinfo
object for the proposed
drive.
Modify the
System.Management.Automation.PSDriveinfo
object that describes the
drive with any required performance or reliability information, or
provide extra
data for callers using the drive.
This method returns either the drive information that was passed to the method or
a
provider-specific version of it.
This drive provider does not override this method. However, the following code shows
the default
implementation of this method:
Removing a Drive
To close the database connection, the drive provider must implement the
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive*
method.
This method closes the connection to the drive after cleaning up any provider-specific
information.
C#
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
If the drive can be removed, the method should return the information passed to the
method through
the drive parameter. If the drive cannot be removed, the method
should write an exception and then
return null . If your provider does not override this
method, the default implementation of this
method just returns the drive information
passed as input.
This method returns a collection of drive information about the initialized drives, or an
empty
collection. The call to this method is made after the Windows PowerShell runtime
calls the
System.Management.Automation.Provider.Cmdletprovider.Start*
method to
initialize the provider.
All drive providers should mount a root drive to help the user with discoverability. The
root drive
might list locations that serve as roots for other mounted drives. For example,
the Active Directory
provider might create a drive that lists the naming contexts found in
the namingContext attributes
on the root Distributed System Environment (DSE). This
helps users discover mount points for other
drives.
Code Sample
For complete sample code, see
AccessDbProviderSample02 Code Sample.
1. Run the Get-PSProvider cmdlet to retrieve the list of providers to ensure that the
AccessDB drive provider is present:
PS> Get-PSProvider
Output
Name Capabilities Drives
AccessDB None {}
2. Ensure that a database server name (DSN) exists for the database by accessing the
Data
Sources portion of the Administrative Tools for the operating system. In the
User DSN
table, double-click MS Access Database and add the drive path
C:\ps\northwind.mdb .
PowerShell
Output
7 Note
The user cannot yet interact with the provider as a drive, as the provider
needs container
functionality for that interaction. For more information, see
Creating a Windows PowerShell Container Provider.
Output
ConnectionString : Driver={Microsoft Access Driver
(*.mdb)};DBQ=c:\ps\northwind.mdb
ConnectionTimeout : 15
Database : c:\ps\northwind
DataSource : ACCESS
ServerVersion : 04.00.0000
Driver : odbcjt32.dll
State : Open
Site :
Container :
PowerShell
PS> exit
See Also
Creating Windows PowerShell Providers
This topic describes how to create a Windows PowerShell provider that can manipulate
the data in a
data store. In this topic, the elements of data in the store are referred to as
the "items" of the
data store. As a consequence, a provider that can manipulate the data
in the store is referred to as
a Windows PowerShell item provider.
7 Note
The Windows PowerShell item provider described in this topic gets items of data from
an Access
database. In this case, an "item" is either a table in the Access database or a
row in a table.
C#
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
For more information about how to implement functionality for adding session-specific
initialization
information and for releasing resources used by the provider, see
Creating
a Basic Windows PowerShell Provider.
However, most providers, including the provider
described here, can use the default implementation
of this functionality that is provided
by Windows PowerShell.
Before the Windows PowerShell item provider can manipulate the items in the store, it
must implement
the methods of the
System.Management.Automation.Provider.DriveCmdletProvider
base class to access to
the data store. For more information about implementing this class, see
Creating a
Windows PowerShell Drive Provider.
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
C#
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be within
return true;
return false;
} // ItemExists
When defining the provider class, a Windows PowerShell item provider might
declare provider
capabilities of ExpandWildcards , Filter , Include , or Exclude ,
from the
System.Management.Automation.Provider.ProviderCapabilities
enumeration. In these cases, the implementation of the
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists
method
must ensure that the path passed to the method meets the requirements of the
specified
capabilities. To do this, the method should access the appropriate
property, for example, the
System.Management.Automation.Provider.CmdletProvider.Exclude
and
System.Management.Automation.Provider.CmdletProvider.Include
properties.
The implementation of this method should handle any form of access to the item
that might make the
item visible to the user. For example, if a user has write access
to a file through the FileSystem
provider (supplied by Windows PowerShell), but
not read access, the file still exists and
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists
returns
true . Your implementation might require checking a parent item to see if the child
item
can be enumerated.
This Windows PowerShell item provider does not implement this method. However, the
following code is
the default implementation of this method.
Retrieving an item
To retrieve an item, the Windows PowerShell item provider must override
System.Management.Automation.Provider.ItemCmdletProvider.GetItem
method to
support calls from the Get-Item cmdlet. This method writes the item using the
System.Management.Automation.Provider.CmdletProvider.WriteItemObject
method.
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
When defining the provider class, a Windows PowerShell item provider might
declare provider
capabilities of ExpandWildcards , Filter , Include , or Exclude ,
from the
System.Management.Automation.Provider.ProviderCapabilities
enumeration. In these cases, the implementation of
System.Management.Automation.Provider.ItemCmdletProvider.GetItem
must
ensure that the path passed to the method meets those requirements. To do this,
the method
should access the appropriate property, for example, the
System.Management.Automation.Provider.CmdletProvider.Exclude
and
System.Management.Automation.Provider.CmdletProvider.Include
properties.
By default, overrides of this method should not retrieve objects that are generally
hidden from
the user unless the
System.Management.Automation.Provider.CmdletProvider.Force
property is set to
true . For example, the
System.Management.Automation.Provider.ItemCmdletProvider.GetItem
method
for the FileSystem provider checks the
System.Management.Automation.Provider.CmdletProvider.Force
property before it
attempts to call
System.Management.Automation.Provider.CmdletProvider.WriteItemObject
for
hidden or system files.
This provider does not implement this method. However, the following code is the
default
implementation of this method.
Setting an item
To set an item, the Windows PowerShell item provider must override the
System.Management.Automation.Provider.ItemCmdletProvider.SetItem
method to
support calls from the Set-Item cmdlet. This method sets the value of the item at the
specified path.
When defining the provider class, a Windows PowerShell item provider might
declare provider
capabilities of ExpandWildcards , Filter , Include , or Exclude ,
from the
System.Management.Automation.Provider.ProviderCapabilities
enumeration. In these cases, the implementation of
System.Management.Automation.Provider.ItemCmdletProvider.SetItem
must
ensure that the path passed to the method meets those requirements. To do this,
the method
should access the appropriate property, for example, the
System.Management.Automation.Provider.CmdletProvider.Exclude
and
System.Management.Automation.Provider.CmdletProvider.Include
properties.
By default, overrides of this method should not set or write objects that are hidden
from the user
unless the
System.Management.Automation.Provider.CmdletProvider.Force
property is set to
true . An error should be sent to the
System.Management.Automation.Provider.CmdletProvider.WriteError
method if
the path represents a hidden item and
System.Management.Automation.Provider.CmdletProvider.Force
is set to false .
This provider does not implement this method. However, the following code is the
default
implementation of this method.
Clearing an item
To clear an item, the Windows PowerShell item provider implements the
System.Management.Automation.Provider.ItemCmdletProvider.ClearItem
method to
support calls from the Clear-Item cmdlet. This method erases the data item at the
specified path.
This provider does not implement this method. However, the following code is the
default
implementation of this method.
When defining the provider class, a Windows PowerShell item provider might
declare provider
capabilities of ExpandWildcards , Filter , Include , or Exclude ,
from the
System.Management.Automation.Provider.ProviderCapabilities
enumeration. In these cases, the implementation of
System.Management.Automation.Provider.ItemCmdletProvider.ClearItem
must
ensure that the path passed to the method meets those requirements. To do this,
the method
should access the appropriate property, for example, the
System.Management.Automation.Provider.CmdletProvider.Exclude
and
System.Management.Automation.Provider.CmdletProvider.Include
properties.
By default, overrides of this method should not set or write objects that are hidden
from the user
unless the
System.Management.Automation.Provider.CmdletProvider.Force
property is set to
true . An error should be sent to the
System.Management.Automation.Provider.CmdletProvider.WriteError
method if
the path represents an item that is hidden from the user and
System.Management.Automation.Provider.CmdletProvider.Force
is set to false .
This item provider does not implement this method. However, the following code is the
default
implementation of this method.
This provider does not implement this method. However, the following code is the
default
implementation of this method.
When defining the provider class, a Windows PowerShell item provider might
declare provider
capabilities of ExpandWildcards , Filter , Include , or Exclude ,
from the
System.Management.Automation.Provider.ProviderCapabilities
enumeration. In these cases, the implementation of
System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultActio
n
must ensure that the path passed to the method meets those requirements. To
do this, the method
should access the appropriate property, for example, the
System.Management.Automation.Provider.CmdletProvider.Exclude
and
System.Management.Automation.Provider.CmdletProvider.Include
properties.
By default, overrides of this method should not set or write objects hidden from
the user unless
the
System.Management.Automation.Provider.CmdletProvider.Force
property is set to
true . An error should be sent to the
System.Management.Automation.Provider.CmdletProvider.WriteError
method if
the path represents an item that is hidden from the user and
System.Management.Automation.Provider.CmdletProvider.Force
is set to false .
This item provider does not implement this method. However, the following code is the
default
implementation of this method.
NormalizePath method
This item provider implements a NormalizePath helper method to ensure that the path
has a
consistent format. The format specified uses a backslash ( \ ) as a separator.
PathIsDrive method
This item provider implements a PathIsDrive helper method to determine if the
specified path is
actually the drive name.
ChunkPath method
This item provider implements a ChunkPath helper method that breaks up the specified
path so
that the provider can identify its individual elements. It returns an array
composed of the path
elements.
GetTable method
This item provider implements the GetTables helper method that returns a
DatabaseTableInfo
object that represents information about the table specified in the
call.
GetRow method
The
System.Management.Automation.Provider.ItemCmdletProvider.GetItem
method of
this item provider calls the GetRows helper method. This helper method retrieves a
DatabaseRowInfo object that represents information about the specified row in the
table.
DatabaseTableInfo class
This item provider defines a DatabaseTableInfo class that represents a collection of
information
in a data table in the database. This class is similar to the
System.IO.Directoryinfo class.
DatabaseRowInfo class
This item provider defines the DatabaseRowInfo helper class that represents a row in a
table of
the database. This class is similar to the System.IO.FileInfo
class.
Code sample
For complete sample code, see AccessDbProviderSample03 Code Sample.
Defining object types and formatting
When writing a provider, it may be necessary to add members to existing objects or
define new
objects. When finished, create a Types file that Windows PowerShell can use
to identify the members
of the object and a Format file that defines how the object is
displayed. For more information, see
Extending Object Types and Formatting.
See also
Windows PowerShell SDK
Windows PowerShell Programmer's Guide
Creating Windows PowerShell Providers
Designing Your Windows PowerShell provider
Extending Object Types and Formatting
How Windows PowerShell Works
Creating a Container Windows PowerShell provider
Creating a Drive Windows PowerShell provider
How to Register Cmdlets, Providers, and Host Applications
Creating a Windows PowerShell
Container Provider
Article • 11/08/2021
This topic describes how to create a Windows PowerShell provider that can work on
multi-layer data
stores. For this type of data store, the top level of the store contains the
root items and each
subsequent level is referred to as a node of child items. By allowing
the user to work on these
child nodes, a user can interact hierarchically through the data
store.
Providers that can work on multi-level data stores are referred to as Windows
PowerShell container
providers. However, be aware that a Windows PowerShell
container provider can be used only when
there is one container (no nested containers)
with items in it. If there are nested containers, then
you must implement a Windows
PowerShell navigation provider. For more information about implementing
Windows
PowerShell navigation provider, see
Creating a Windows PowerShell Navigation
Provider.
7 Note
The Windows PowerShell container provider described here defines the database as its
single
container, with the tables and rows of the database defined as items of the
container.
U Caution
Be aware that this design assumes a database that has a field with the name ID, and
that the type
of the field is LongInteger.
Defining a Windows PowerShell Container
Provider Class
A Windows PowerShell container provider must define a .NET class that derives from the
System.Management.Automation.Provider.Containercmdletprovider
base class. Here is
the class definition for the Windows PowerShell container provider described in
this
section.
C#
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
To get access to the data store, the provider must implement the methods of the
System.Management.Automation.Provider.Drivecmdletprovider
base class. For more
information about implementing these methods, see
Creating an Windows PowerShell
Drive Provider.
To manipulate the items of a data store, such as getting, setting, and clearing items, the
provider
must implement the methods provided by the
System.Management.Automation.Provider.Itemcmdletprovider
base class. For more
information about implementing these methods, see
Creating an Windows PowerShell
Item Provider.
C#
// returned
if (PathIsDrive(path))
// if the specified item exists and recurse has been set then
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
When defining the provider class, a Windows PowerShell container provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method needs to ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
The implementation of this method should take into account any form of access to
the item that
might make the item visible to the user. For example, if a user has
write access to a file through
the FileSystem provider (supplied by Windows
PowerShell), but not read access, the file still
exists and
System.Management.Automation.Provider.Itemcmdletprovider.Itemexists*
returns
true . Your implementation might require the checking of a parent item to see if
the
child can be enumerated.
Your implementation of
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
is responsible for preventing infinite recursion when there are circular links, and
the like. An
appropriate terminating exception should be thrown to reflect such a
condition.
This Windows PowerShell container provider does not implement this method. However,
the following
code is the default implementation of this method.
Retrieving Child Item Names
To retrieve the names of child items, the Windows PowerShell container provider must
override the
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames*
method to support calls from the Get-ChildItem cmdlet when its Name parameter is
specified. This
method retrieves the names of the child items for the specified path or
child item names for all
containers if the returnAllContainers parameter of the cmdlet
is specified. A child name is the
leaf portion of a path. For example, the child name for
the path c:\windows\system32\abc.dll is
"abc.dll". The child name for the directory
c:\windows\system32 is "system32".
C#
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
When defining the provider class, a Windows PowerShell container provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method needs to ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
7 Note
By default, overrides of this method should not retrieve names of objects that are
generally
hidden from the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is
specified. If the specified path indicates a container, the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is not
required.
Your implementation of
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames
*
is responsible for preventing infinite recursion when there are circular links, and
the like. An
appropriate terminating exception should be thrown to reflect such a
condition.
This provider does not implement this method. However, the following code is the
default
implementation of this method.
Renaming Items
To rename an item, a Windows PowerShell container provider must override the
System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
method to support calls from the Rename-Item cmdlet. This method changes the name
of the item at
the specified path to the new name provided. The new name must always
be relative to the parent item
(container).
When defining the provider class, a Windows PowerShell container provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method needs to ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
The
System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
method is intended for the modification of the name of an item only, and not for
move operations.
Your implementation of the method should write an error if the
newName parameter contains path
separators, or might otherwise cause the item to
By default, overrides of this method should not rename objects unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is
specified. If the specified path indicates a container, the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is not
required.
System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
method should call the
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue
method. This method sends a message a confirmation message to the user to
allow additional
feedback to say if the operation should be continued. A provider
should call
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue
as an
additional check for potentially dangerous system modifications.
This container provider does not implement this method. However, the following code is
the default
implementation of this method.
//
// Example
//
// {
// }
} // NewItem
C#
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
The
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
method should perform a case-insensitive comparison of the string passed in the
type parameter.
It should also allow for least ambiguous matches. For example, for
This provider does not implement this method. However, the following code is the
default implementation of this method.
Removing Items
To remove items, the Windows PowerShell provider must override the
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
method to support calls from the Remove-Item cmdlet. This method deletes an item
from the data
store at the specified path. If the recurse parameter of the Remove-Item
cmdlet is set to
true , the method removes all child items regardless of their level. If the
parameter is set to
false , the method removes only a single item at the specified path.
This provider does not support item removal. However, the following code is the default
implementation of
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*.
When defining the provider class, a Windows PowerShell container provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method needs to ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
By default, overrides of this method should not remove objects unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true. If the specified path indicates a container, the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is not
required.
Your implementation of
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
is responsible for preventing infinite recursion when there are circular links, and
the like. An
appropriate terminating exception should be thrown to reflect such a
condition.
This container provider does not implement this method. However, the following code is
the default
implementation of
System.Management.Automation.Provider.Containercmdletprovider.Removeitemdynami
cparameters*.
C#
return false;
} // HasChildItems
C#
ErrorCategory.InvalidOperation, tableName));
return results;
If the container provider exposes a root that contains interesting mount points, the
implementation of the
System.Management.Automation.Provider.Containercmdletprovider.Haschilditems*
method should return true when a null or an empty string is passed in for the
path.
Copying Items
To copy items, the container provider must implement the
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
method
to support calls from the Copy-Item cmdlet. This method copies a data item from the
location indicated by the path parameter of the cmdlet to the location indicated by the
copyPath
parameter. If the recurse parameter is specified, the method copies all sub-
containers. If the
parameter is not specified, the method copies only a single level of
items.
This provider does not implement this method. However, the following code is the
default implementation of
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem.
When defining the provider class, a Windows PowerShell container provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
method needs to ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
By default, overrides of this method should not copy objects over existing objects
unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to true . For example, the FileSystem provider will not copy
c:\temp\abc.txt over
an existing c:\abc.txt file unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . If the path specified in the copyPath parameter exists and indicates
a
container, the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is not required. In this case,
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
should copy the item indicated by the path parameter to the container indicated
by the
copyPath parameter as a child.
Your implementation of
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
is
responsible for preventing infinite recursion when there are circular links, and the
like. An
appropriate terminating exception should be thrown to reflect such a
condition.
This provider does not implement this method. However, the following code is the
default
implementation of
System.Management.Automation.Provider.Containercmdletprovider.Copyitemdynamicp
arameters*.
Code Sample
For complete sample code, see
AccessDbProviderSample04 Code Sample.
1. Run the Get-ChildItem cmdlet to retrieve the list of child items from a Customers
table in the
Access database.
PowerShell
Get-ChildItem mydb:customers
Output
PSPath : AccessDB::customers
PSDrive : mydb
PSProvider : System.Management.Automation.ProviderInfo
PSIsContainer : True
Data : System.Data.DataRow
Name : Customers
RowCount : 91
Columns :
PowerShell
(Get-ChildItem mydb:customers).data
Output
TABLE_CAT : c:\PS\northwind
TABLE_SCHEM :
TABLE_NAME : Customers
TABLE_TYPE : TABLE
REMARKS :
3. Now use the Get-Item cmdlet to retrieve the items at row 0 in the data table.
PowerShell
Get-Item mydb:\customers\0
Output
PSPath : AccessDB::customers\0
PSDrive : mydb
PSProvider : System.Management.Automation.ProviderInfo
PSIsContainer : False
Data : System.Data.DataRow
RowNumber : 0
PowerShell
(Get-Item mydb:\customers\0).data
Output
CustomerID : 1234
CompanyName : Fabrikam
ContactTitle : President
City : Buffalo
Region : NY
PostalCode : 98052
Country : USA
5. Now use the New-Item cmdlet to add a row to an existing table. The Path
parameter specifies
the full path to the row, and must indicate a row number that
is greater than the existing number
of rows in the table. The Type parameter
indicates "row" to specify that type of item to add.
Finally, the Value parameter
specifies a comma-delimited list of column values for the row.
PowerShell
none
PS mydb:\> cd Customers
Output
ID : 3
FirstName : Eric
LastName : Gruber
Email : [email protected]
Title : President
Company : Fabrikam
City : Buffalo
State : NY
Zip : 98052
Country : USA
See Also
Creating Windows PowerShell Providers
This topic describes how to create a Windows PowerShell navigation provider that can
navigate the
data store. This type of provider supports recursive commands, nested
containers, and relative
paths.
7 Note
The provider described here enables the user handle an Access database as a drive so
that the user
can navigate to the data tables in the database. When creating your own
navigation provider, you can
implement methods that can make drive-qualified paths
required for navigation, normalize relative
paths, move items of the data store, as well as
methods that get child names, get the parent path of
an item, and test to identify if an
item is a container.
U Caution
Be aware that this design assumes a database that has a field with the name ID, and
that the type
of the field is LongInteger.
C#
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
To get access to the data store through a Windows PowerShell drive, you must
implement the methods
of the
System.Management.Automation.Provider.Drivecmdletprovider
base class. For more
information about implementing these methods, see
Creating a Windows PowerShell
Drive Provider.
To manipulate the items of a data store, such as getting, setting, and clearing items, the
provider
must implement the methods provided by the
System.Management.Automation.Provider.Itemcmdletprovider
base class. For more
information about implementing these methods, see
Creating an Windows PowerShell
Item Provider.
To get to the child items, or their names, of the data store, as well as methods that
create, copy,
rename, and remove items, you must implement the methods provided by
the
System.Management.Automation.Provider.Containercmdletprovider
base class. For
more information about implementing these methods, see
Creating a Windows
PowerShell Container Provider.
Creating a Windows PowerShell Path
Windows PowerShell navigation provider use a provider-internal Windows PowerShell
path to navigate
the items of the data store. To create a provider-internal path the
provider must implement the
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
method to supports calls from the Combine-Path cmdlet. This method combines a
parent and child path
into a provider-internal path, using a provider-specific path
separator between the parent and child
paths.
The default implementation takes paths with "/" or "\" as the path separator, normalizes
the path
separator to "\", combines the parent and child path parts with the separator
between them, and
then returns a string that contains the combined paths.
This navigation provider does not implement this method. However, the following code
is the default
implementation of the
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
method.
) Important
The sample navigation provider does not override this method, but uses the default
implementation.
It accepts paths that use both "/" and "\" as path separators. It first
normalizes the path to have
only "\" separators, then splits the parent path off at the last
"\" and returns the parent path.
The sample navigation provider does not override this method. The default
implementation is shown
below. It accepts paths that use both "/" and "\" as path
separators. It first normalizes the path
to have only "\" separators, then splits the parent
path off at the last "\" and returns the name
of the child path part.
) Important
The path provided in the call to this method might contain characters that are
illegal in the
provider namespace. These characters are most likely used for
wildcard expansion or regular
expression matching, and the implementation of this
method should not remove them.
C#
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
return true;
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
} // IsItemContainer
Moving an Item
In support of the Move-Item cmdlet, your navigation provider implements the
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*
method. This method moves the item specified by the path parameter to the container
at the path
supplied in the destination parameter.
System.Management.Automation.Provider.Cmdletprovider.Force*
property is not
required. In this case,
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*
should
move the item indicated by the path parameter to the container indicated by the
destination parameter as a child.
This navigation provider does not implement this method. However, the following code
is the default
implementation of
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitemdynamic
parameters*.
The sample navigation provider does not override this method. The following is the
default implementation.
Code Sample
For complete sample code, see AccessDbProviderSample05 Code Sample.
1. Run your new shell and use the Set-Location cmdlet to set the path to indicate
the Access
database.
PowerShell
Set-Location mydb:
2. Now run the Get-Childitem cmdlet to retrieve a list of the database items, which
are the
available database tables. For each table, this cmdlet also retrieves the
number of table rows.
PowerShell
Output
RowCount Name
-------- ----
180 MSysAccessObjects
0 MSysACEs
1 MSysCmdbars
0 MSysIMEXColumns
0 MSysIMEXSpecs
0 MSysObjects
0 MSysQueries
7 MSysRelationships
8 Categories
91 Customers
9 Employees
830 Orders
77 Products
3 Shippers
29 Suppliers
3. Use the Set-Location cmdlet again to set the location of the Employees data table.
PowerShell
Set-Location Employees
4. Let's now use the Get-Location cmdlet to retrieve the path to the Employees table.
PowerShell
Get-Location
Output
Path
----
mydb:\Employees
5. Now use the Get-Childitem cmdlet piped to the Format-Table cmdlet. This set of
cmdlets
retrieves the items for the Employees data table, which are the table rows.
They are formatted as
specified by the Format-Table cmdlet.
PowerShell
Output
1 False System.Data.DataRow
2 False System.Data.DataRow
3 False System.Data.DataRow
4 False System.Data.DataRow
5 False System.Data.DataRow
6 False System.Data.DataRow
7 False System.Data.DataRow
8 False System.Data.DataRow
6. You can now run the Get-Item cmdlet to retrieve the items for row 0 of the
Employees data
table.
PowerShell
Get-Item 0
Output
PSPath : AccessDB::C:\PS\Northwind.mdb\Employees\0
PSParentPath : AccessDB::C:\PS\Northwind.mdb\Employees
PSChildName : 0
PSDrive : mydb
PSProvider : System.Management.Automation.ProviderInfo
PSIsContainer : False
Data : System.Data.DataRow
RowNumber : 0
7. Use the Get-Item cmdlet again to retrieve the employee data for the items in row
0.
PowerShell
(Get-Item 0).data
Output
EmployeeID : 1
LastName : Davis
FirstName : Sara
TitleOfCourtesy : Ms.
Apt. 2A
City : Buffalo
Region : NY
PostalCode : 98052
Country : USA
Extension : 5467
Photo : EmpID1.bmp
Toastmasters International.
ReportsTo : 2
See Also
Creating Windows PowerShell providers
This topic describes how to create a Windows PowerShell provider that enables the user
to manipulate
the contents of the items in a data store. As a consequence, a provider
that can manipulate the
contents of items is referred to as a Windows PowerShell
content provider.
7 Note
C#
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
For more information about how to implement functionality for adding session-specific
initialization
information and for releasing resources that are used by the provider, see
Creating a Basic Windows PowerShell Provider.
However, most providers, including the
provider described here, can use the default implementation
of this functionality that is
provided by Windows PowerShell.
To access the data store, the provider must implement the methods of the
System.Management.Automation.Provider.Drivecmdletprovider
base class. For more
information about implementing these methods, see
Creating a Windows PowerShell
Drive Provider.
To manipulate the items of a data store, such as getting, setting, and clearing items, the
provider
must implement the methods provided by the
System.Management.Automation.Provider.Itemcmdletprovider
base class. For more
information about implementing these methods, see
Creating a Windows PowerShell
Item Provider.
To work on multi-layer data stores, the provider must implement the methods provided
by the
System.Management.Automation.Provider.Containercmdletprovider
base class.
For more information about implementing these methods, see
Creating a Windows
PowerShell Container Provider.
To support recursive commands, nested containers, and relative paths, the provider
must implement
the
System.Management.Automation.Provider.Navigationcmdletprovider
base class. In
addition, this Windows PowerShell content provider can attaches
System.Management.Automation.Provider.Icontentcmdletprovider
interface to the
System.Management.Automation.Provider.Navigationcmdletprovider
base class, and
must therefore implement the methods provided by that class. For more information,
see implementing those methods, see
Implement a Navigation Windows PowerShell
Provider.
Implementing a Content Reader
To read content from an item, a provider must implements a content reader class that
derives from
System.Management.Automation.Provider.Icontentreader.
The content
reader for this provider allows access to the contents of a row in a data table. The
content reader class defines a Read method that retrieves the data from the indicated
row and
returns a list representing that data, a Seek method that moves the content
reader, a Close
method that closes the content reader, and a Dispose method.
C#
this.path = path;
this.provider = provider;
}
/// <summary>
/// </summary>
/// return.</param>
// offset
string tableName;
int rowNumber;
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
return null;
int rowsRead = 0;
results.Add(rows[(int)currentOffset].Data);
rowsRead++;
currentOffset++;
return results;
} // Read
/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
if (type == PathType.Table)
throw new
ArgumentException(
);
if (origin == System.IO.SeekOrigin.Begin)
currentOffset = offset - 1;
else
currentOffset += offset;
} // if (type...
else
currentOffset = 0;
} // Seek
/// <summary>
/// </summary>
Dispose();
} // Close
/// <summary>
/// </summary>
Seek(0, System.IO.SeekOrigin.Begin);
GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentReader
C#
this.path = path;
this.provider = provider;
}
/// <summary>
/// </summary>
/// </param>
///
if (content == null)
return null;
// the end
string tableName;
int rowNumber;
if (type == PathType.Table)
OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
if (da == null)
return null;
if (!String.IsNullOrEmpty(colValues[i]))
row[i] = colValues[i];
//table.Rows.InsertAt(row, rowNumber);
table.Rows.Add(row);
da.Update(ds, tableName);
else
return null;
} // Write
/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
throw new
ArgumentException(
);
if (origin == System.IO.SeekOrigin.Begin)
currentOffset = offset - 1;
else
currentOffset += offset;
} // Seek
/// <summary>
/// </summary>
Dispose();
} // Close
/// <summary>
/// </summary>
Seek(0, System.IO.SeekOrigin.Begin);
GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentWriter
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
} // GetContentReader
C#
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
} // GetContentReader
By default, overrides of this method should not retrieve a reader for objects that
are hidden from
the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . An error should be written if the path represents an item that is
hidden from
the user and
System.Management.Automation.Provider.Cmdletprovider.Force*
is
set to false .
This Windows PowerShell container provider does not implement this method. However,
the following
code is the default implementation of this method.
C#
return null;
C#
return null;
C#
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
C#
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
When defining the provider class, a Windows PowerShell content provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwrite
r*
method must ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
By default, overrides of this method should not retrieve a writer for objects that are
hidden from
the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . An error should be written if the path represents an item that is
hidden from
This Windows PowerShell container provider does not implement this method. However,
the following
code is the default implementation of this method.
C#
return null;
Clearing Content
Your content provider implements the
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
method in support of the Clear-Content cmdlet. This method removes the contents of
the item at the
specified path, but leaves the item intact.
C#
string tableName;
int rowNumber;
if (type != PathType.Table)
WriteError(new ErrorRecord(
"NotValidRow", ErrorCategory.InvalidArgument,
path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "ClearContent"))
da.Update(ds, tableName);
}
} // ClearContent
When defining the provider class, a Windows PowerShell content provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
method must ensure that the path passed to the method meets the requirements
of the specified
capabilities. To do this, the method should access the appropriate
property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
By default, overrides of this method should not clear the contents of objects that
are hidden from
the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . An error should be written if the path represents an item that is
hidden from
This Windows PowerShell container provider does not implement this method. However,
the following code is the default implementation of this method.
C#
return null;
C#
return null;
Code Sample
For complete sample code, see AccessDbProviderSample06 Code Sample.
Use the Get-Content cmdlet to retrieve the contents of specified item in the database
table at the
path specified by the Path parameter. The ReadCount parameter specifies
the number of items for
the defined content reader to read (default 1). With the
following command entry, the cmdlet
retrieves two rows (items) from the table and
displays their contents. Note that the following
example output uses a fictitious Access
database.
PowerShell
Output
ID : 1
FirstName : Eric
LastName : Gruber
Email : [email protected]
Title : President
Company : Fabrikam
City : Buffalo
State : NY
Zip : 98052
Country : USA
ID : 2
FirstName : Eva
LastName : Corets
Email : [email protected]
City : Cabmerlot
State : WA
Zip : 98089
Country : USA
See Also
Creating Windows PowerShell providers
This topic describes how to create a provider that enables the user to manipulate the
properties of
items in a data store. As a consequence, this type of provider is referred to
as a Windows
PowerShell property provider. For example, the Registry provider provided
by Windows PowerShell
handles registry key values as properties of the registry key
item. This type of provider must add
the
System.Management.Automation.Provider.Ipropertycmdletprovider
interface to the
implementation of the .NET class.
7 Note
Windows PowerShell provides a template file that you can use to develop a
Windows PowerShell
provider. The TemplateProvider.cs file is available on the
Microsoft Windows Software Development
Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded template is available in the <PowerShell Samples> directory. You
should make a
copy of this file and use the copy for creating a new Windows
PowerShell provider, removing any
functionality that you do not need. For more
information about other Windows PowerShell provider
implementations, see
Designing Your Windows PowerShell Provider.
U Caution
The methods of your property provider should write any objects using the
System.Management.Automation.Provider.Cmdletprovider.Writepropertyobject*
method.
Retrieving Properties
To retrieve properties, the provider must implement the
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty*
method to support calls from the Get-ItemProperty cmdlet. This method retrieves the
properties of
the item located at the specified provider-internal path (fully-qualified).
When defining the provider class, a Windows PowerShell property provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty*
method needs to ensure that the path passed to the method meets the
requirements of the specified
capabilities. To do this, the method should access the
appropriate property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
By default, overrides of this method should not retrieve a reader for objects that
are hidden from
the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . An error should be written if the path represents an item that is
hidden from
the user and
System.Management.Automation.Provider.Cmdletprovider.Force*
is
set to false .
Setting Properties
To set properties, the Windows PowerShell property provider must implement the
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
method to support calls from the Set-ItemProperty cmdlet. This method sets one or
more properties
of the item at the specified path, and overwrites the supplied properties
as required.
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
also
writes an instance of a
System.Management.Automation.PSObject object
that represents
a property bag of the updated properties.
When defining the provider class, a Windows PowerShell property provider might
declare provider
capabilities of ExpandWildcards, Filter, Include, or Exclude, from
the
System.Management.Automation.Provider.Providercapabilities
enumeration. In
these cases, the implementation of the
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
method must ensure that the path passed to the method meets the requirements
of the specified
capabilities. To do this, the method should access the appropriate
property, for example, the
System.Management.Automation.Provider.Cmdletprovider.Exclude*
and
System.Management.Automation.Provider.Cmdletprovider.Include*
properties.
By default, overrides of this method should not retrieve a reader for objects that
are hidden from
the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . An error should be written if the path represents an item that is
hidden from
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
method should call the
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue
method. This method sends a confirmation message to the user to allow additional
feedback to
indicate that the operation should be continued.
Clearing Properties
To clear properties, the Windows PowerShell property provider must implement the
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
method to support calls from the Clear-ItemProperty cmdlet. This method sets one or
more
properties for the item located at the specified path.
By default, overrides of this method should not retrieve a reader for objects that
are hidden from
the user unless the
System.Management.Automation.Provider.Cmdletprovider.Force*
property is set to
true . An error should be written if the path represents an item that is
hidden from
the user and
System.Management.Automation.Provider.Cmdletprovider.Force*
is
set to false .
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
method should call the
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue
method. This method sends a confirmation message to the user to allow additional
feedback to
indicate that the potentially dangerous operation should be
continued.
Attaching Dynamic Parameters to the Clear-
ItemProperty Cmdlet
The Clear-ItemProperty cmdlet might require additional parameters that are specified
dynamically
at runtime. To provide these dynamic parameters, the Windows PowerShell
property provider must
implement the
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearpropertydynam
icparameters*
method. This method returns an object that has properties and fields with
parsing attributes similar
to a cmdlet class or a
System.Management.Automation.Runtimedefinedparameterdictionary
object. The null
value can be returned if no dynamic parameters are to be added.
See Also
Windows PowerShell provider
Windows PowerShell provides a Make-Shell tool, also referred to as the "make-kit", that is
used to create a console shell that is not extensible. Shells created with this new tool cannot
be extended later through a Windows PowerShell snap-in.
Syntax
Here is the syntax used to run Make-Shell from within a make-file.
make-shell
-out n.exe
-namespace ns
[ -lib libdirectory1[,libdirectory2,..] ]
[ -reference ca1.dll[,ca2.dll,...] ]
[ -formatdata fd1.format.ps1xml[,fd2.format.ps1xml,...] ]
[ -typedata td1.type.ps1xml[,td2.type.ps1xml,...] ]
[ -authorizationmanager authorizationManagerType ]
[ -win32icon i.ico ]
[ -initscript p.ps1 ]
[ -builtinscript s1.ps1[,s2.ps1,...] ]
[ -resource resourcefile.txt ]
[ -cscflags cscFlags ]
[ -? | -help ]
Parameters
Here is a brief description of the parameters of Make-Shell.
U Caution
Parameter Description
Parameter Description
-out n.exe Required. The name of the shell to produce. The path is specified as
part of this parameter.
-lib libdirectory1[,libdirectory2,..] The directories that are searched for .NET assemblies, including the
Windows PowerShell assemblies, assemblies specified by the
reference parameter, assemblies indirectly referenced by another
assembly, and the .NET system assemblies.
The assemblies can be specified using their full path, otherwise they
will be searched for using the path specified by the lib parameter.
-source c1.cs [,c2.cs,...] The name of a file, provided by the shell developer, that contains
any source code needed to build the shell.
The source code file can contain any of the following source code:
-win32icon i.ico The icon for the .exe file for the shell. If not specified, then the shell
will have the icon that the c# compiler includes (if any).
-initscript p.ps1 The startup profile for the shell. The file is included "as-is"; no
validity checking is done by Make-Shell.
-builtinscript s1.ps1[,s2.ps1,...] A list of built-in scripts for the shell. These scripts are discovered
before scripts in the path, and their contents cannot be changed
once the shell is built.
-resource resourcefile.txt The .txt file containing help and banner resources for the shell. The
first resource is named ShellHelp, and contains the text displayed if
the shell is invoked with the help parameter. The second resource
is named ShellBanner, and it contains the text and copyright
information displayed when the shell is launched in interactive
mode.
-cscflags cscFlags Flags that should be passed to the C# compiler (csc.exe). These are
passed through unchanged. If this parameter includes spaces, it
should be surrounded in double-quotes.
-?
Displays the copyright message and Make-Shell command line
options.
-help
See Also
Windows PowerShell Programmer's Guide
This section contains conceptual information that will help you understand PowerShell
from a
developer's viewpoint.
Extending Output Objects How to extend PowerShell objects. For more information, see
About Types.ps1xml
Requesting Confirmation from How cmdlets and providers request feedback from the user
Cmdlets before an action is taken.
Windows PowerShell Provider Overview about PowerShell providers that are used to access
Overview data stores.
See also
PowerShell Class
Windows PowerShell® samples are available through the Windows SDK. This section
contains the sample
code that is contained in the Windows SDK samples.
7 Note
When the Windows SDK is installed, a Samples directory is created in which all the
Windows
PowerShell samples are made available. A typical installation directory is
C:\Program
Files\Microsoft SDKs\Windows\v6.0. Start Windows PowerShell and
type "cd
Samples\SysMgmt\PowerShell" to locate the Windows PowerShell
Samples directory. In this
document, the Windows PowerShell Samples directory is
referred to as <PowerShell Samples>.
GetProc01 Code Samples This is the basic Get-Process cmdlet sample described in Creating
Your First Cmdlet.
GetProc02 Code Samples This is the Get-Process cmdlet sample described in Adding
Parameters that Process Command-Line Input.
Sample Code Description
GetProc03 Code Samples This is the Get-Process cmdlet sample described in Adding
Parameters that Process Pipeline Input.
GetProc04 Code Samples This is the Get-Process cmdlet sample described in Adding
Nonterminating Error Reporting to Your Cmdlet.
GetProc05 Code Samples This Get-Process cmdlet is similar to the cmdlet described in
Adding Nonterminating Error Reporting to Your Cmdlet.
StopProc01 Code Samples This is the Stop-Process cmdlet sample described in Creating a
Cmdlet That Modifies the System.
Runspace01 Code Samples These are the code samples for the runspace described in Creating
a Console Application That Runs a Specified Command.
RunSpace03 Code Samples These are the code samples for the runspace described in "Creating
a Console Application That Runs a Specified Script".
RunSpace04 Code Samples This is a code sample for a runspace that uses the
System.Management.Automation.Runspaceinvoke class to execute
a script that generates a terminating error.
RunSpace10 Code Sample This is the source code for the Runspace10 sample, which adds a
cmdlet to
System.Management.Automation.Runspaces.Runspaceconfiguration
and then uses the modified configuration information to create the
runspace.
See Also
Windows PowerShell Programmer's Guide
Windows PowerShell SDK
AccessDbProviderSample01 Code
Sample
Article • 09/17/2021
The following code shows the implementation of the Windows PowerShell provider
described in
Creating a Basic Windows PowerShell Provider.
This implementation
provides methods for starting and stopping the provider, and although it does
not
provide a means to access a data store or to get or set the data in the data store, it does
provide the basic functionality that is required by all providers.
7 Note
Code Sample
C#
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
#endregion AccessDBProvider
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of the Windows PowerShell provider
described in
Creating a Windows PowerShell Drive Provider.
This implementation
creates a path, makes a connection to an Access database, and then removes the
drive.
7 Note
Code Sample
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
} // AccessDBProvider
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of the Windows PowerShell provider
described in
Creating a Windows PowerShell Item Provider.
This provider that can
manipulate the data in a data store.
7 Note
Code Sample
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Collections.ObjectModel;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Chunks the path and returns the table name and the row number
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
/// <returns>Table information.</returns>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
return null;
try
if (connection.State != ConnectionState.Open)
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
// data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // SafeConvertRowNumber
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of the Windows PowerShell provider
described in
Creating a Windows PowerShell Container Provider.
This provider works on
multi-layer data stores. For this type of data store, the top level of the
store contains the
root items and each subsequent level is referred to as a node of child items. By
allowing
the user to work on these child nodes, a user can interact hierarchically through the data
store.
Code Sample
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
/// <remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// </param>
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
/// <summary>
/// </summary>
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (PathIsDrive(path))
return true;
} // HasChildItems
/// <summary>
/// </summary>
///
/// </param>
///
/// Type for the object to create. "Table" for creating a new table
and
/// </param>
///
/// Object for creating new instance of a type at the specified path.
For
/// a "Row" the object must be of type string which will contain
comma
/// </param>
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// is specified, then a row can be created under it. For the sake
of
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
if (!TableNameIsValid(newTableName))
return;
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
} // NewItem
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// </param>
///
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
if (!Force && GetTable(copyTableName) != null)
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
/// <summary>
/// </summary>
///
/// </param>
///
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
} // RemoveItem
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Chunks the path and returns the table name and the row number
/// </summary>
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
return;
try
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
cmd.ExecuteScalar();
ErrorCategory.InvalidOperation, null)
);
} // RemoveTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
return null;
try
// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";
// columnds
da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;
sql += ")";
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;
if (connection.State != ConnectionState.Open)
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // SafeConvertRowNumber
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
/// <summary>
/// </summary>
int big = 0;
int id = 0;
object o = row["ID"];
if (o.GetType().Name.Equals("Int16"))
id = (int)(short)o;
else
id = (int)o;
big = id;
big++;
return big;
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
See Also
Windows PowerShell SDK
AccessDbProviderSample05 Code
Sample
Article • 09/17/2021
The following code shows the implementation of the Windows PowerShell navigation
provider described
in
Creating a Windows PowerShell Navigation Provider.
This provider
supports recursive commands, nested containers, and relative paths that allow it to
navigate the data store.
Code Sample
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
path = NormalizePath(path);
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// </param>
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
/// <summary>
/// </summary>
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (PathIsDrive(path))
return true;
} // HasChildItems
/// <summary>
/// </summary>
///
/// </param>
///
/// Type for the object to create. "Table" for creating a new table
and
/// </param>
///
/// Object for creating new instance of a type at the specified path.
For
/// a "Row" the object must be of type string which will contain
comma
/// </param>
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// is specified, then a row can be created under it. For the sake
of
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
} // NewItem
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// </param>
///
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
if (!Force && GetTable(copyTableName) != null)
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
/// <summary>
/// </summary>
///
/// </param>
///
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
} // RemoveItem
#region Navigation
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
return true;
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
} // IsItemContainer
/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// </param>
///
/// <returns>
/// </returns>
if (PathIsDrive(path))
return path;
string tableName;
int rowNumber;
if (type == PathType.Table)
return tableName;
return rowNumber.ToString(CultureInfo.CurrentCulture);
else
ThrowTerminatingInvalidPathException(path);
return null;
/// <summary>
/// Removes the child segment of the path and returns the remaining
/// </summary>
///
/// </param>
///
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// </param>
///
/// <returns></returns>
if (!String.IsNullOrEmpty(root))
if (!path.Contains(root))
return null;
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// </returns>
string result;
normalParent = RemoveDriveFromPath(normalParent);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
result = String.Empty;
result = normalChild;
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result = normalParent;
else
} // else if (!String...
else
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
else
result = normalParent;
if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result += normalChild.Substring(1);
else
result += normalChild;
} // else
return result;
} // MakePath
/// <summary>
/// Normalizes the path that was passed in and returns the normalized
/// </summary>
///
///
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>
string basepath)
normalPath = RemoveDriveFromPath(normalPath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
return normalPath;
else
if (!normalPath.Contains(normalBasePath))
return null;
return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
/// <summary>
/// Moves the item specified by the path to the specified destination
/// </summary>
///
/// </param>
///
/// </param>
out destRowNumber);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (destType == PathType.Invalid)
ThrowTerminatingInvalidPathException(destination);
if (type == PathType.Table)
ErrorCategory.InvalidArgument, path));
throw e;
else
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (dda == null)
return;
if (destType == PathType.Table)
destRow.ItemArray = row.ItemArray;
else
destRow.ItemArray = row.ItemArray;
if (ShouldProcess(path, "MoveItem"))
dda.Update(dds, destTableName);
#endregion Navigation
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
string root;
if (this.PSDriveInfo == null)
root = String.Empty;
else
root = this.PSDriveInfo.Root;
if (result == null)
result = String.Empty;
if (result.Contains(root))
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
return result;
/// <summary>
/// Chunks the path and returns the table name and the row number
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
/// <returns>Table information.</returns>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
return;
try
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
cmd.ExecuteScalar();
ErrorCategory.InvalidOperation, null)
);
} // RemoveTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
return null;
try
// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";
// columnds
da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;
sql += ")";
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;
if (connection.State != ConnectionState.Open)
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
// data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // SafeConvertRowNumber
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
/// <summary>
/// </summary>
int big = 0;
int id = (int)row["ID"];
big = id;
big++;
return big;
} // AccessDBProvider
#endregion AccessDBProvider
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
See Also
Windows PowerShell SDK
AccessDbProviderSample06 Code
Sample
Article • 09/17/2021
The following code shows the implementation of the Windows PowerShell content
provider described in
Creating a Windows PowerShell Content Provider.
This provider
enables the user to manipulate the contents of the items in a data store.
7 Note
Code Sample
C#
using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Globalization;
namespace Microsoft.Samples.PowerShell.Providers
#region AccessDBProvider
/// <summary>
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
/// <summary>
/// </summary>
/// </param>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);
return null;
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);
return null;
builder.Add("DBQ", drive.Root);
conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// </summary>
if (drive == null)
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);
return null;
if (accessDBPSDriveInfo == null)
return null;
accessDBPSDriveInfo.Connection.Close();
return accessDBPSDriveInfo;
} // RemoveDrive
/// <summary>
/// </summary>
if (PathIsDrive(path))
return;
}// if (PathIsDrive...
// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
if (type == PathType.Table)
else
ThrowTerminatingInvalidPathException(path);
} // GetItem
/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;
if (type != PathType.Row)
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
} // if (rowNum...
row[i] = colValues[i];
if (ShouldProcess(path, "SetItem"))
da.Update(ds, tableName);
} // SetItem
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (table != null)
return true;
// exist for the table and then specified row number must be
within
return true;
return false;
} // ItemExists
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(path))
result = false;
if (pathChunk.Length == 0)
result = false;
return result;
} // IsValidPath
/// <summary>
/// </summary>
/// </param>
// returned
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
false);
} // foreach (DatabaseRowInfo...
false);
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildItems
/// <summary>
/// </summary>
ReturnContainers returnContainers)
if (PathIsDrive(path))
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
// Get type, table name and row number from path specified
string tableName;
int rowNumber;
if (type == PathType.Table)
// Get all the rows in the table and then write out the
// row numbers.
} // foreach (DatabaseRowInfo...
else
ThrowTerminatingInvalidPathException(path);
} // else
} // GetChildNames
/// <summary>
/// </summary>
/// <returns>
/// </returns>
if (PathIsDrive(path))
return true;
} // HasChildItems
/// <summary>
/// </summary>
///
/// </param>
///
/// Type for the object to create. "Table" for creating a new table
and
/// </param>
///
/// a "Row" the object must be of type string which will contain
comma
/// </param>
object newItemValue)
string tableName;
int rowNumber;
if (pt == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
WriteError(new ErrorRecord
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
);
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
if (PathIsDrive(path))
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
try
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
if (ShouldProcess(newTableName, "create"))
{
cmd.ExecuteScalar();
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
} // if (String...
throw new
}// if (PathIsDrive...
else
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
if (rowNumber < 0)
throw new
else
throw new
} //if (String.Equals....
if (String.IsNullOrEmpty(value))
throw new
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (rowValues.Length != table.Columns.Count)
string message =
String.Format(CultureInfo.CurrentCulture,
table.Columns.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
rowNumber,
table.Rows.Count);
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
// Create a new row and update the row with the input
row[i] = rowValues[i];
table.Rows.Add(row);
da.Update(ds, tableName);
} // NewItem
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// </param>
///
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(copyPath);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (cda == null)
return;
if (type == PathType.Table)
if (copyType != PathType.Table)
ErrorCategory.InvalidArgument, copyPath));
throw e;
// to force a copy
copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
} // if (type == ...
else
if (copyType == PathType.Row)
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
else
string message =
String.Format(CultureInfo.CurrentCulture,
table.Rows.Count);
else
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
if (ShouldProcess(copyTableName, "CopyItems"))
cda.Update(cds, copyTableName);
} //CopyItem
/// <summary>
/// </summary>
///
/// </param>
///
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
string tableName;
int rowNumber = 0;
if (type == PathType.Table)
if (recurse)
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
RemoveTable(tableName);
}//if (recurse...
else
if (ShouldProcess(path, "RemoveItem"))
RemoveTable(tableName);
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[rowNumber].Delete();
if (ShouldProcess(path, "RemoveItem"))
da.Update(ds, tableName);
else
ThrowTerminatingInvalidPathException(path);
} // RemoveItem
#region Navigation
/// <summary>
/// </summary>
if (PathIsDrive(path))
return true;
string tableName;
int rowNumber;
if (type == PathType.Table)
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
return true;
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
} // IsItemContainer
/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// </param>
///
/// <returns>
/// </returns>
if (PathIsDrive(path))
return path;
string tableName;
int rowNumber;
if (type == PathType.Table)
return tableName;
return rowNumber.ToString(CultureInfo.CurrentCulture);
else
ThrowTerminatingInvalidPathException(path);
return null;
/// <summary>
/// Removes the child segment of the path and returns the remaining
/// </summary>
///
/// </param>
///
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// </param>
///
/// <returns></returns>
if (!String.IsNullOrEmpty(root))
if (!path.Contains(root))
return null;
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// </returns>
string result;
normalParent = RemoveDriveFromPath(normalParent);
normalChild = RemoveDriveFromPath(normalChild);
if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
result = String.Empty;
result = normalChild;
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result = normalParent;
else
} // else if (!String...
else
if (!normalParent.Equals(String.Empty,
StringComparison.OrdinalIgnoreCase) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
else
result = normalParent;
if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
result += normalChild.Substring(1);
else
result += normalChild;
} // else
return result;
} // MakePath
/// <summary>
/// Normalizes the path that was passed in and returns the
normalized
/// </summary>
///
/// </param>
///
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>
string
basepath)
normalPath = RemoveDriveFromPath(normalPath);
normalBasePath = RemoveDriveFromPath(normalBasePath);
if (String.IsNullOrEmpty(normalBasePath))
return normalPath;
else
if (!normalPath.Contains(normalBasePath))
return null;
return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
/// <summary>
/// </summary>
///
/// </param>
///
/// </param>
out destRowNumber);
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
if (destType == PathType.Invalid)
ThrowTerminatingInvalidPathException(destination);
if (type == PathType.Table)
ErrorCategory.InvalidArgument, path));
throw e;
else
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
if (dda == null)
return;
if (destType == PathType.Table)
destRow.ItemArray = row.ItemArray;
else
destRow.ItemArray = row.ItemArray;
if (ShouldProcess(path, "MoveItem"))
dda.Update(dds, destTableName);
#endregion Navigation
/// <summary>
/// </summary>
/// <returns>
/// </returns>
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))
return true;
else
return false;
} // PathIsDrive
/// <summary>
/// </summary>
// Return the path with the drive name and first path
// separator character removed, split by the path separator.
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// </summary>
/// <returns></returns>
if (!String.IsNullOrEmpty(path))
return result;
} // NormalizePath
/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
string root;
if (this.PSDriveInfo == null)
root = String.Empty;
else
root = this.PSDriveInfo.Root;
if (result == null)
result = String.Empty;
if (result.Contains(root))
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
return result;
/// <summary>
/// Chunks the path and returns the table name and the row number
/// </summary>
/// path</param>
rowNumber = -1;
tableName = null;
if (PathIsDrive(path))
return PathType.Database;
switch (pathChunks.Length)
case 1:
{
if (TableNameIsValid(name))
tableName = name;
retVal = PathType.Table;
break;
case 2:
{
if (TableNameIsValid(name))
tableName = name;
if (number >= 0)
rowNumber = number;
retVal = PathType.Row;
else
WriteError(new ErrorRecord(
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
break;
default:
WriteError(new ErrorRecord(
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
break;
} // switch(pathChunks...
return retVal;
} // GetNamesFromPath
/// <summary>
/// </summary>
message.Append(path);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return null;
DataTable dt = connection.GetSchema("Tables");
int count;
try
count = (Int32)command.ExecuteScalar();
catch
count = 0;
DatabaseTableInfo table =
results.Add(table);
} // foreach (DataRow...
return results;
} // GetTables
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();
try
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return null;
int i = 0;
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return results;
} // GetRows
/// <summary>
/// </summary>
/// data.</param>
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
return table;
return null;
} // GetTable
/// <summary>
/// </summary>
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
return;
try
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
return;
cmd.ExecuteScalar();
ErrorCategory.InvalidOperation, null)
);
} // RemoveTable
/// <summary>
/// </summary>
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
return null;
try
// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";
// columnds
ds.Locale = CultureInfo.InvariantCulture;
da.FillSchema(ds, SchemaType.Source);
sql += ")";
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;
connection.Open();
catch (Exception e)
ErrorCategory.InvalidOperation, tableName));
return da;
} // GetAdapterForTable
/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// </summary>
Debug.Assert(adapter != null);
// data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;
return ds;
} //GetDataSetForTable
/// <summary>
/// </summary>
/// schema</param>
///
Debug.Assert(ds != null);
Debug.Assert(tableName != null);
table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable
/// <summary>
/// </summary>
Collection<DatabaseRowInfo> di = GetRows(tableName);
return di[row];
else
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
return null;
} // GetRow
/// <summary>
/// </summary>
/// number</param>
try
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
ErrorCategory.InvalidData, rowNumberAsStr));
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
return rowNumber;
} // 1
/// <summary>
/// </summary>
if (exp.IsMatch(tableName))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid
/// <summary>
/// database
/// </summary>
if (di == null)
return false;
DataTable dt = connection.GetSchema("Tables");
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
return true;
WriteError(new ErrorRecord(
ErrorCategory.InvalidArgument, tableName));
return false;
}// TableIsPresent
/// <summary>
/// </summary>
int big = 0;
int id = (int)row["ID"];
big = id;
big++;
return big;
/// <summary>
/// </summary>
string tableName;
int rowNumber;
if (type != PathType.Table)
WriteError(new ErrorRecord(
"NotValidRow", ErrorCategory.InvalidArgument,
path));
return;
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
return;
table.Rows[i].Delete();
if (ShouldProcess(path, "ClearContent"))
da.Update(ds, tableName);
} // ClearContent
/// <summary>
/// </summary>
/// <returns></returns>
return null;
/// <summary>
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
} // GetContentReader
/// <summary>
/// </summary>
/// <returns></returns>
return null;
/// <summary>
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
ThrowTerminatingInvalidPathException(path);
/// <summary>
/// </summary>
/// <returns></returns>
return null;
} // AccessDBProvider
#endregion AccessDBProvider
/// <summary>
/// </summary>
/// <summary>
/// </summary>
Database,
/// <summary>
/// </summary>
Table,
/// <summary>
/// </summary>
Row,
/// <summary>
/// </summary>
Invalid
};
#region AccessDBPSDriveInfo
/// <summary>
/// Any state associated with the drive should be held here.
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo
#region DatabaseTableInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return name;
set
name = value;
/// <summary>
/// </summary>
get
return rowCount;
set
rowCount = value;
/// <summary>
/// </summary>
get
return columns;
set
columns = value;
/// <summary>
/// Constructor.
/// </summary>
DataColumnCollection columns)
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo
#endregion DatabaseTableInfo
#region DatabaseRowInfo
/// <summary>
/// </summary>
/// <summary>
/// </summary>
get
return data;
set
data = value;
/// <summary>
/// </summary>
get
return rowNumber;
set
rowNumber = value;
/// <summary>
/// Constructor.
/// </summary>
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo
#endregion DatabaseRowInfo
#region AccessDBContentReader
/// <summary>
/// </summary>
this.path = path;
this.provider = provider;
/// <summary>
/// </summary>
/// return.</param>
// offset
string tableName;
int rowNumber;
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
return null;
int rowsRead = 0;
results.Add(rows[(int)currentOffset].Data);
rowsRead++;
currentOffset++;
return results;
} // Read
/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
if (type == PathType.Table)
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
throw new
ArgumentException(
);
if (origin == System.IO.SeekOrigin.Begin)
currentOffset = offset - 1;
else
currentOffset += offset;
} // if (type...
else
currentOffset = 0;
} // Seek
/// <summary>
/// </summary>
Dispose();
} // Close
/// <summary>
/// </summary>
Seek(0, System.IO.SeekOrigin.Begin);
GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentReader
#endregion AccessDBContentReader
#region AccessDBContentWriter
/// <summary>
/// </summary>
this.path = path;
this.provider = provider;
/// <summary>
/// </summary>
/// </param>
///
if (content == null)
return null;
// the end
string tableName;
int rowNumber;
if (type == PathType.Table)
OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
if (da == null)
return null;
if (!String.IsNullOrEmpty(colValues[i]))
row[i] = colValues[i];
//table.Rows.InsertAt(row, rowNumber);
table.Rows.Add(row);
da.Update(ds, tableName);
else
return null;
} // Write
/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
string tableName;
int rowNumber;
if (type == PathType.Invalid)
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
throw new
ArgumentException(
);
if (origin == System.IO.SeekOrigin.Begin)
currentOffset = offset - 1;
else
currentOffset += offset;
} // Seek
/// <summary>
/// </summary>
Dispose();
} // Close
/// <summary>
/// </summary>
Seek(0, System.IO.SeekOrigin.Begin);
GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentWriter
#endregion AccessDBContentWriter
} // namespace Microsoft.Samples.PowerShell.Providers
See Also
Windows PowerShell Programmer's Guide
Here are the code samples for the GetProc01 sample cmdlet. This is the basic Get-
Process cmdlet sample described in Creating Your First Cmdlet. A Get-Process cmdlet is
designed to retrieve information about all the processes running on the local computer.
Language Topic
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of the GetProc01 sample cmdlet. Notice
that the cmdlet
is simplified by leaving the actual work of process retrieval to the
System.Diagnostics.Process.Getprocesses*
method.
7 Note
You can download the C# source file (getproc01.cs) for this Get-Proc cmdlet using
the Microsoft
Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For
download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
C#
using System;
using System.Diagnostics;
using System.ComponentModel;
// installutil GetProcessSample01.dll
// Then run:
// Add-PSSnapin GetProcessSnapIn01
// get-proc
namespace Microsoft.Samples.PowerShell.Commands
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
/// <summary>
/// </summary>
WriteObject(processes, true);
#endregion Overrides
} //GetProcCommand
#endregion GetProcCommand
/// <summary>
/// </summary>
[RunInstaller(true)]
/// <summary>
/// </summary>
public GetProcPSSnapIn01()
: base()
/// <summary>
/// Get a name for this PowerShell snap-in. This name will be used in
registering
/// </summary>
get
return "GetProcPSSnapIn01";
/// <summary>
/// </summary>
get
return "Microsoft";
/// <summary>
/// resourceBaseName,resourceName.
/// </summary>
get
return "GetProcPSSnapIn01,Microsoft";
/// <summary>
/// </summary>
get
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of the GetProc01 sample cmdlet. Notice
that the cmdlet is simplified by leaving the actual work of process retrieval to the
System.Diagnostics.Process.Getprocesses* method.
7 Note
You can download the C# source file (getproc01.cs) for this Get-Proc cmdlet using
the Microsoft Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
See Also
Windows PowerShell Programmer's Guide
Here are the code samples for the GetProc02 sample cmdlet. This is the Get-Process
cmdlet sample described in Adding Parameters that Process Command-Line Input. This
Get-Process cmdlet retrieves processes based on their name, and then displays
information about the processes at the command line.
7 Note
You can download the C# source file (getproc02.cs) for this Get-Proc cmdlet using
the Microsoft Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of a Get-Process cmdlet that accepts
command-line
input. Notice that this implementation defines a Name parameter to allow
command-line input, and
it uses the
WriteObject(System.Object,System.Boolean)
method as the output mechanism for sending output objects to the pipeline.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Diagnostics;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
} // if (processNames...
} // ProcessRecord
#endregion GetProcCommand
See Also
Windows PowerShell SDK
GetProc02 (VB.NET) Sample Code
Article • 09/17/2021
The following code shows the implementation of a Get-Process cmdlet that accepts
command-line
input. Notice that this implementation defines a Name parameter to allow
command-line input, and
it uses the
WriteObject(System.Object,System.Boolean)
method as the output mechanism for sending output objects to the pipeline.
Code Sample
See Also
Windows PowerShell SDK
GetProc03 Code Samples
Article • 09/17/2021
Here are the code samples for the GetProc03 sample cmdlet. This is the Get-Process
cmdlet sample described in Adding Parameters that Process Pipeline Input. This Get-
Process cmdlet uses a Name parameter that accepts input from a pipeline object,
retrieves process information from the local computer based on the supplied names,
and then displays information about the processes at the command line.
7 Note
You can download the C# source file (getprov03.cs) for this Get-Proc cmdlet using
the Microsoft Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of a Get-Process cmdlet that can accept
pipelined
input. This implementation defines a Name parameter that accepts pipeline
input, retrieves process
information from the local computer based on the supplied
names, and then uses the
WriteObject(System.Object,System.Boolean)
method as the
output mechanism for sending objects to the pipeline.
7 Note
You can download the C# source file (getprov03.cs) for this Get-Proc cmdlet using
the Microsoft
Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For
download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Diagnostics;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
WriteObject(Process.GetProcessesByName(name), true);
} // if (processNames ...
} // ProcessRecord
#endregion Overrides
#endregion GetProcCommand
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of a Get-Process cmdlet that can accept
pipelined
input. This implementation defines a Name parameter that accepts pipeline
input, retrieves process
information from the local computer based on the supplied
names, and then uses the
WriteObject(System.Object,System.Boolean)
method as the
output mechanism for sending objects to the pipeline.
Code Sample
GetProc04 Code Samples
Article • 09/17/2021
Here are the code samples for the GetProc04 sample cmdlet. This is the Get-Process
cmdlet sample described in Adding Nonterminating Error Reporting to Your Cmdlet.
This Get-Process cmdlet calls the System.Management.Automation.Cmdlet.WriteError
method whenever an invalid operation exception is thrown while retrieving process
information.
7 Note
You can download the C# source file (getprov04.cs) for this Get-Proc cmdlet using
the Microsoft Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of a Get-Process cmdlet that reports
nonterminating
errors. This implementation calls the
System.Management.Automation.Cmdlet.WriteError
method to report nonterminating
errors.
7 Note
You can download the C# source file (getprov04.cs) for this Get-Proc cmdlet using
the Microsoft
Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For
download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Diagnostics;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
#region Parameters
/// <summary>
/// </summary>
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
#endregion Parameters
/// <summary>
/// </summary>
// processes.
if (this.processNames == null)
WriteObject(Process.GetProcesses(), true);
else
// error stream.
Process[] processes;
try
processes = Process.GetProcessesByName(name);
WriteError(new ErrorRecord(
ex,
"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation,
name));
continue;
WriteObject(processes, true);
} // else
} // ProcessRecord
#endregion Overrides
#endregion GetProcCommand
See Also
Windows PowerShell Programmer's Guide
The following code shows the implementation of a Get-Process cmdlet that reports
nonterminating errors. This implementation calls the
System.Management.Automation.Cmdlet.WriteError method to report nonterminating
errors.
7 Note
You can download the C# source file (getprov04.cs) for this Get-Proc cmdlet using
the Microsoft Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
See Also
Windows PowerShell Programmer's Guide
Here are the code samples for the GetProc05 sample cmdlet. This Get-Process cmdlet is
similar to the cmdlet described in Adding Nonterminating Error Reporting to Your
Cmdlet.
Language Topic
See Also
Windows PowerShell SDK
GetProc05 (C#) Sample Code
Article • 09/17/2021
C#
namespace Microsoft.Samples.PowerShell.Commands
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Permissions;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc",
DefaultParameterSetName = "ProcessName")]
#region Fields
/// <summary>
/// </summary>
/// <summary>
/// </summary>
/// <summary>
/// </summary>
#endregion Fields
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
/// <summary>
/// </summary>
[Parameter(
ParameterSetName = "Id",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
public int[] Id
/// <summary>
/// stream of [collection of] Process objects, the cmdlet bypasses the
/// directly. This allows the cmdlet to deal with processes that have
/// </summary>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
#endregion Parameters
/// <summary>
/// </summary>
List<Process> matchingProcesses;
switch (ParameterSetName)
case "Id":
matchingProcesses = this.GetMatchingProcessesById();
break;
case "ProcessName":
matchingProcesses = this.GetMatchingProcessesByName();
break;
case "InputObject":
matchingProcesses = this.GetProcessesByInput();
break;
default:
ThrowTerminatingError(
new ErrorRecord(
"UnableToAccessProcessList",
ErrorCategory.InvalidOperation,
null));
return;
} // switch (ParameterSetName)
matchingProcesses.Sort(ProcessComparison);
WriteObject(process);
}
} // ProcessRecord
#endregion Overrides
/// <summary>
/// specified process name which is not found even though the name
/// </summary>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();
List<Process> allProcesses =
new List<Process>(Process.GetProcesses());
if (null == this.processNames)
matchingProcesses.AddRange(allProcesses);
else
+ pattern + "\".");
WildcardPattern wildcard =
new WildcardPattern(
pattern,
WildcardOptions.IgnoreCase);
if (!keys.ContainsKey(process.Id))
if (processName.Length == 0)
allProcesses.Remove(process);
// pattern specified.
if (!wildcard.IsMatch(processName))
continue;
+ process.Id + ".");
// A match is found.
found = true;
keys.Add(process.Id, 0);
} // foreach (Process...
if (!found &&
!WildcardPattern.ContainsWildcardCharacters(pattern))
WriteError(new ErrorRecord(
"ProcessNameNotFound",
ErrorCategory.ObjectNotFound,
pattern));
} // foreach (string...
} // if (null...
return matchingProcesses;
} // GetMatchingProcessesByName
/// <summary>
/// </summary>
/// returned.</param>
[EnvironmentPermissionAttribute(
new EnvironmentPermission(PermissionState.Unrestricted).Assert();
if (process != null)
try
return process.ProcessName;
catch (Win32Exception)
catch (InvalidOperationException)
return name;
} // SafeGetProcessName
/// <summary>
/// </summary>
/// </returns>
SafeGetProcessName(x),
SafeGetProcessName(y),
StringComparison.CurrentCultureIgnoreCase);
if (0 != diff)
{
return diff;
else
return x.Id.CompareTo(y.Id);
/// <summary>
/// </summary>
/// <returns>
/// </returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();
if (null != this.processIds)
+ processId + ".");
if (!keys.ContainsKey(processId))
Process process;
try
process = Process.GetProcessById(processId);
WriteError(new ErrorRecord(
ex,
"ProcessIdNotFound",
ErrorCategory.ObjectNotFound,
processId));
continue;
matchingProcesses.Add(process);
keys.Add(processId, 0);
return matchingProcesses;
} // GetMatchingProcessesById
/// <summary>
/// parameter.
/// </summary>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();
if (null != this.Input)
if (!keys.ContainsKey(process.Id))
try
process.Refresh();
catch (Win32Exception)
catch (InvalidOperationException)
matchingProcesses.Add(process);
return matchingProcesses;
} // GetProcessesByInput
#endregion GetProcCommand
See Also
Windows PowerShell SDK
GetProc05 (VB.NET) Sample Code
Article • 09/17/2021
Here is the complete VB.NET code for the GetProc05 sample cmdlet.
VB
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.Security.Permissions
Imports System.Management.Automation
Imports System.ComponentModel
Namespace Microsoft.Samples.PowerShell.Commands
#Region "GetProcCommand"
''' <summary>
''' </summary>
<Cmdlet(VerbsCommon.Get, "Proc", _
DefaultParameterSetName:="ProcessName")> _
Inherits PSCmdlet
#Region "Parameters"
''' <summary>
''' The list of process names on which this cmdlet will work
''' </summary>
<Parameter(Position:=0, ParameterSetName:="ProcessName", _
ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True), _
ValidateNotNullOrEmpty()> _
Get
Return processNames
End Get
processNames = value
End Set
End Property
''' <summary>
''' </summary>
<Parameter(ParameterSetName:="Id", _
Mandatory:=True, ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True, _
Get
Return processIds
End Get
processIds = value
End Set
End Property
''' <summary>
''' </summary>
<Parameter(ParameterSetName:="InputObject", _
Mandatory:=True, ValueFromPipeline:=True)> _
Get
Return inputObjects
End Get
inputObjects = value
End Set
End Property
#End Region
''' <summary>
''' </summary>
Case "Id"
matchingProcesses = GetMatchingProcessesById()
Case "ProcessName"
matchingProcesses = GetMatchingProcessesByName()
Case "InputObject"
matchingProcesses = GetProcessesByInput()
Case Else
ThrowTerminatingError(New ErrorRecord( _
"UnableToAccessProcessList", _
ErrorCategory.InvalidOperation, Nothing))
Return
End Select
matchingProcesses.Sort(AddressOf ProcessComparison)
WriteObject(process)
Next process
#End Region
''' <summary>
''' parameter.
''' no wildcards.
''' </summary>
''' <returns></returns>
matchingProcesses.AddRange(allProcesses)
Else
WildcardOptions.IgnoreCase)
SafeGetProcessName(process)
If processName.Length = 0 Then
allProcesses.Remove(process)
End If
GoTo ContinueForEach2
End If
WriteDebug(String.Format( _
found = True
keys.Add(process.Id, 0)
matchingProcesses.Add(process)
End If
ContinueForEach2:
Then
WriteError(New ErrorRecord( _
ErrorCategory.ObjectNotFound, pattern))
End If
Next pattern
End If
Return matchingProcesses
''' <summary>
''' </summary>
''' returned.</param>
As String
Try
Return process.ProcessName
Catch e1 As Win32Exception
Catch e2 As InvalidOperationException
End Try
End If
Return name
#End Region
''' <summary>
''' </summary>
''' <returns>
''' </returns>
SafeGetProcessName(y),
StringComparison.CurrentCultureIgnoreCase)
Return diff
End If
''' <summary>
''' parameter.
''' </summary>
''' </returns>
Try
process = _
System.Diagnostics.Process.GetProcessById( _
processId)
Catch ex As ArgumentException
WriteError(New ErrorRecord(ex, _
"ProcessIdNotFound", _
ErrorCategory.ObjectNotFound, processId))
GoTo ContinueForEach1
End Try
matchingProcesses.Add(process)
keys.Add(processId, 0)
End If
ContinueForEach1:
Next processId
End If
Return matchingProcesses
''' <summary>
''' </summary>
Try
process.Refresh()
Catch e1 As Win32Exception
Catch e2 As InvalidOperationException
End Try
matchingProcesses.Add(process)
End If
Next process
End If
Return matchingProcesses
#End Region
#End Region
#End Region
''' <summary>
''' </summary>
<RunInstaller(True)> _
Inherits PSSnapIn
''' <summary>
''' </summary>
''' <summary>
''' Get a name for this PowerShell snap-in. This name will
''' </summary>
Get
Return "GetProcPSSnapIn05"
End Get
End Property
''' <summary>
''' </summary>
Get
Return "Microsoft"
End Get
End Property
''' <summary>
''' resourceBaseName,resourceName.
''' </summary>
Get
Return "GetProcPSSnapIn05,Microsoft"
End Get
End Property
''' <summary>
''' </summary>
Get
End Get
End Property
#End Region
End Namespace
See Also
Windows PowerShell SDK
StopProc01 Code Samples
Article • 09/17/2021
Here is the code sample for the StopProc01 sample cmdlet. This is the Stop-Process
cmdlet sample described in Creating a Cmdlet that Modifies the System. The Stop-
Process cmdlet is designed to stop processes that are retrieved using the Get-Proc
cmdlet (described in Creating Your First Cmdlet).
7 Note
You can download the C# (stopproc01.cs) source file for the Stop-Proc cmdlet using
the Microsoft Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
7 Note
You can download the C# (stopproc01.cs) source file for the Stop-Proc cmdlet using
the Microsoft
Windows Software Development Kit for Windows Vista and .NET
Framework 3.0 Runtime Components. For
download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
C#
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
// the user wants the cmdlet to return an object, and how to request
//
// To test this cmdlet, create a module folder that has the same name as
// following command:
// import-module stopprocesssample01
namespace Microsoft.Samples.PowerShell.Commands
#region StopProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
/// <summary>
/// the cmdlet to stop its operation. This parameter should always
/// </summary>
[Parameter]
/// <summary>
/// completed.
/// </summary>
[Parameter]
#endregion Parameters
/// <summary>
/// The ProcessRecord method does the following for each of the
/// </summary>
// processes.
// a process.
Process[] processes;
try
processes = Process.GetProcessesByName(name);
WriteError(new
ErrorRecord(ioe,"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation, name));
continue;
string processName;
try
{
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.ReadError,
process));
continue;
if
(!ShouldProcess(string.Format(CultureInfo.CurrentCulture,"{0} ({1})",
processName,
process.Id)))
continue;
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));
if (criticalProcess &&!force)
(CultureInfo.CurrentCulture,
processName);
if (!ShouldContinue(message, "Warning!",
continue;
} // if (criticalProcess...
try
{
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a nonterminating error.
WriteError(new ErrorRecord(e,
"CouldNotStopProcess",
ErrorCategory.CloseError,
process));
continue;
} // if ((e is...
else throw;
} // catch
if (passThru)
WriteObject(process);
} // foreach (Process...
} // foreach (string...
} // ProcessRecord
/// <summary>
/// </summary>
);
} // StopProcCommand
#endregion StopProcCommand
See Also
Windows PowerShell Programmer's Guide
Here are the code samples for the StopProc00 sample cmdlet. This is the Stop-Process
cmdlet sample described in Adding Parameter Sets to a Cmdlet. The Stop-Process
cmdlet is designed to stop processes that are retrieved using the Get-Proc cmdlet
(described in Creating Your First Cmdlet).
7 Note
The downloaded source files are available in the <PowerShell Samples> directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
Here is the complete C# sample code for the StopProc04 sample cmdlet. This is the
code for the
Stop-Process cmdlet described in
Adding Parameter Sets to a Cmdlet. The
Stop-Process cmdlet is designed to stop processes that are retrieved using the Get-Proc
cmdlet
(described in Creating Your First Cmdlet).
7 Note
You can download the C# (stopprocesssample04.cs) source file for this Stop-Proc
cmdlet using the
Microsoft Windows Software Development Kit for Windows Vista
and .NET Framework 3.0 Runtime
Components. For download instructions, see
How
to Install Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
C#
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization;
// This sample shows how to declare parameter sets, the input object, and
//
// To test this cmdlet, create a module folder that has the same name as
// following command:
// import-module stopprocesssample04
namespace Microsoft.Samples.PowerShell.Commands
#region StopProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName = "ProcessId",
SupportsShouldProcess = true)]
#region Parameters
/// <summary>
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
)]
[Alias("ProcessName")]
/// <summary>
/// the cmdlet to stop its operation. This parameter should always
/// </summary>
[Parameter]
/// <summary>
/// completed.
/// </summary>
[Parameter(
)]
[Parameter(
ParameterSetName = "ProcessId",
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ValueFromPipeline = true
)]
[Alias("ProcessId")]
public int[] Id
/// <summary>
/// </summary>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
#endregion Parameters
#region CmdletOverrides
/// <summary>
/// The ProcessRecord method does the following for each of the
/// </summary>
switch (ParameterSetName)
case "ProcessName":
ProcessByName();
break;
case "ProcessId":
ProcessById();
break;
case "InputObject":
SafeStopProcess(process);
break;
default:
} // switch (ParameterSetName...
} // ProcessRecord
/// <summary>
/// </summary>
/// </param>
WildcardOptions.Compiled;
try
processNameToMatch = process.ProcessName;
catch (Win32Exception e)
// checked again.
allProcesses.Remove(process);
string message =
String.Format(CultureInfo.CurrentCulture, "The
process \"{0}\" could not be found",
processName);
WriteVerbose(message);
ErrorCategory.ObjectNotFound,
processName));
continue;
if (!wildcard.IsMatch(processNameToMatch))
continue;
matchingProcesses.Add(process);
} // foreach(Process...
return matchingProcesses;
} // SafeGetProcessesByName
/// <summary>
/// </summary>
try
processName = process.ProcessName;
catch (Win32Exception e)
ErrorCategory.OpenError, processName));
return;
if (!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
return;
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));
message = String.Format(CultureInfo.CurrentCulture,
processName);
if (!ShouldContinue(message, "Warning!",
return;
} // if (criticalProcess...
// process.
if (criticalProcess)
message =
String.Format(CultureInfo.CurrentCulture,
processName);
WriteWarning(message);
} // if (criticalProcess...
try
process.Kill();
catch (Exception e)
(e is InvalidOperationException))
// a non-terminating error.
ErrorCategory.CloseError,
process)
);
return;
} // if ((e is...
else throw;
} // catch
message = String.Format(CultureInfo.CurrentCulture,
processName, process.Id);
WriteVerbose(message);
if (passThru)
message =
String.Format(CultureInfo.CurrentCulture,
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru..
} // SafeStopProcess
/// <summary>
/// </summary>
try
base.ThrowTerminatingError(new ErrorRecord(
ioe, "UnableToAccessProcessList",
ErrorCategory.InvalidOperation, null));
// retrieve a process.
// from the list so that its not compared the next time.
ArrayList processes =
// terminating error.
if (processes.Count == 0)
WriteError(new ErrorRecord(
"ProcessNotFound",
ErrorCategory.ObjectNotFound,
name));
} // if (processes...
else
SafeStopProcess(process);
} // foreach (Process...
} // else
} // foreach (string...
} // ProcessByName
/// <summary>
/// </summary>
try
process = Process.GetProcessById(processId);
string message =
String.Format(CultureInfo.CurrentCulture,
process.Id);
WriteDebug(message);
string
message = String.Format(CultureInfo.CurrentCulture,
processId);
WriteVerbose(message);
ErrorCategory.ObjectNotFound,
processId));
continue;
SafeStopProcess(process);
} // foreach (int...
} // ProcessById
/// <summary>
/// </summary>
);
} // StopProcCommand
#endregion StopProcCommand
See Also
Windows PowerShell Programmer's Guide
Here is the complete VB.NET sample code for the StopProc04 sample cmdlet. This is the
code for the Stop-Process cmdlet described in Adding Parameter Sets to a Cmdlet. The
Stop-Process cmdlet is designed to stop processes that are retrieved using the Get-Proc
7 Note
You can download the VB.NET (stopprocesssample04.vb) source file for this Stop-
Proc cmdlet using the Microsoft Windows Software Development Kit for Windows
Vista and .NET Framework 3.0 Runtime Components. For download instructions,
see How to Install Windows PowerShell and Download the Windows PowerShell
SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
VB
Imports System
Imports System.Diagnostics
Imports System.Collections
Imports System.Globalization
Namespace Microsoft.Samples.PowerShell.Commands
' This sample introduces parameter sets, the input object and
' DefaultParameterSet.
#Region "StopProcCommand"
''' <summary>
''' </summary>
<Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName:="ProcessId", _
SupportsShouldProcess:=True)> _
Inherits PSCmdlet
#Region "Parameters"
''' <summary>
''' The list of process names on which this cmdlet will work.
''' </summary>
<Parameter(Position:=0, ParameterSetName:="ProcessName", _
Mandatory:=True, _
ValueFromPipeline:=True, ValueFromPipelineByPropertyName:=True, _
Get
Return processNames
End Get
processNames = value
End Set
End Property
''' <summary>
''' </summary>
<Parameter()> _
Get
Return myForce
End Get
myForce = value
End Set
End Property
''' <summary>
''' object down the pipeline after the process has been stopped.
''' </summary>
<Parameter( _
HelpMessage:= _
"If set the process(es) will be passed to the pipeline " & _
Get
Return myPassThru
End Get
myPassThru = value
End Set
End Property
''' <summary>
''' The list of process IDs on which this cmdlet will work.
''' </summary>
<Parameter(ParameterSetName:="ProcessId", _
Mandatory:=True, _
ValueFromPipelineByPropertyName:=True, _
ValueFromPipeline:=True), [Alias]("ProcessId")> _
Get
Return processIds
End Get
processIds = value
End Set
End Property
''' <summary>
''' </summary>
<Parameter(ParameterSetName:="InputObject", _
Mandatory:=True, ValueFromPipeline:=True)> _
Get
Return myInputObject
End Get
myInputObject = value
End Set
End Property
#End Region
#Region "CmdletOverrides"
''' <summary>
''' </summary>
Case "ProcessName"
ProcessByName()
Case "ProcessId"
ProcessById()
Case "InputObject"
SafeStopProcess(process)
Next process
Case Else
End Select
#End Region
''' <summary>
''' </summary>
''' </param>
WildcardOptions.Compiled
Try
processNameToMatch = process.ProcessName
Catch e As Win32Exception
allProcesses.Remove(process)
String.Format(CultureInfo.CurrentCulture, _
WriteVerbose(message)
WriteError(New ErrorRecord(e, _
"ProcessNotFound", ErrorCategory.ObjectNotFound, _
processName))
GoTo ContinueForEach1
End Try
GoTo ContinueForEach1
End If
matchingProcesses.Add(process)
ContinueForEach1:
Next process
Return matchingProcesses
''' <summary>
''' </summary>
Try
processName = process.ProcessName
Catch e As Win32Exception
ErrorCategory.OpenError, processName))
Return
End Try
If Not ShouldProcess(String.Format(CultureInfo.CurrentCulture, _
Return
End If
criticalProcessNames.Contains( _
processName.ToLower(CultureInfo.CurrentCulture))
message = String.Format(CultureInfo.CurrentCulture, _
' Cmdlet.
Return
End If
End If
If criticalProcess Then
message = String.Format(CultureInfo.CurrentCulture, _
WriteWarning(message)
End If
Try
process.Kill()
Catch e As Exception
WriteError(New ErrorRecord(e, _
"CouldNotStopProcess", ErrorCategory.CloseError,
process))
Return
Else
Throw
End If
End Try
message = String.Format(CultureInfo.CurrentCulture, _
WriteVerbose(message)
If myPassThru Then
message = String.Format(CultureInfo.CurrentCulture, _
WriteDebug(message)
WriteObject(process)
End If
''' <summary>
''' </summary>
Try
MyBase.ThrowTerminatingError(New ErrorRecord(ioe, _
"UnableToAccessProcessList", _
ErrorCategory.InvalidOperation, Nothing))
End Try
' from the list so that its not compared the next time.
allProcesses)
If processes.Count = 0 Then
WriteError(New ErrorRecord( _
"ProcessNotFound", ErrorCategory.ObjectNotFound,
name))
Else
SafeStopProcess(process)
Next process
End If
Next name
''' <summary>
''' </summary>
Try
process =
System.Diagnostics.Process.GetProcessById(processId)
CultureInfo.CurrentCulture, _
WriteDebug(message)
Catch ae As ArgumentException
CultureInfo.CurrentCulture, _
WriteVerbose(message)
WriteError(New ErrorRecord(ae, _
"ProcessIdNotFound", _
ErrorCategory.ObjectNotFound, processId))
GoTo ContinueForEach1
End Try
SafeStopProcess(process)
ContinueForEach1:
Next processId
#End Region
''' <summary>
''' </summary>
#End Region
#End Region
''' <summary>
''' </summary>
<RunInstaller(True)> _
Inherits PSSnapIn
''' <summary>
''' </summary>
''' <summary>
''' Get a name for this PowerShell snap-in. This name will
''' </summary>
Get
Return "StopProcPSSnapIn04"
End Get
End Property
''' <summary>
''' </summary>
Get
Return "Microsoft"
End Get
End Property
''' <summary>
''' resourceBaseName,resourceName.
''' </summary>
Get
Return "StopProcPSSnapIn04,Microsoft"
End Get
End Property
''' <summary>
''' </summary>
Get
End Get
End Property
#End Region
End Namespace
See Also
Windows PowerShell Programmer's Guide
Here are the code samples for the runspace described in Creating a Console Application
That Runs a Specified Command. The command that is invoked in the runspace is the
Get-Process cmdlet.
Language Topic
See Also
Windows PowerShell Programmer's Guide
7 Note
You can download the C# source file (runspace01.cs) for this runspace using the
Microsoft Windows
Software Development Kit for Windows Vista and Microsoft
.NET Framework 3.0 Runtime Components.
For download instructions, see
How to
Install Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Management.Automation;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
System.Console.ReadKey();
See Also
Windows PowerShell Programmer's Guide
Here are the code samples for the runspace described in Creating a Console Application
That Runs a Specified Command. To do this, the application invokes a runspace, and
then invokes a command. (Note that this application does not specify runspace
configuration information, nor does it explicitly create a pipeline.) The command that is
invoked is the Get-Process cmdlet.
Code Sample
VB
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces
Namespace Microsoft.Samples.PowerShell.Runspaces
Module Runspace01
' <summary>
' <remarks>
' </remarks>
Sub Main()
Console.WriteLine("Process HandleCount")
Console.WriteLine("--------------------------------")
' Now invoke the runspace and display the objects that are
' returned...
Console.WriteLine("{0,-20} {1}", _
result.Members("ProcessName").Value, _
result.Members("HandleCount").Value)
Next
System.Console.ReadKey()
End Sub
End Module
End Namespace
See Also
Windows PowerShell SDK
Runspace02 Code Samples
Article • 09/17/2021
Here is the source code for the Runspace02 sample. This sample uses the
System.Management.Automation.Runspaceinvoke class to execute the Get-Process
cmdlet synchronously. Windows Forms and data binding are then used to display the
results in a DataGridView control.
Language Topic
See Also
Windows PowerShell SDK
Runspace02 (C#) Code Sample
Article • 09/17/2021
Here is the C# source code for the Runspace02 sample. This sample uses the
System.Management.Automation.Runspaceinvoke
class to execute the Get-Process
cmdlet synchronously. Windows Forms and data binding are then
used to display the
results in a DataGridView control
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Windows.Forms;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This method creates the form where the output is displayed.
/// </summary>
form.Controls.Add(grid);
grid.Dock = DockStyle.Fill;
powershell.AddCommand("get-process").AddCommand("sort-
object").AddArgument("ID");
if (Runspace.DefaultRunspace == null)
Runspace.DefaultRunspace = powershell.Runspace;
objects.AddRange(results);
grid.DataSource = objects;
form.ShowDialog();
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
Runspace02.CreateForm();
See Also
Windows PowerShell SDK
Runspace02 (VB.NET) Code Sample
Article • 09/17/2021
Here is the VB.NET source code for the Runspace02 sample. This sample uses the
System.Management.Automation.Runspaceinvoke class to execute the Get-Process
cmdlet synchronously. Windows Forms and data binding are then used to display the
results in a DataGridView control.
Code Sample
VB
Imports System
Imports System.Collections
Imports System.Collections.ObjectModel
Imports System.Windows.Forms
Imports System.Management.Automation.Runspaces
Imports System.Management.Automation
Namespace Microsoft.Samples.PowerShell.Runspaces
Class Runspace02
form.Controls.Add(grid)
grid.Dock = DockStyle.Fill
objects.AddRange(results)
grid.DataSource = objects
form.ShowDialog()
''' <summary>
''' </summary>
''' <remarks>
''' </remarks
Runspace02.CreateForm()
End Namespace
See Also
Windows PowerShell SDK
RunSpace03 Code Samples
Article • 09/17/2021
Here are the code samples for the runspace described in "Creating a Console
Application That Runs a Specified Script".
7 Note
You can download the C# source file (runspace03.cs) and the VB.NET source
file
(runspace03.vb) for this sample using the Microsoft Windows Software
Development Kit for Windows Vista and Microsoft .NET Framework 3.0 Runtime
Components. For download instructions, see
How to Install Windows PowerShell
and Download the Windows PowerShell SDK.
The downloaded source files are
available in the <PowerShell Samples>
directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
Here is the C# source code for the console application described in "Creating a
Console
Application That Runs a Specified Script". This sample uses the
System.Management.Automation.Runspaceinvoke
class to execute a script that retrieves
process information by using the list
of process names passed into the script. It shows
how to pass input objects to
a script and how to retrieve error objects as well as the
output objects.
7 Note
You can download the C# source file (runspace03.cs) for this sample using the
Microsoft Windows Software Development Kit for Windows Vista and Microsoft
.NET Framework 3.0 Runtime Components. For download instructions, see
How to
Install Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples>
directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
/// <remarks>
/// 3. Passing input objects to the script from the calling program.
/// </remarks>
};
powershell.AddScript(script);
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
// returned...
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
PSDataCollection<ErrorRecord> errors =
powershell.Streams.Error;
System.Console.ReadKey();
See Also
Windows PowerShell Programmer's Guide
Here is the VB.NET source code for the console application described in
"Creating a
Console Application That Runs a Specified Script". This sample uses
the
System.Management.Automation.Runspaceinvoke
class to execute a script that retrieves
process information for the list of
process names passed into the script. It shows how to
pass input objects to a
script and how to retrieve error objects as well as the output
objects.
7 Note
You can download the VB.NET source file (runspace03.vb) for this sample by
using
the Windows Software Development Kit for Windows Vista and Microsoft
.NET
Framework 3.0 Runtime Components. For download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples>
directory.
Code Sample
VB
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces
Namespace Microsoft.Samples.PowerShell.Runspaces
Class Runspace03
''' <summary>
''' </summary>
''' <remarks>
''' 3. Passing input objects to the script from the calling program.
''' </remarks>
"services", "nosuchprocess2"}
Console.WriteLine("Process HandleCount")
Console.WriteLine("--------------------------------")
' Now invoke the runspace and display the objects that are
' returned...
Console.WriteLine("{0,-20} {1}", _
result.Members("ProcessName").Value, _
result.Members("HandleCount").Value)
Next result
' Now process any error records that were generated while
Next err
End If
System.Console.ReadKey()
End Namespace
See Also
Windows PowerShell Programmer's Guide
7 Note
You can download the VB.NET source file (Runspace04.vb) for this runspace using
the Windows
Software Development Kit for Windows Vista and Microsoft .NET
Framework 3.0 Runtime Components.
For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
Language Topic
See Also
Windows PowerShell Programmer's Guide
Here is the VB.NET source code for the Runspace04 sample. This sample uses the
System.Management.Automation.Runspaceinvoke class to execute a script that
generates a terminating error. The host application is responsible for catching the error
and interpreting the error record.
7 Note
You can download the VB.NET source file (runspace02.vb) for this sample by using
the Windows Software Development Kit for Windows Vista and Microsoft .NET
Framework 3.0 Runtime Components. For download instructions, see How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
VB
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces
Namespace Microsoft.Samples.PowerShell.Runspaces
Class Runspace04
''' <summary>
''' </summary>
''' <remarks>
''' 3. Passing input objects to the script from the calling program.
''' </remarks>
' thrown.
Try
Console.WriteLine("'{0}'", result.ToString())
Next result
Console.WriteLine(vbCrLf & _
Next err
End If
vbCrLf + "{2}", _
runtimeException.ErrorRecord.InvocationInfo.InvocationName, _
runtimeException.Message, _
runtimeException.ErrorRecord.InvocationInfo.PositionMessage)
End Try
System.Console.ReadKey()
End Namespace
See Also
Windows PowerShell Programmer's Guide
Here is the source code for the Runspace05 sample that is described in
Configuring a
Runspace Using RunspaceConfiguration .
This sample shows how to create the
runspace configuration information, create a runspace, create a
pipeline with a single
command, and then execute the pipeline. The command that is executed is the
Get-
Process cmdlet.
7 Note
You can download the C# source file (runspace05.cs) by using the Microsoft
Windows Software
Development Kit for Windows Vista and Microsoft .NET
Framework 3.0 Runtime Components. For
download instructions, see
How to Install
Windows PowerShell and Download the Windows PowerShell SDK.
The
downloaded source files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample uses an initial session state to create a runspace. The
sample
/// </summary>
/// <remarks>
/// This sample assumes that user has the GetProcessSample01.dll that is
produced
/// snap-in.
/// </remarks>
PSSnapInException warning;
myRunSpace.Open();
powershell.AddCommand("GetProcPSSnapIn01\\get-proc");
powershell.Runspace = myRunSpace;
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Windows PowerShell Programmer's Guide
7 Note
You can download the C# source file (runspace06.cs) by using the Windows
Software Development Kit
for Windows Vista and Microsoft .NET Framework 3.0
Runtime Components. For download instructions,
see
How to Install Windows
PowerShell and Download the Windows PowerShell SDK.
The downloaded source
files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// The sample invokes a command from binary module that is loaded by
the
/// </summary>
/// <remarks>
/// This sample assumes that user has the GetProcessSample02.dll that is
/// module.
/// </remarks>
myRunSpace.Open();
powershell.AddCommand(@"GetProcessSample02\get-proc");
powershell.Runspace = myRunSpace;
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Windows PowerShell Programmer's Guide
7 Note
You can download the C# source file (runspace07.cs) using the Microsoft Windows
Software
Development Kit for Windows Vista and Microsoft .NET Framework 3.0
Runtime Components. For
download instructions, see
How to Install Windows
PowerShell and Download the Windows PowerShell SDK.
The downloaded source
files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to create a runspace and how to run
/// that runs the get-process cmdlet, which is piped to the measure-
object
/// </summary>
/// <remarks>
/// </remarks>
myRunSpace.Open();
powershell.Runspace = myRunSpace;
using (powershell)
powershell.AddCommand("get-process");
// of the pipeline.
powershell.AddCommand("measure-object");
result = powershell.Invoke();
powershell = null;
// everything is ok first.
if (count == null)
Console.WriteLine(
count.Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Windows PowerShell Programmer's Guide
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// This sample shows how to use a PowerShell object to run commands.
The
/// which is then piped to the sort-object cmdlet. Parameters are added
to the
/// </summary>
/// <remarks>
/// </remarks>
using (powershell)
powershell.AddCommand("get-process");
// in descending order.
powershell.AddCommand("sort-
object").AddParameter("descending").AddParameter("property", "handlecount");
results = powershell.Invoke();
powershell = null;
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
System.Console.ReadKey();
See Also
Windows PowerShell SDK
RunSpace09 Code Sample
Article • 09/17/2021
This sample application creates and opens a runspace, creates and asynchronously
invokes a pipeline,
and then uses pipeline events to process the script asynchronously.
The script that is run by this
application creates the integers 1 through 10 in 0.5-second
intervals (500 ms).
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// is run asynchronously and events are used to handle the output.
/// </summary>
/// <remarks>
/// </remarks>
// Add the event handlers. If we did not care about hooking the
DataAdded
// event, we would let BeginInvoke create the output stream for us.
powershell.InvocationStateChanged += new
EventHandler<PSInvocationStateChangedEventArgs>
(Powershell_InvocationStateChanged);
// Wait for things to happen. If the user hits a key before the
// to halt processing.
Console.ReadKey();
if (powershell.InvocationStateInfo.State !=
PSInvocationState.Completed)
powershell.Stop();
System.Threading.Thread.Sleep(500);
Console.ReadKey();
/// <summary>
/// The output data added event handler. This event is called when
/// data is added to the output pipe. It reads the data that is
/// </summary>
Console.WriteLine(result.ToString());
/// <summary>
/// This event handler is called when the pipeline state is changed.
/// </summary>
if (e.InvocationStateInfo.State == PSInvocationState.Completed)
See Also
Windows PowerShell SDK
RunSpace10 Code Sample
Article • 09/17/2021
Here is the source code for the Runspace10 sample. This sample application adds a
cmdlet to
System.Management.Automation.Runspaces.Runspaceconfiguration
and then
uses the modified configuration information to create the runspace.
7 Note
You can download the C# source file (runspace10.cs) by using the Windows
Software Development Kit
for Windows Vista and Microsoft .NET Framework 3.0
Runtime Components. For download instructions,
see
How to Install Windows
PowerShell and Download the Windows PowerShell SDK.
The downloaded source
files are available in the <PowerShell Samples> directory.
Code Sample
C#
namespace Microsoft.Samples.PowerShell.Runspaces
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
#region GetProcCommand
/// <summary>
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
/// <summary>
/// For each of the requested process names, retrieve and write
/// </summary>
WriteObject(processes, true);
#endregion Overrides
#endregion GetProcCommand
/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
/// <summary>
/// </summary>
// by Windows PowerShell.
iss.Commands.Add(ssce);
// See the Hosting samples for information on creating your own custom
host.
myRunSpace.Open();
powershell.Runspace = myRunSpace;
powershell.AddCommand("get-proc");
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
myRunSpace.Close();
System.Console.ReadKey();
See Also
Windows PowerShell Programmer's Guide
The Contributor's Guide is a collection of articles that describe the tools and processes
we use to
create documentation at Microsoft. Some of these guides cover information
common to any
documentation set published to learn.microsoft.com . Other guides are
specific to how we write
documentation for PowerShell.
The common articles are available in our centralized Contributor's Guide. The
PowerShell-specific guides are available here.
Ways to contribute
There are two ways to contribute. Both contributions are valuable to us.
1. Quick edits to existing docs - Minor corrections, fixing typos, or small additions
2. Full GitHub workflow for docs - large changes, multiple versions, adding or
changing
images, or contributing new articles
Also, read the Writing essentials section of the centralized Contributor's Guide. Another
excellent resource is the Microsoft Writing Style Guide.
Use the full GitHub workflow when you're making significant changes. If you're not an
employee of
Microsoft, our PR validation system adds a comment to the pull request
asking you to sign the online
Contribution Licensing Agreement (CLA) . You must
complete this step before we can review or
accept your pull request. Signing the CLA is
only required the first time you submit a PR in the
repository. You will be asked to sign
the CLA for each time you contribute to a new repository.
Code of conduct
All repositories that publish to Microsoft Learn have adopted the
Microsoft Open Source
Code of Conduct or the
.NET Foundation Code of Conduct . For more
information,
see the Code of Conduct FAQ .
Next steps
The following articles cover information specific to PowerShell documentation. Where
there's overlap
with the guidance in the centralized Contributor's Guide, we call out how
those rules differ for the
PowerShell content.
Additional resources
Editorial checklist
How we manage issues
How we manage pull requests
Get started contributing to PowerShell
documentation
Article • 10/27/2022
PowerShell-Docs structure
The PowerShell-Docs repository is divided into two groups of content: reference and
conceptual.
Reference content
The reference content is the PowerShell cmdlet reference for the cmdlets that ship in
PowerShell.
The cmdlet reference is collected in versioned folders (like 5.1, 7.0, and
7.2), which contain
reference for the modules that ship with PowerShell. This content is
also used to create the help
information displayed by the Get-Help cmdlet.
Conceptual content
The conceptual documentation isn't organized by version. All articles are displayed for
every
version of PowerShell.
7 Note
Similar to the PowerShell RFC process , create an issue before you write the content.
The issue
ensures you don't waste time and effort on work that gets rejected by the
PowerShell-Docs team. The
issue allows us to consult with you on the scope of the
content and where it fits in the PowerShell
documentation. All articles must be included
in the Table of Contents (TOC). The proposed TOC
location should be included in the
issue discussion.
7 Note
The TOC for reference content is autogenerated by the publishing system. You
don't have to update
the TOC.
Localized content
The PowerShell documentation is written in English and translated into 17 other
languages. The
English content is stored in the GitHub repository named
MicrosoftDocs/PowerShell-Docs . Issues
found in the translated content should be
submitted to the English repository.
All translations start from the English content first. We use both human and machine
translation.
Human translation de-DE, es-ES, fr-FR, it-IT, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-TW
The content translated by machine translation may not always result in correct word
choices and
grammar. If you find an error in translation for any language, rather than in
the technical details
of the article, open an issue explaining why you think the
translation is wrong.
Some translation issues can be fixed by changing the English source files. However,
some issues may
require updates to our internal translation system. For those cases, we
must submit the issue to our
internal localization team for review and response.
Next steps
There are two common ways of submitting changes in GitHub. Both methods are
described in the central
Contributor's Guide:
1. You can make quick edits to existing documents in the GitHub web interface.
2. Use the full GitHub workflow for adding new articles, updating multiple files, or
other
large changes.
Before starting any changes, you should create a fork of the PowerShell-Docs repository.
The changes
should be made in a working branch in you copy of the PowerShell-Docs. If
you're using the quick
edit method in GitHub, these steps are handled for you. If you're
using the full GitHub
workflow, you must be set up to work locally.
Both methods end with the creation of a Pull Request (PR). See Submitting a pull
request for
more information and best practices.
Contribute using GitHub Codespaces
Article • 05/17/2023
GitHub has a feature called Codespaces that you can use to contribute to the
PowerShell
documentation without having to install or configure any software locally.
When you use a
codespace, you get the same authoring tools the team uses for writing
and editing.
You can use a codespace in your browser, making your contributions in VS Code hosted
over the
internet. If you have VS Code installed locally, you can connect to the
codespace there too.
Available tools
When you use a codespace to contribute to the PowerShell documentation, your editor
has these tools
already available for you:
Cost
GitHub Codespaces can be used for free up to 120 core-hours per month. With the
configuration we
recommend in this article, that means up to 60 hours of free usage per
month. The monthly usage is
calculated across all your repositories, not just
documentation.
For more information about pricing, see About billing for GitHub Codespaces .
Tip
If you're comfortable using containers and Docker, you can get the same
experience as using
GitHub Codespaces in VS Code by using the devcontainer
defined for the PowerShell documentation
repositories. There's no cost associated
with using devcontainers. For more information, see
the Dev Containers tutorial .
After following these steps, GitHub creates a new codespace for that repository and sets
it up for
you. When the codespace is ready, the page refreshes and shows the web
editor UI for the codespace.
The UI is based on VS Code and works the same way.
After you select your codespace, GitHub opens it in the same window. From here, you're
ready to
contribute.
The rest of this article describes a selection of tasks you can do in your GitHub
Codespace while
writing or editing your contribution.
1. Right click on the link destination and select "Refactor..." in the context menu.
2. Press Ctrl + Shift + R .
Either action raises the refactoring context menu. Select "Extract to link definition" in the
context menu. This replaces the (destination.md) in the link with [def] . You can
rename the
definition by typing a name in.
For the PowerShell documentation, we use two-digit numerical reference link definitions,
like
[01] or [31] . Only use reference link definitions in about topics and conceptual
documentation.
Don't use reference link definitions in cmdlet reference documentation.
Select the rule's name in the hover information to open a web page that explains the
rule. Select
the rule's filename (ending in .yml ) to open the rule and review its
implementation.
If the rule supports a quick fix, you can select "Quick Fix..." in the hover information for
the
violation and apply one of the suggested fixes by selecting it from the context
menu. You can also
press Ctrl + . when your cursor is on a highlighted problem to
apply a quick
fix if the rule supports it.
If the rule doesn't support quick fixes, read the rule's message and fix it if you can. If
you're not sure how to fix it, the editors can make a suggestion when reviewing your PR.
Fix syntax problems
When you review an article in your codespace, Markdownlint automatically checks the
article when
you open it and as you type. If Markdownlint finds any syntax problems, it
highlights them in the
document with colored squiggles.
Select the rule's ID in the hover information to open a web page that explains the rule.
If the rule supports a quick fix, you can select "Quick Fix..." in the hover information for
the
violation and apply one of the suggested fixes by selecting it from the context
menu. You can also
press Ctrl + . when your cursor is on a highlighted problem to
apply a quick
fix if the rule supports it.
If the rule doesn't support quick fixes, read the rule's message and fix it if you can. If
you're not sure how to fix it, the editors can make a suggestion when reviewing your PR.
You can also apply fixes to all syntax violations in an article. To do so, open the
command palette
and type Fix all supported markdownlint violations in the
document . As you type, the command
palette filters the available commands. Select the
"Fix all supported markdownlint violations in
the document" command. When you do,
Markdownlint updates the document to resolve any violations it
has a quick fix for.
Format a table
To format a Markdown table, place your cursor in or on the table in your Markdown.
Open the Command
Palette and search for the Table: Format Current command. When
you select that command, it
updates the Markdown for your table to align and pad the
table for improved readability.
markdown
|:--:|:--|-:|
| a | b | c |
Into this:
markdown
| foo | bar | baz |
| a | b | c |
Insert an alert
The documentation uses alerts to make information more notable to a reader.
To insert an alert, you can, open the Command Palette and search for the Learn: Alert
command.
When you select that command, it opens a context menu. Select the alert
type you want to add. When
you do, the command inserts the alert's Markdown at your
cursor in the document.
You can also use the casing commands for any text in the document.
To open the Command Palette in the UI, select "View" in the top menu bar. Then select
"Command
Palette..." in the context menu.
To open the Command Palette with your keyboard, press the key combination for your
operating system:
When using this command for block quotes, make sure the paragraph in the block
quote you're
reflowing is surrounded by blank lines. Otherwise, the command reflows
every paragraph together.
U Caution
Don't use this command when editing about topics. The lines in those documents
must not be
longer than 80 characters. There's currently no way for a repository to
configure different line
lengths by folder or filename, so reflow doesn't work for
about topic documents.
To open the Problems View in the UI, select "View" in the top menu bar. Then select
"Problems" in
the context menu.
To open the Problems View with your keyboard, press the key combination for your
operating system:
The Problems View displays all errors, warnings, and suggestions for the open
document. Select a
problem to scroll to it in the document.
Additional resources
The tasks and commands described in this article don't cover everything you can do
with VS Code or
the installed extensions.
For more information about the installed extensions, see their documentation:
change-case
GitLens
Gremlins tracker for Visual Studio Code
Learn Authoring Pack
markdownlint
Reflow Markdown
Table Formatter
Markdown best practices
Article • 09/27/2022
This article provides specific guidance for using Markdown in our documentation. This is
not a
tutorial for Markdown, but list specific rules and best practice for Markdown in the
PowerShell
docs. If you need a tutorial for Markdown, see this Markdown cheatsheet .
Markdown specifics
The Microsoft Open Publishing System (OPS) that builds our documentation uses
markdig to
process the Markdown documents. Markdig parses the documents based
on the rules of the latest
CommonMark specification.
The CommonMark spec is much stricter about the construction of some Markdown
elements. Pay close
attention to the details provided in this document.
We use the markdownlint extension in VS Code to enforce our style and formatting
rules. This
extension is installed as part of the Learn Authoring Pack.
There should be a single blank between Markdown blocks of different types -- for
example, between
a paragraph and a list or header.
Don't use more than one blank line. Multiple blank lines render as a single blank
line in HTML
and serve no purpose.
Within a code block, consecutive blank lines break the code block.
Remove extra spaces at the end of lines. Trailing spaces can change how
Markdown renders.
Always uses spaces instead of hard tabs.
Use sentence case - only proper nouns and the first letter of a title or header
should be
capitalized
There must be a single space between the # and the first letter of the heading
Headings should be surrounded by a single blank line
Only one H1 per document
Header levels should increment by one -- don't skip levels
Avoid using bold or other markup in headers
Use the Reflow Markdown extension in VS Code to reflow paragraphs to fit the
prescribed line
length.
Lists
If your list has multiple sentences or paragraphs, consider using a sublevel header rather
than a
list.
Unordered lists
Don't end list items with a period unless they contain multiple sentences.
Use the hyphen character ( - ) for list item bullets. This avoids confusion with bold
or italic
markup that uses the asterisk ( * ).
To include a paragraph or other elements under a bullet item, insert a line break
and align
indentation with the first character after the bullet.
For example:
markdown
Ordered lists
All items in a numbered listed should use the number 1. rather than incrementing
each item.
Markdown rendering increments the value automatically.
This makes reordering items easier and standardizes the indentation of
subordinate content.
To include a paragraph or other elements under a numbered item, align
indentation with the first
character after the item number.
For example:
markdown
1. For the first element, insert a single space after the 1. Long sentences
should be wrapped to the
next line and must line up with the first character after the numbered
list marker.
To include a second element, insert a line break after the first and
align indentations. The
indentation of the second element must line up with the first character
after the numbered list
marker.
1. For the first element, insert a single space after the 1. Long sentences should be
wrapped to the
next line and must line up with the first character after the
numbered list marker.
To include a second element, insert a line break after the first and align
indentations. The
indentation of the second element must line up with the first
character after the numbered list
marker.
Images
The syntax to include an image is:
markdown
![[alt text]](<folderPath>)
Example:

Where alt text is a brief description of the image and <folderPath> is a relative path
to the
image.
Alternate text is required to support screen readers for the visually impaired.
Images should be stored in a media/<article-name> folder within the folder
containing the
article.
Create a folder that matches the filename of your article under the media folder.
Copy the
images for that article to that new folder.
Don't share images between articles.
If an image is used by multiple articles, each folder must have a copy of that
image.
This prevents a change to an image in one article affecting another article.
The following image file types are supported: *.png , *.gif , *.jpeg , *.jpg , *.svg
markdown
> [!NOTE]
> [!TIP]
> [!IMPORTANT]
> [!CAUTION]
> [!WARNING]
Note block
7 Note
Tip block
Tip
Important block
) Important
Caution block
U Caution
Negative potential consequences of an action.
Warning block
2 Warning
Hyperlinks
Hyperlinks must use Markdown syntax [friendlyname](url-or-path) .
All URLs to external websites should use HTTPS unless that isn't valid for the target
site.
Links must have a friendly name, usually the title of the linked article
Don't use backticks, bold, or other markup inside the brackets of a hyperlink.
Bare URLs may be used when you're documenting a specific URI and must be
enclosed in backticks.
For example:
markdown
URL-type Links
URL links to other articles on learn.microsoft.com must use site-relative paths. The
simplest
way to create a relative link is to copy the URL from your browser then
remove
https://learn.microsoft.com/en-us from the value you paste into
markdown.
Don't include locales in URLs on Microsoft properties (remove /en-us from URL).
Remove any unnecessary query parameters from the URL. Examples that should be
removed:
?view=powershell-5.1 - used to link to a specific version of PowerShell
?redirectedfrom=MSDN - added to the URL when you get redirected from an old
view=powershell-5.1&preserve-view=true
URL links don't contain file extensions (for example, no .md )
File-type links
A file link is used to link from one reference article to another, or from one
conceptual
article to another. If you need to link from a conceptual article to a
reference article you must
use a URL link.
Use relative filepaths (for example: ../folder/file.md )
All file paths use forward-slash ( / ) characters
Include the file extension (for example, .md )
Cross-reference links
Cross-reference links are a special feature supported by the publishing system. You can
use
cross-reference links in conceptual articles to link to .NET API or cmdlet reference.
For links to .NET API reference, see Use links in documentation in the central
Contributor
Guide.
Microsoft.PowerShell.Management module.
[Get-Content](xref:Microsoft.PowerShell.Management.Get-Content)
Deep linking
(https://code.visualstudio.com/docs/getstarted/keybindings#_custom-
keybindings-for-refactorings)
Next steps
PowerShell style guide
PowerShell-Docs style guide
Article • 11/15/2022
This article provides style guidance specific to the PowerShell-Docs content. It builds on
the
information outlined in the Overview.
Property, parameter, object, type names, class names, class methods should be
bold.
Property and parameter values should be wrapped in backticks ( ` ).
When referring to types using the bracketed style, use backticks. For example:
[System.Io.FileInfo]
Language keywords, cmdlet names, functions, variables, native EXEs, file paths, and
inline syntax
examples should be wrapped in backtick ( ` ) characters.
For example:
markdown
```powershell
markdown
line as a parameter.
markdown
Including the file extension ensures that the correct command is executed
according to
PowerShell's command precedence.
All code blocks should be contained in a code fence. Never use indentation for code
blocks. Markdown
allows this pattern but it can be problematic and should be avoided.
A code block is one or more lines of code surrounded by a triple-backtick ( ``` ) code
fence.
The code fence markers must be on their own line before and after the code
sample. The opening
marker may have an optional language label. The language label
enables syntax highlighting on the
rendered webpage.
For a full list of supported language tags, see Fenced code blocks in the centralized
contributor guide.
Publishing also adds a Copy button that can copy the contents of the code block to the
clipboard. This allows you to paste the code into a script to test the code sample.
However, not all
examples are intended to be run as written. Some code blocks are basic
illustrations of PowerShell
concepts.
markdown
```
```
markdown
```
{<statement list>}
```
Illustrative examples
Illustrative examples are used to explain a PowerShell concept. They aren't meant to be
copied and
pasted for execution. These are most commonly used for simple examples
that are easy to understand.
The code block can include the PowerShell prompt and
example output.
Here's a simple example illustrating the PowerShell comparison operators. In this case,
we don't
intend the reader to copy and run this example.
markdown
```powershell
PS> 2 -eq 2
True
PS> 2 -eq 3
False
True
False
abc
```
Executable examples
Complex examples, or examples that are intended to be copied and executed, should
use the following
block-style markup:
markdown
```powershell
```
markdown
```powershell
```
```Output
```
The Output code label isn't an official "language" supported by the syntax highlighting
system.
However, this label is useful because our publishing system adds the "Output"
label to the code box
frame on the web page. The "Output" code box has no syntax
highlighting.
Use PowerShell splatting to reduce line length for cmdlets that have several
parameters.
Take advantage of PowerShell's natural line break opportunities, like after pipe ( | )
characters,
opening braces ( { ), parentheses ( ( ), and brackets ( [ ).
PowerShell
PS C:\> cd HKCU:\System\
PS HKCU:\System\> dir
Hive: HKEY_CURRENT_USER\System
Name Property
---- --------
CurrentControlSet
GameConfigStore GameDVR_Enabled : 1
GameDVR_FSEBehaviorMode : 2
Win32_AutoGameModeDefaultProfile : {2, 0, 1,
0...}
Win32_GameModeRelatedProcesses : {1, 0, 1,
0...}
GameDVR_HonorUserFSEBehaviorMode : 0
GameDVR_DXGIHonorFSEWindowsCompatible : 0
PlatyPS has a schema that expects a specific structure for cmdlet reference. The
platyPS.schema.md document attempts to describe this structure. Schema violations
cause build
errors that must be fixed before we can accept your contribution.
Don't remove any of the ATX header structures. PlatyPS expects a specific set of
headers.
The Input type and Output type headers must have a type. If the cmdlet doesn't
take input
or return a value, then use the value None .
Inline code spans can be used in any paragraph.
Fenced code blocks are only allowed in the EXAMPLES section.
0 or more paragraphs
0 or more paragraphs.
For example:
markdown
This command gets the PowerShell cmdlets, functions, and aliases that are
installed on the
computer.
```powershell
Get-Command
```
```powershell
Get-Command -ListImported
```
Within a paragraph, these characters should be put into code spans. For
example:
markdown
Markdown tables
For About_* topics, tables must fit within 76 characters
If the content doesn't fit within 76 character limit, use bullet lists instead
Use opening and closing | characters on each line
Next steps
Editorial checklist
Editor's checklist
Article • 11/16/2022
This is a summary of rules to apply when writing new or updating existing articles. See
other
articles in the Contributor's Guide for detailed explanations and examples of these
rules.
Metadata
ms.date : must be in the format MM/DD/YYYY
search result
Formatting
Backtick syntax elements that appear, inline, within a paragraph
Cmdlet names Verb-Noun
Variable $counter
Syntactic examples Verb-Noun -Parameter
File paths C:\Program Files\PowerShell , /usr/bin/pwsh
URLs that aren't meant to be clickable in the document
Property or parameter values
Use bold for property names, parameter names, class names, module names, entity
names, object or
type names
Bold is used for semantic markup, not emphasis
Bold - use asterisks **
Italic - use underscore _
Only used for emphasis, not for semantic markup
Line breaks at 100 columns (or at 80 for about_Topics)
No hard tabs - use spaces only
No trailing spaces on lines
PowerShell keywords and operators should be all lowercase
Use proper (Pascal) casing for cmdlet names and parameters
Headers
H1 is first - only one H1 per article
Use ATX Headers only
Use sentence case for all headers
Don't skip levels - no H3 without an H2
Max depth of H3 or H4
Blank line before and after
PlatyPS enforces specific headers in its schema - don't add or remove headers
Code blocks
Blank line before and after
Use tagged code fences - powershell, Output, or other appropriate language ID
Untagged fence - syntax blocks or other shells
Put output in separate code block except for basic examples where you don't
intend the for the
reader to use the Copy button
See list of supported languages
Lists
Indented properly
Blank line before first item and after last item
Bullet - use hyphen ( - ) not asterisk ( * ) to reduce confusion with emphasis
For numbered lists, all numbers are "1."
Terminology
PowerShell vs. Windows PowerShell
See Product Terminology
PowerShell syntax
Use full names of cmdlets and parameters - no aliases
Use splatting for parameters when the command line gets too long
Avoid using line continuation backticks - only use when necessary
Remove or simplify the PowerShell prompt ( PS> ) except where required for the
example
markdown
more code blocks. Recommend at least one and no more than two.
```powershell
```
```Output
don't put paragraphs between the code blocks. All descriptive content must come
before or after
the code blocks.
don't include locales in URLs on Microsoft properties (eg. remove /en-us from
URL)
All URLs to external websites should use HTTPS unless that's not valid for the
target site
When linking within the docset
Use the relative filepath (e.g. ../folder/file.md )
All paths use forward-slash ( / ) characters
Image links should have unique alt text
Product terminology and branding
guidelines
Article • 11/15/2022
When writing about any product it's important to correctly and consistently use product
names and
terminology. This guide defines product names and terminology related to
PowerShell. Note the
capitalization of specific words or use cases.
Guidelines
Subsequent mentions - Use "PowerShell" unless the use case requires "Windows
PowerShell" to be
more specific:
For example:
Azure PowerShell
Az.Accounts module
Windows management module
Hyper-V module
Microsoft Graph PowerShell SDK
Exchange PowerShell
Guidelines
Always use the collective name or the more specific module name when referring
to a PowerShell
module
Never refer to a module as "PowerShell"
There are several versions of Azure PowerShell products available. Each product contains
multiple
named modules.
Guidelines
Guidelines
Always use the full proper name of the product or the specific PowerShell module
name
Guidelines
Guidelines
At the bottom of most pages on learn.microsoft.com , you'll see two feedback buttons.
One is a link
for product feedback and one is for documentation feedback. The
documentation feedback requires a
GitHub account. Clicking the button takes you in
GitHub and presents an issue template. Enter your
feedback and submit the form.
7 Note
The feedback tool not a support channel. This is a way to ask questions to clarify
documentation
or to report errors and omissions. If you need technical support, see
Community resources.
Before you file a new issue, read through existing issues to see if your problem has
already been
reported. This helps avoid duplication and your issue may have been
answered already. If you find an
existing issue, you can add your comments, related
questions, or answers.
Next steps
See Get started writing.
Additional resources
How we manage issues
How to submit pull requests
Article • 09/19/2022
To make changes to content, submit a pull request (PR) from your fork. A pull request
must be
reviewed before it can be merged. For best results, review the editorial checklist
before
submitting your pull request.
Before starting any changes, create a working branch in your local copy of the
PowerShell-Docs
repository. When working locally, be sure to synchronize your local
repository before creating your
working branch. The working branch should be created
from an update-to-date copy of the main
branch.
All pull requests should target the main branch. Don't submit change to the live
branch. Changes
made in the main branch get merged into live , overwriting any
changes made to live .
Bulk changes create PRs with large numbers of changed files. Limit your PRs to a
maximum of 50
changed files. Large PRs are difficult to review and are more prone to
contain errors.
Renaming or deleting files
When renaming or deleting files, there must be an issue associated with the PR. That
issue must
discuss the need to rename or delete the files.
Avoid mixing content additions or change with file renames and deletes. Any file that's
renamed or
deleted must be added to the global redirection file. When possible, update
any files that link to
the renamed or deleted content, including any TOC files.
Incorrect modifications to repository configuration files can break the build, introduce
vulnerabilities or accessibility issues, or violate organizational standards. Repository
configuration files are any files that match one or more of these patterns:
*.yml
.github/**
.localization-config
.openpublishing*
LICENSE*
reference/docfx.json
reference/mapping/**
tests/**
ThirdPartyNotices
tools/**
For safety and security, if you believe you have discovered a bug or potential
improvement for a
repository configuration file, file an issue . The maintainers will
review and implement any
fixes or improvements as needed.
Markdown
# PR Summary
<!--
Delete this comment block and summarize your changes and list
- Fixes #1234
- Resolves #1235
-->
## PR Checklist
<!--
ensure you have followed these steps. As you complete the steps,
check each box by replacing the space between the brackets with an
-->
- [ ] **Summary:** This PR's summary describes the scope and intent of the
change.
<!--
-->
[contrib]: /powershell/scripting/community/contributing/overview
[style]: /powershell/scripting/community/contributing/powershell-style-guide
In the "PR Summary" section, write a short summary of your changes and list any related
issues by
their issue number, like #1234 . If your PR fixes or resolves the issue, use
GitHub's
autoclose feature so the issue is automatically closed when your PR is
merged.
Review the items in the "PR Checklist" section and check them off as you complete each
one. You must
follow the directions and check each item for the team to approve your
PR.
If your PR is a work-in-progress, set it to draft mode or prefix your PR title with WIP .
Expectations Comment
After you submit your PR, a bot will comment on your PR to provide you with resources
and to set
expectations for the rest of the process. Always review this comment, even if
you've contributed
before, because it contains accurate and up-to-date information.
2. In the GitHub comment that indicates the status of your PR, you'll see the status of
"checks"
enabled on the repository. In this example, there are two checks enabled,
"Commit Validation" and
"OpenPublishing.Build":
The build can pass even if commit validation fails.
4. On the Details page, you'll see all the validation checks that failed, with information
about how
to fix the issues.
If you are an external (not a Microsoft employee) contributor you don't have access
to the
detailed build reports or preview links.
When the PR is reviewed, you may be asked to make changes or fix validation warning
messages. The
PowerShell-Docs team can help you understand validation errors and
editorial requirements.
GitHub Actions
Several different GitHub Actions run against your changes to validate and provide
context for you
and the reviewers.
Checklist verification
If your PR is not in draft mode and is not prefixed with WIP , a GitHub Action inspects
your
PR to verify that you have checked every item in the PR template's checklist. If this
check fails,
the team won't review or merge your PR. The checklist items are mandatory.
Authorization verification
If your PR targets the live branch or modifies any repository configuration files, a
GitHub Action
checks your permissions to verify that you are authorized to submit those
changes.
Only repository administrators are authorized to target the live branch or modify
repository
configuration files.
This report is useful for seeing if there are other versions of the file(s) you modified and
whether
or not those versions have also been updated in the changeset.
Additional resources
How we manage pull requests
Contributing quality improvements
Article • 12/13/2022
Aliases
Formatting code samples
Formatting command syntax
Link References
Markdown linting
Spelling
Project Tracking
We're tracking contributions with the PowerShell Docs Quality Contributions GitHub
Project.
The project page has several views for the issues and PRs related to this effort:
Aliases
We're working through documenting the aliases for every cmdlet.
In the Notes section, add the information to the beginning of the section using this
format:
Markdown
- All platforms:
- `<alias>`
- Linux:
- `<alias>`
- macOS:
- `<alias>`
- Windows:
- `<alias>`
If there is more than one alias for a platform, add it on a separate line as a new list item.
If a
platform has no aliases, omit it from the list.
Markdown
- `<alias>`
Markdown
Always use the full name for cmdlets and parameters. Avoid using aliases unless
you're
specifically demonstrating the alias.
Property, parameter, object, type names, class names, class methods should be
bold.
Property and parameter values should be wrapped in backticks ( ` ).
When referring to types using the bracketed style, use backticks. For example:
[System.Io.FileInfo]
Link references
For maintainability and readability of the markdown source for our documentation,
we're converting
our conceptual documentation to use link references instead of inline
links.
Markdown
It should be:
Markdown
7 Note
When you replace an inline link, reflow the content to wrap at 100 characters. You
can use the
reflow-markdown VS Code extension to do this quickly.
At the bottom of the file, add a markdown comment before the definition of the links.
Markdown
[01]: https://www.powershellgallery.com/packages
1. The links are defined in the order they appear in the document.
2. Every link points to the correct location.
3. The link reference definitions are at the bottom of the file after the markdown
comment and are
in the correct order.
Markdown linting
For any article in one of the participating repositories, opening the article in VS Code
displays
linting warnings. Address any of these warnings you find, except:
Make sure of the line lengths and use the Reflow Markdown extension to fix any long
lines.
Spelling
Sometimes, despite our best efforts, typos and misspellings get through and end up in
the
documentation. These mistakes make documentation harder to follow and localize.
Fixing these
mistakes makes the documentation more readable, especially for non-
English speakers who rely on
accurate translations.
Process
We encourage you to choose one or more of the quality areas and an article (or group
of articles)
to improve. Once you've decided what articles and content areas you want to
work on, follow these
steps:
1. Check the project for issues filed for this effort to avoid duplicating efforts.
3. Follow our contributor's guide to get setup for making your changes.
b. Your PR body references the issue it resolves as an unordered list item and uses
one of the
linking keywords .
For example, if you're working on issue 123 , the body of your PR should include
the
following Markdown:
Markdown
- resolves #123
The content developers will review your work as soon as they can to help you get it
merged.
Hacktoberfest and other hack-a-thon
events
Article • 10/04/2022
Hacktoberfest is an annual worldwide event held during October. The event encourages
open source
developers to contribute to repositories through pull requests (PR). GitHub
hosts many open source
repositories that contribute to Microsoft Learn content. Several
repositories actively participate
in Hacktoberfest.
How to contribute
Before you can contribute to an open source repo, you must first configure your
account to
contribute to Microsoft Learn. If you have never completed this process, start
by
signing up for a GitHub account. Be sure to install Git and the Markdown tools.
To get credit for participation, register with Hacktoberfest and read their
participation
guide .
Before contributing should read the meta-issue. When you are ready to start, open a
new issue using
the Hacktoberfest issue template (linked below):
MicrosoftDocs/PowerShell-Docs
MicrosoftDocs/PowerShell-Docs-DSC
MicrosoftDocs/PowerShell-Docs-Modules
MicrosoftDocs/windows-powershell-docs
MicrosoftDocs/azure-docs-powershell
Quality expectations
To have a successful contribution to an open source Microsoft Learn repository, create a
meaningful
and impactful PR. The following examples from the official Hacktoberfest
site are considered
low-quality contributions:
PRs that are automated (for example, scripted opening PRs to remove whitespace,
fix typos, or
optimize images)
PRs that are disruptive (for example, taking someone else's branch or commits and
making a PR)
PRs that are regarded by a project maintainer as a hindrance vs. helping
A submission that's clearly an attempt to simply +1 your PR count for October
Finally, one PR to fix a typo is fine, but five PRs to remove a stray whitespace are not.
Open a PR
A PR provides a convenient way for a contributor to propose a set of changes. When
opening a PR,
specify in the original comment that it's intended to contribute to
hacktoberfest. Successful PRs
have these common characteristics:
If you're proposing a PR without a corresponding issue, create an issue first. For more
information,
see GitHub: About pull requests .
See also
Git and GitHub essentials for Microsoft Learn documentation
Official Hacktoberfest site
How we manage issues
Article • 11/10/2022
This article documents how we manage issues in the PowerShell-Docs repository. This
article is
designed to be a job aid for members of the PowerShell-Docs team. It's
published here to provide
process transparency for our public contributors.
Sources of issues
Community contributors
Internal contributors
Transcriptions of comments from social media channels
Feedback via the Docs feedback form
Label Types
Area - Identifies the part of PowerShell or the docs that the issue is discussing
Issue - The type of issue: like bug, feedback, or idea
Priority - The priority of the issue; value range 0-3 (high-low)
Quality - The quality improvement effort the issue commits to resolving
Status - The status of the work item or why it was closed
Tag - Used to for additional classification like availability or doc-a-thons
Waiting - Shows that we're waiting on some external person or event
Milestones
Issues and PRs should be tagged with the appropriate milestone. If the issue doesn't
apply to a
specific version, then no milestone is used. PRs and related issues for changes
that have yet to be
merged into the PowerShell code base should be assigned to the
Future milestone. After the code
change has been merged, change the milestone to the
appropriate version.
Milestone Description
Triage process
PowerShell docs team members review the issues daily and triage new issues as they
arrive. The team
meets weekly to discuss difficult issues need triage and prioritize the
work.
Optional: Copy the issue to the appropriate product feedback location, add a link
to the copied
item, and close the issue.
Support requests
If the support question is simple, answer it politely and close the issue.
If the question is more complicated, or the submitter replies with more questions,
redirect them
to forums and support channels. Suggested text for redirecting to
forums:
Markdown
> This is not the right forum for these kinds of questions. Try posting
your question in a
> https://learn.microsoft.com/powershell/scripting/community/community-
support
This article documents how we manage pull requests in the PowerShell-Docs repository.
This article
is designed to be a job aid for members of the PowerShell-Docs team. It's
published here to provide
process transparency for our public contributors.
Best practices
The person submitting the PR shouldn't merge the PR without a peer review.
Assign the peer reviewer when the PR is submitted. Early assignment allows the
reviewer to respond
sooner with editorial remarks.
Use comments to describe the nature of the change being submitted. Be sure to
@mention the
reviewer. For example, if the change is minor and you don't need a
full technical review, explain
this in a comment.
Reviewers should use the comment suggestion feature, when appropriate, to make
it easier for the
author to accept the suggested change. For more information, see
Reviewing proposed changes in a pull request .
PR Process steps
1. Writer: Create PR
PR Merger checklist
Content review complete
Correct target branch for the change
No merge conflicts
All validation and build step pass
Warnings and suggestions should be fixed (see Notes for exceptions)
No broken links
The Checklist action ran and passed
If an Authorization check was triggered, it passed
Merge according to table
Notes
The following warnings can be ignored:
Metadata with following name(s) are not allowed to be set in Yaml header, or
as file level
Docs platform, so the values set in these 3 places will be ignored. Please
remove them from all
When a PR is merged, the HEAD of the target branch is changed. Any open PRs that
were based on the
previous HEAD are now outdated. The outdated PR can be merged
using Admin rights to override the
merge warnings in GitHub. This is safe to do if the
previously merged PRs haven't touched the same
files. Clicking the Update Branch
button is the safest option. Choose Update with rebase
option. For more information
see Updating your pull request branch .
Publishing to Live
Periodically, the changes accumulated in the main branch need to be published to the
live
website.
This article documents how we label issues and pull requests in the PowerShell-Docs
repository.
This article is designed to be a job aid for members of the PowerShell-Docs
team. It's published
here to provide process transparency for our public contributors.
Labels always have a name and a description that is prefixed with their type.
Area labels
Area labels identify the parts of PowerShell or the documentation that the issue relates
to.
area-helpsystem The Help services, including the pipeline and *-Help cmdlets.
area-sdk-ref The .NET API reference documentation for the PowerShell SDK.
Issue labels
Issue labels distinguish issues by purpose.
Priority labels
Priority labels rank which work items need to be worked on before others. These labels
are only
used when needed to manage large sets of work items.
Label Priority Level
Pri0 Highest
Pri1 High
Pri2 Medium
Pri3 Low
Project Labels
Project labels indicate what ongoing GitHub Project a work item is related to. These
labels are
used for automatically adding work items to a project on creation.
Label Project
Quality labels
Quality labels categorize work items for the quality improvement effort.
Label Improvement
quality-format-code- Ensure proper casing, line length, and other formatting in code
samples samples
Status labels
Status labels indicate why a work item was closed or shouldn't be merged. Issues are
only given
status labels when they're closed without a related PR.
Label Status
Tag labels
Tag labels add independent context for work items.
Label Purpose
Waiting labels
Waiting labels indicate that a work item can't be resolved until an external condition is
met.
7 Note
This document is about support for PowerShell. Windows PowerShell (1.0 - 5.1) is a
component of
the Windows operating system. Components receive the same
support as their parent product or
platform. For more information, see Product and
Services Lifecycle Information.
PowerShell is supported under the Microsoft Modern Lifecycle Policy, but support dates
are
linked to .NET and .NET Core Support Policy . In this servicing approach, customers
can choose
Long Term Support (LTS) releases or current releases.
An LTS release of PowerShell is built on an LTS release of .NET. Updates to an LTS release
only
contain critical security updates and servicing fixes that are designed to minimize
impact to
existing workloads. LTS releases of PowerShell are supported until the end-of-
support for .NET.
A current release is a release that occurs between LTS releases. Current releases can
contain
critical fixes, innovations, and new features. A current release is supported for six
months after
the next release (current or LTS).
) Important
You must have the latest patch update installed to qualify for support. For example,
if you're
running PowerShell 7.3 and 7.3.1 has been released, you must update to
7.3.1 to qualify for
support.
Supported platforms
PowerShell runs on multiple operating systems (OS) and processor architectures. To be
supported by
Microsoft, the OS must meet the following criteria:
Windows
The following table is a list of PowerShell releases and the versions of Windows they're
supported
on. These versions are supported until either the version of
PowerShell
reaches end-of-support or the version of
Windows reaches end-of-support.
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
Windows 11
Windows 10 1607+
7 Note
Windows Server 2012 R2+ x64, x86 x64, x86 x64, x86
Windows Server Core 2012 R2+ x64, x86 x64, x86 x64, x86
Windows 10 or 11 Client x64, x86, Arm64 x64, x86, Arm64 x64, x86, Arm64
macOS
The following table contains a list of PowerShell releases and the status of support for
versions of
macOS. These versions remain supported until either the version of
PowerShell reaches end-of-support or the version of macOS reaches end-of-support.
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
macOS Big Sur 11.5 x64, Arm64 x64, Arm64 x64, Arm64
Alpine Linux
The following table lists the supported PowerShell releases and the versions of Alpine
they're
supported on. These versions are supported until either the version of
PowerShell reaches end-of-support or the version of
Alpine reaches end-of-life .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
3.15
3.14
Debian Linux
The following table is a list of currently supported PowerShell releases and the versions
of Debian
they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
Debian reaches end-of-
life .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
Debian 7.2 (LTS-current) 7.3 7.4 (preview)
11
10
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
Ubuntu Linux
The following table is a list of currently supported PowerShell releases and the versions
of
Ubuntu they're supported on. These versions remain supported until either the
version of
PowerShell reaches end-of-support or the version of
Ubuntu reaches end-of-
support .
The icon indicates that the version of the OS or PowerShell is still supported
The icon indicates the version of PowerShell is no longer supported on that
version of the OS
The icon indicates that we haven't finished testing PowerShell on that OS
The icon indicates that the version of the OS or PowerShell isn't supported
When both the version of the OS and the version of PowerShell have a icon,
that
combination is supported
22.04 (LTS)
20.04 (LTS)
18.04 (LTS)
Only the LTS releases of Ubuntu are officially supported. Microsoft does not support
interim releases or their equivalent. Interim releases are community supported. For
more
information, see Community supported distributions.
Raspberry Pi OS
Raspberry Pi OS (formerly Raspbian) is a free operating system based on Debian.
) Important
Experimental features
Experimental features are limited to community support.
Notes on licensing
PowerShell is released under the MIT license . Under this license, and without a paid
support
agreement, users are limited to community support. With community support,
Microsoft makes no
guarantees of responsiveness or fixes.
Getting support
Support for PowerShell is delivered via traditional Microsoft support agreements,
including
paid support , Microsoft Enterprise Agreements , and Microsoft Software
Assurance .
You can also pay for assisted support for PowerShell by filing a support
request for your
problem.
There are also community support options. You can file an issue, bug, or feature request
on
GitHub. Also, you may find help from other members of the community in the
Microsoft
PowerShell Tech Community or any of the forums listed in the community
section of
PowerShell hub page. We offer no guarantee there that the community will
address or resolve
your issue in a timely manner. If you have a problem that requires
immediate attention, you should
use the traditional, paid support options.
) Important
You must have the latest patch update installed to qualify for support. For example,
if you're
running PowerShell 7.3 and 7.3.1 has been released, you must update to
7.3.1 to qualify for
support.
Support for PowerShell on a specific platforms is based on the support policy of the
version of .NET
used.
PowerShell 7.3 (Stable) is based on the .NET 7.0 Supported OS Lifecycle Policy
PowerShell 7.2 (LTS-current) is based on the .NET 6.0 Supported OS Lifecycle
Policy
PowerShell 7.1 (Stable) is based on the .NET 5.0 Supported OS Lifecycle Policy
PowerShell 7.0 (LTS) is based on the .NET Core 3.1 Supported OS Lifecycle Policy
Release history
The following table contains a timeline of the major releases of PowerShell. This table is
provided
for historical reference. It isn't intended for use to determine the support
lifecycle.
PowerShell 6.0 Jan-2018 First release, built on .NET Core 2.0. Installable on Windows,
Linux, and macOS
Windows PowerShell Oct-2013 Integrated in Windows 8.1 and with Windows Server 2012 R2,
4.0 WMF 4.0
Windows PowerShell Oct-2012 Integrated in Windows 8 and with Windows Server 2012 WMF
3.0 3.0
Windows PowerShell Jul-2009 Integrated in Windows 7 and Windows Server 2008 R2, WMF
2.0 2.0