# Technical Documentation: PowerShell/powershell

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/PowerShell/powershell)

### Overview (`README.md`)

# ![logo][] PowerShell

Welcome to the PowerShell GitHub Community!
[PowerShell](https://learn.microsoft.com/powershell/scripting/overview) is a cross-platform (Windows, Linux, and macOS) automation and configuration tool/framework that works well with your existing tools and is optimized
for dealing with structured data (e.g. JSON, CSV, XML, etc.), REST APIs, and object models.
It includes a command-line shell, an associated scripting language, and a framework for processing cmdlets.

[logo]: assets/ps_black_64.svg?sanitize=true

## Windows PowerShell vs. PowerShell 7+

Although this repository started as a fork of the Windows PowerShell codebase, changes made in this repository are not ported back to Windows PowerShell 5.1.
This also means that [issues tracked here][issues] are only for PowerShell 7.x and higher.
Windows PowerShell specific issues should be reported with the [Feedback Hub app][feedback-hub], by choosing "Apps > PowerShell" in the category.

[issues]: https://github.com/PowerShell/PowerShell/issues
[feedback-hub]: https://support.microsoft.com/windows/send-feedback-to-microsoft-with-the-feedback-hub-app-f59187f8-8739-22d6-ba93-f66612949332

## New to PowerShell?

If you are new to PowerShell and want to learn more, we recommend reviewing the [getting started][] documentation.

[getting started]: https://learn.microsoft.com/powershell/scripting/learn/more-powershell-learning

## Get PowerShell

PowerShell is supported on Windows, macOS, and a variety of Linux platforms. For
more information, see [Installing PowerShell](https://learn.microsoft.com/powershell/scripting/install/installing-powershell).

## Upgrading PowerShell

For best results when upgrading, you should use the same install method you used when you first
installed PowerShell. The update method is different for each platform and install method.

## Community Dashboard

[Dashboard](https://aka.ms/PSPublicDashboard) with visualizations for community contributions and project status using PowerShell, Azure, and PowerBI.

For more information on how and why we built this dashboard, check out this [blog post](https://devblogs.microsoft.com/powershell/powershell-open-source-community-dashboard/).

## Discussions

[GitHub Discussions](https://docs.github.com/discussions/quickstart) is a feature to enable free and open discussions within the community
for topics that are not related to code, unlike issues.

This is an experiment we are trying in our repositories, to see if it helps move discussions out of issues so that issues remain actionable by the team or members of the community.
There should be no expectation that PowerShell team members are regular participants in these discussions.
Individual PowerShell team members may choose to participate in discussions, but the expectation is that community members help drive discussions so that team members
can focus on issues.

Create or join a [discussion](https://github.com/PowerShell/PowerShell/discussions).

## Chat

Want to chat with other members of the PowerShell community?

There are dozens of topic-specific channels on our community-driven PowerShell Virtual User Group, which you can join on:

* [Discord](https://discord.gg/PowerShell)
* [IRC](https://web.libera.chat/#powershell) on Libera.Chat
* [Slack](https://aka.ms/psslack)

## Developing and Contributing

Want to contribute to PowerShell? Please start with the [Contribution Guide][] to learn how to develop and contribute.

If you are developing .NET Core C# applications targeting PowerShell Core, [check out our FAQ][] to learn more about the PowerShell SDK NuGet package.

Also, make sure to check out our [PowerShell-RFC repository](https://github.com/powershell/powershell-rfc) for request-for-comments (RFC) documents to submit and give comments on proposed and future designs.

[Contribution Guide]: .github/CONTRIBUTING.md
[check out our FAQ]: docs/FAQ.md#where-do-i-get-the-powershell-core-sdk-package

## Building PowerShell

| Linux                    | Windows                    | macOS                   |
|--------------------------|----------------------------|------------------------|
| [Instructions][bd-linux] | [Instructions][bd-windows] | [Instructions][bd-macOS] |

If you have any problems building PowerShell, please start by consulting the developer [FAQ].

[bd-linux]: docs/building/linux.md
[bd-windows]: docs/building/windows-core.md
[bd-macOS]: docs/building/macos.md
[FAQ]: docs/FAQ.md

## Downloading the Source Code

You can clone the repository:

```sh
git clone https://github.com/PowerShell/PowerShell.git
```

For more information, see [working with the PowerShell repository](https://github.com/PowerShell/PowerShell/tree/master/docs/git).

## Support

For support, see the [Support Section][].

[Support Section]: https://github.com/PowerShell/PowerShell/tree/master/.github/SUPPORT.md

## Legal and Licensing

PowerShell is licensed under the [MIT license][].

[MIT license]: https://github.com/PowerShell/PowerShell/tree/master/LICENSE.txt

### Docker Containers

> [!Important]
> The PowerShell container images are now [maintained by the .NET team](https://github.com/PowerShell/Announcements/issues/75). The containers at `mcr.microsoft.com/powershell` are currently not maintained.

License: By requesting and using the Container OS Image for Windows containers, you acknowledge, understand, and consent to the Supplemental License Terms available on [Microsoft Artifact Registry][mcr].

[mcr]: https://mcr.microsoft.com/en-us/product/powershell/tags

### Telemetry

Please visit our [about_Telemetry](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_telemetry)
topic to read details about telemetry gathered by PowerShell.

## Governance

The governance policy for the PowerShell project is described the [PowerShell Governance][gov] document.

[gov]: https://github.com/PowerShell/PowerShell/blob/master/docs/community/governance.md

## [Code of Conduct](CODE_OF_CONDUCT.md)

Please see our [Code of Conduct](CODE_OF_CONDUCT.md) before participating in this project.

## [Security Policy](.github/SECURITY.md)

For any security issues, please see our [Security Policy](.github/SECURITY.md).

---

### Overview (`CHANGELOG/README.md`)

# Changelogs

- [Current preview changelog](preview.md)
- [7.6 changelog](7.6.md)
- [7.5 changelog](7.5.md)
- [7.4 changelog](7.4.md)
- [7.3 changelog](7.3.md)
- [7.2 changelog](7.2.md)
- [7.1 changelog](7.1.md)
- [7.0 changelog](7.0.md)
- [6.2 changelog](6.2.md)
- [6.1 changelog](6.1.md)
- [6.0 changelog](6.0.md)

---

### Overview (`assets/README.md`)

# Use of Trademarked Logos

The assets in this folder are trademarked by Microsoft and don't fall under the same [License](https://raw.githubusercontent.com/PowerShell/PowerShell/master/LICENSE.txt) as the source code.

## Permitted Uses

Parties interested in using these logos can review the [Use of Microsoft Copyrighted Material](https://www.microsoft.com/en-us/legal/intellectualproperty/permissions) page.
If the use falls into any of those categories, you can move forward with the use and will not need additional permission.

## Third Party Permission Requests

If questions remain after reviewing the permitted uses page, please submit a request to [Third Party Permissions](mailto:mscrqs@microsoft.com).
The people supporting this will direct the request depending upon the content.

If a request needs to be submitted to the [Third Party Permissions](mailto:mscrqs@microsoft.com), the request should include the following:

  - A statement that the [Use of Microsoft Copyrighted Material](https://www.microsoft.com/en-us/legal/intellectualproperty/permissions) was reviewed and did not address the situation.
  - A statement that Microsoft (and not a third party) is the owner of the logo at issue.
  - Clear identification of the materials to be used (i.e., the picture of the book cover included by the author in the letter request should suffice).
  - A description, including URLs of how they found or located the logo.
  - A description of how the party intends to use or distribute the logo (i.e., that it is for the book cover of an instructional book on PowerShell).
  - A description of how long the party needs to use the logo.

---

### Overview (`docker/README.md`)

# Docker

Dockerfiles to build the Docker images for PowerShell Core have been moved to [PowerShell/PowerShell-Docker](https://github.com/PowerShell/PowerShell-Docker).

---

### Overview (`test/README.md`)

Testing
=======

The tests are organized by testing language. Thus Pester tests, which
are written in the PowerShell language, are in
[./powershell](./powershell) and xUnit tests, written in C#, are in
[./xUnit](./xUnit). The third-party
[shebang][] test is in [./shebang](./shebang).

[shebang]: https://en.wikipedia.org/wiki/Shebang_(Unix)

---

### Overview (`tools/install-powershell.ps1-README.md`)

# install-powershell.ps1

## Features of install-powershell.ps1

- Can be called directly from Git
- Optionally allows install of the latest Preview build
- Optionally installs using the latest MSI
- Automatically looks up latest version via Git tags
- Optionally installs silently
- Optionally adds the install location to Path environment variable

## Examples

### Install PowerShell Preview Build

```PowerShell
Invoke-Expression "& { $(Invoke-RestMethod 'https://aka.ms/install-powershell.ps1') } -Preview"
```

### Install PowerShell using the MSI installer

```PowerShell
Invoke-Expression "& { $(Invoke-RestMethod 'https://aka.ms/install-powershell.ps1') } -UseMSI"
```

---

### Overview (`tools/install-powershell.sh-README.md`)

# install-powershell.sh

## Features of install-powershell.sh

* Can be called directly from git
* Optionally installs vs code and vs powershell extension (aka PowerShell IDE) using optional `-includeide` switch
* Defaults to completely automated operation (if appropriate permissions are available)
* Automatically looks up latest version via git tags
* Automatic selection of appropriate install sub-script
* Configures software installs for repositories when repositories are in place, otherwise pulls files from git releases.  As repository versions are made available, script will be updated to take advantage.
* User permission checking
* Sub-installers called from local file system if they exist, otherwise pulled from git
* Sub-installers can be called directly if auto-selection is not needed

## Minimum Requirements for install-powershell.sh

* bash shell
* `sed`
* native package manager available
* `curl` (auto-installed if missing)
* `tr`

## Parameters

* -includeide - installs VSCode and VSCode PowerShell extension (only relevant to machines with a desktop environment)
* -interactivetesting - do a quick launch test of VSCode (only relevant when used with -includeide)
* -skip-sudo-check - use sudo without verifying its availability (hard to accurately do on some distros)
* -preview - installs the latest preview release of PowerShell core side-by-side with any existing production releases

## Usage

### Direct from Github

```bash
bash <(wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) <ARGUMENTS>

wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh | bash -s <ARGUMENTS>
```

### Local Copy

```bash
bash install-powershell.sh <ARGUMENTS>
```

## Examples

### Only Install PowerShell Core

```bash
bash <(wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh)
```

### Install PowerShell Core with IDE

```bash
bash <(wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) -includeide
```

### Install PowerShell Core with IDE and do tests that require a human to interact with the installation process

```bash
bash <(wget -O - https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/install-powershell.sh) -includeide -interactivetesting
```

### Installation To do list

* Detect and wait when package manager is busy/locked? - at least Ubuntu (CentOS does this internally)

---

### Overview (`docs/debugging/README.md`)

# Visual Studio Code

The [Visual Studio Code][vscode] editor supports cross-platform debugging.
This is made possible by the [OmniSharp][] extension for VS Code.

Please review their [detailed instructions][core-debug]. In
addition to being able to build PowerShell, you need:

- C# Extension for VS Code installed
- .NET Core debugger installed (semi-automatic)
- `powershell` executable in your path (self-host if not on Windows)

The .NET CLI tools *must* be on your path for Visual Studio Code.
`Start-PSBootstrap` installs the tools to `~/.dotnet` (non-Windows) or `"$env:LocalAppData\Microsoft\dotnet"` (Windows),
but does not add this to your `PATH`.
You can do this in Bash with `export PATH=$PATH:$HOME/.dotnet` or in PowerShell with `$env:path = $env:path+";$env:LocalAppData\Microsoft\dotnet"`.

Once the extension is installed, you have to open a C# file to force VS Code to
install the actual .NET Core debugger (the editor will tell you to do this if
you attempt to debug and haven't already opened a C# file).

The committed `.vscode` folder in the root of this repository contains
the `launch.json` and `tasks.json` files which provide Core PowerShell
debugging configurations and a build task.

The "build" task will run `Start-PSBuild`, emitting the executable to
`PowerShell/debug/powershell` so that the debugger always knows where to find it
(regardless of platform). If you edit this, please do not commit it, as the
default is meant to "just work" for anyone.

The ".NET Core Launch" configuration will build and start a `powershell`
process, with `justMyCode` disabled, and `stopAtEntry` enabled, thus PowerShell
will stop right at `Main`, and you need to click the green arrow to continue.

With either Gnome Terminal or XTerm installed, the launch configuration will
launch an external console with PowerShell running interactively. If neither of
these installed, the editor will tell you to do so.

Alternatively, the ".NET Core Attach" configuration will start listening for a
process named `powershell`, and will attach to it. If you need more fine-grained
control, replace `processName` with `processId` and provide a PID. (Please be
careful not to commit such a change.)

[core-debug]: https://learn.microsoft.com/dotnet/core/tutorials/with-visual-studio-code#debug
[vscode]: https://code.visualstudio.com/
[OmniSharp]: https://github.com/OmniSharp/omnisharp-vscode

## PowerShell

The `Trace-Command` cmdlet can be used to enable tracing of certain PowerShell
subsystems. Use `Get-TraceSource` for a list of tracers:

* CmdletProviderClasses
* CommandDiscovery
* CommandSearch
* ConsoleHost
* ConsoleHostRunspaceInit
* ConsoleHostUserInterface
* ConsoleLineOutput
* DisplayDataQuery
* ETS
* FileSystemProvider
* FormatFileLoading
* FormatViewBinding
* LocationGlobber
* MemberResolution
* Modules
* MshSnapinLoadUnload
* ParameterBinderBase
* ParameterBinderController
* ParameterBinding
* PathResolution
* PSDriveInfo
* PSSnapInLoadUnload
* RunspaceInit
* SessionState
* TypeConversion
* TypeMatch

Then trace it like this:

```powershell
Trace-Command -Expression { Get-ChildItem . } -Name PathResolution -PSHost
```

The `-PSHost` specifies the sink, in this case the console host,
so we can see the tracing messages.
The `-Name` chooses the list of tracers to enable.

## LLDB with SOS plug-in

The `./tools/debug.sh` script can be used to launch PowerShell inside of LLDB
with the SOS plug-in provided by .NET Core. This provides an additional way to
debug PowerShell on Linux, but VS Code is recommended for a better user
experience (and its single-stepping capabilities).

The script is self-documented and contains a link to the
[CoreCLR debugging help][clr-debug] .

[clr-debug]: https://github.com/dotnet/coreclr/blob/master/Documentation/building/debugging-instructions.md#debugging-coreclr-on-linux

## `corehost`

The native executable produced by .NET CLI will produce trace output
if launched with `COREHOST_TRACE=1 ./powershell`.

## CoreCLR PAL

The native code in the CLR has debug channels to selectively output
information to the console. These are controlled by the
`PAL_DBG_CHANNELS`, e.g., `export PAL_DBG_CHANNELS="+all.all"`, as
detailed in the `dbgmsg.h` [header][].

Enabling `+all.all` is *incredibly* noisy;
you will need to narrow your scope.

[header]: https://github.com/dotnet/coreclr/blob/release/1.0.0/src/pal/src/include/pal/dbgmsg.h

## Debugging .NET Core

The .NET Core libraries downloaded from NuGet and shipped with PowerShell are release versions.
This means that `PAL_DBG_CHANNELS` will not work with them,
and instead you must build and deploy .NET Core built in debug mode.
These instructions are not meant to be comprehensive,
but should prove useful.

They are currently written for Linux and are meant only as a shortcut means to debug.

## Build and deploy CoreCLR

* Clone CoreCLR: `git clone -b release/1.0.0 https://github.com/dotnet/coreclr.git`
* Follow [building instructions](https://github.com/dotnet/coreclr/blob/release/1.0.0/Documentation/building/linux-instructions.md)
* Wait for `./build.sh` to finish
* Overwrite PowerShell libraries: `cp bin/Product/Linux.x64.Debug/*{so,dll} /path/to/powershell/`

## Build and deploy CoreFX

* Clone CoreFX: `git clone -b release/1.0.0 https://github.com/dotnet/corefx.git`
* Follow [building instructions](https://github.com/dotnet/corefx/blob/release/1.0.0/Documentation/building/unix-instructions.md)
* Wait for `./build.sh skiptests` to finish
* Overwrite PowerShell libraries:

> This must be done in a particular order to get the most specific build,
> and each phase must be allowed to overwrite both the previous phase
> and any files previously found (hence the use of `-exec cp`).
> The glob cannot go more than one directory deep,
> as subdirectories can have alternative and unwanted implementations
> of libraries with the same name.

```sh
dest=/path/to/powershell/
find bin/AnyOS.AnyCPU.Debug/*/*.dll -exec cp -p {} $dest \;
find bin/Unix.AnyCPU.Debug/*/*.dll -exec cp -p {} $dest \;
find bin/Linux.AnyCPU.Debug/*/*.dll -exec cp -p {} $dest \;
find bin/Linux.x64.Debug/ -name *.so -exec cp -p {} $dest \;
```

---

### Overview (`docs/git/README.md`)

# Working with PowerShell repository

## Get the code for the first time

```sh
git clone https://github.com/PowerShell/PowerShell.git --branch=master
```

## Branches

* Don't commit your changes directly to master.
  It will make the collaborative workflow messy.
* Checkout a new local branch from `master` for every change you want to make (bugfix, feature).
* Use lowercase-with-dashes for naming.
* Follow [Linus' recommendations][Linus] about history.
  * "People can (and probably should) rebase their _private_ trees (their own work). That's a _cleanup_. But never other peoples code. That's a 'destroy history'...
  You must never EVER destroy other peoples history. You must not rebase commits other people did.
  Basically, if it doesn't have your sign-off on it, it's off limits: you can't rebase it, because it's not yours."

### Understand branches

* **master** is the branch with the latest and greatest changes.
  It could be unstable.
* Send your pull requests to **master**.

### Sync your local repository

Use **git rebase** instead of **git merge** and **git pull**, when you're updating your feature-branch.

```sh
# fetch updates all remote branch references in the repository
# --all : tells it to do it for all remotes (handy, when you use your fork)
# -p : tells it to remove obsolete remote branch references (when they are removed from remote)
git fetch --all -p

# rebase on origin/master will rewrite your branch history
git rebase origin/master
```

### More complex scenarios

Covering all possible git scenarios is behind the scope of the current document.
Git has excellent documentation and lots of materials available online.

We are leaving a few links here:

[Linus]:https://web.archive.org/web/20230522041845/https://wincent.com/wiki/git_rebase%3A_you're_doing_it_wrong

## Tags

If you are looking for the source code for a particular release,
you will find it via **tags**.

* `git tag` will show you list of all tags.
* Find the tag that corresponds to the release.
* Use `git checkout <tag-name>` to get this version.

**Note:** [checking out a tag][tag] will move the repository to a [DETACHED HEAD][HEAD] state.

[tag]:https://git-scm.com/book/en/v2/Git-Basics-Tagging#Checking-out-Tags
[HEAD]:https://www.git-tower.com/learn/git/faq/detached-head-when-checkout-commit

If you want to make changes, based on tag's version (i.e. a hotfix),
checkout a new branch from this DETACHED HEAD state.

```sh
git checkout -b vors/hotfix
```

## Recommended Git configurations

We highly recommend these configurations to help deal with whitespace,
rebasing, and general use of Git.

> Auto-corrects your command when it's sure (`stats` to `status`)

```sh
git config --global help.autoCorrect -1
```

> Refuses to merge when pulling, and only pushes to branch with same name.

```sh
git config --global pull.ff only
git config --global push.default current
```

> Shows shorter commit hashes and always shows reference names in the log.

```sh
git config --global log.abbrevCommit true
git config --global log.decorate short
```

> Ignores whitespace changes and uses more information when merging.

```sh
git config --global apply.ignoreWhitespace change
git config --global rerere.enabled true
git config --global rerere.autoUpdate true
git config --global am.threeWay true
```

---

### Overview (`docs/host-powershell/README.md`)

# Host PowerShell Core in .NET Core Applications

## PowerShell Core v6.0.1 and Later

The runtime assemblies for Windows, Linux and OSX are now published in NuGet package version 6.*.

Please see the [.NET Core Sample Application](#net-core-sample-application) section for an example that uses PowerShell Core NuGet packages.

## .NET Core Sample Application

Note: The .NET Core `2.1` runtime and .NET Core SDK `2.1` or higher is required for the examples below:

- [sample](./sample)

You can find the sample application project `MyApp` in each of the above 2 sample folders. You can quickly test-run it using `dotnet run`.
To build the sample project properly for distribution, run the following command (make sure the required .NET Core SDK is in use):

```powershell
dotnet publish .\MyApp --configuration release
```

This builds it for the runtimes specified by the `RuntimeIdentifiers` property in the `.csproj` file.
Then you can run the `MyApp` binary from the publish folder and see the results:

```none
PS:> .\MyApp.exe

Evaluating 'Get-Command Write-Output' in PS Core Runspace

Write-Output

Evaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS Core Runspace

System.Management.Automation.ActionPreference
System.Management.Automation.AliasAttribute
```

## Special Hosting Scenario For Native Host

There is a special hosting scenario for native hosts,
where Trusted Platform Assemblies (TPA) do not include PowerShell assemblies,
such as the in-box `powershell.exe` in Nano Server and the Azure DSC host.

For such hosting scenarios, the native host needs to bootstrap by calling [`PowerShellAssemblyLoadContextInitializer.SetPowerShellAssemblyLoadContext`](https://learn.microsoft.com/dotnet/api/system.management.automation.powershellassemblyloadcontextinitializer.setpowershellassemblyloadcontext).
When using this API, the native host can pass in the path to the directory that contains PowerShell assemblies.
A handler will then be registered to the [`Resolving`](https://github.com/dotnet/corefx/blob/d6678e9653defe3cdfff26b2ff62135b6b22c77f/src/System.Runtime.Loader/ref/System.Runtime.Loader.cs#L38)
event of the default load context to deal with the loading of assemblies from that directory.

---

### Overview (`docs/maintainers/README.md`)

# Repository Maintainers

Repository Maintainers are trusted stewards of the PowerShell repository responsible for maintaining consistency and quality of PowerShell code.
One of their primary responsibilities is merging pull requests after all requirements have been fulfilled.

They have [write access](https://docs.github.com/en/free-pro-team@latest/github/setting-up-and-managing-organizations-and-teams/repository-permission-levels-for-an-organization) to the PowerShell repositories which gives them the power to:

1. `git push` to the official PowerShell repository
1. Merge [pull requests](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)
1. Assign labels, milestones, and people to [issues](https://guides.github.com/features/issues/) and [pull requests](https://docs.github.com/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests)

## Table of Contents

- [Current Repository Maintainers](#current-repository-maintainers)
- [Repository Maintainer Responsibilities](#repository-maintainer-responsibilities)
- [Issue Management Process](#issue-management-process)
- [Pull Request Workflow](#pull-request-workflow)
- [Becoming a Repository Maintainer](#becoming-a-repository-maintainer)

## Current Repository Maintainers



- Aditya Patwardhan ([adityapatwardhan](https://github.com/adityapatwardhan))
- Andrew Menagarishvili ([anmenaga](https://github.com/anmenaga))
- Dongbo Wang ([daxian-dbw](https://github.com/daxian-dbw))
- Ilya Sazonov ([iSazonov](https://github.com/iSazonov))
- Robert Holt ([rjmholt](https://github.com/rjmholt))
- Travis Plunk ([TravisEz13](https://github.com/TravisEz13))

## Former Repository Maintainers



- Andy Jordan ([andyleejordan](https://github.com/andyleejordan))
- Jason Shirk ([lzybkr](https://github.com/lzybkr))
- Mike Richmond ([mirichmo](https://github.com/mirichmo))
- Sergei Vorobev ([vors](https://github.com/vors))

## Repository Maintainer Responsibilities

Repository Maintainers enable rapid contributions while maintaining a high level of quality in PowerShell by ensuring that all development processes are being followed correctly.

If you are a Repository Maintainer, you:

1. **MUST** abide by the [Code of Conduct](../../CODE_OF_CONDUCT.md) and report suspected violations to the [PowerShell Committee][ps-committee]
1. **MUST** ensure that each contributor has signed a valid Microsoft Contributor License Agreement (CLA)
1. **MUST** verify compliance with any third party code license terms (e.g., requiring attribution, etc.) if the contribution contains third party code.
1. **MUST** make sure that [any change requiring approval from the PowerShell Committee](../community/governance.md#changes-that-require-an-rfc) has gone through the proper [RFC][RFC-repo] or approval process
1. **MUST** validate that code reviews have been conducted before merging a pull request when no code is written
1. **MUST** validate that tests and documentation have been written before merging a pull request that contains new functionality
1. **SHOULD** add [the correct labels][issue-management] to issues and pull requests
1. **SHOULD** make sure the correct [Area Experts](../community/governance.md#area-experts) are assigned to relevant pull requests and issues.
  This includes adding extra reviewers when it makes sense
  (e.g. a pull request that adds remoting capabilities might require a security expert)
1. **SHOULD** validate that the names and email addresses in the git commits reasonably match identity of the person submitting the pull request
1. **SHOULD** make sure contributors are following the [contributor guidelines][CONTRIBUTING]
1. **SHOULD** ask people to resend a pull request, if it [doesn't target `master`](../../.github/CONTRIBUTING.md#lifecycle-of-a-pull-request)
1. **SHOULD** wait for the [CI system][ci-system] build to pass for pull requests
  (unless, for instance, the pull request is being submitted to fix broken CI)
1. **SHOULD** encourage contributors to refer to issues in their pull request description (e.g. `Resolves issue #123`).
  If a user did not create an issue prior to submitting their pull request, their pull request should not be rejected.
  However, they should be reminded to create an issue in the future to frontload any potential problems with the work and to minimize duplication of efforts.
1. **SHOULD** encourage contributors to create meaningful titles for all PRs.
  Edit the title if necessary to provide clarity on the problem
1. **SHOULD** encourage contributors to write meaningful, descriptive git commits
1. **SHOULD NOT** merge pull requests with a failed CI build
  (unless, for instance, the pull request is being submitted to fix broken CI)
1. **SHOULD NOT** merge pull requests without the status check passing from the Microsoft CLA bot
  (unless the CLA bot is broken, and CLA signing can be confirmed through other means)
1. **SHOULD NOT** merge pull requests too quickly after they're submitted.
  Even if the pull request meets all the requirements, people should have time to give their input
  (unless the pull request is particularly urgent for some reason)
1. **SHOULD NOT** merge your own pull requests.
  If a Repository Maintainer opens a pull request, another Maintainer should merge it unless there are extreme, short-term circumstances requiring a merge or another Maintainer has given explicit sign-off without merging

## Issue Management Process

Please see [Issue Management][issue-management]

## Pull Request Workflow

Please see [Contributing][CONTRIBUTING]

## Maintainer Best Practices

Please see [Best Practices][best-practice]

## Becoming a Repository Maintainer

Repository Maintainers currently consist mostly of Microsoft employees.
It is expected that over time, regular trusted contributors to the PowerShell repository will be made Repository Maintainers.
Eligibility is heavily dependent on the level of contribution and expertise: individuals who contribute consistently in meaningful ways to the project will be recognized accordingly.

At any point in time, the existing Repository Maintainers can unanimously nominate a strong community member to become a Repository Maintainer.
Nominations are brought to the PowerShell Committee to understand the reasons and justification.
A simple majority of the PowerShell Committee is required to veto the nomination.
When a nominee has been approved, a PR will be submitted by a current Maintainer to update this document to add the nominee's name to
the [Current Repository Maintainers](#current-repository-maintainers) with justification as the description of the PR to serve as the public announcement.

[RFC-repo]: https://github.com/PowerShell/PowerShell-RFC
[ci-system]: ../testing-guidelines/testing-guidelines.md#ci-system
[issue-management]: issue-management.md
[CONTRIBUTING]: ../../.github/CONTRIBUTING.md
[best-practice]: best-practice.md
[ps-committee]: ../community/governance.md#powershell-committee

---

### Overview (`src/Microsoft.PowerShell.SDK/README.md`)

Microsoft PowerShell SDK
========================

This is a meta-project that serves two purposes:

1. Group PowerShell sub projects to avoid unnecessary duplication of reference declarations.
2. Group extra .NET Core packages that PowerShell doesn't depend on directly but must provide for our users at runtime.

---

### Overview (`src/Modules/README.md`)

Modules
==========

There are 3 directories with **content** files.
Content files includes: 

- ps1xml
- psm1
- psd1
- ps1

These files are copied as-is by `dotnet`

- Shared (shared between Windows and Unix)
- Windows
- Unix

Notes
-----------

We have files with the same names in different folders.
That means that the contents of these two files are different. 
I.e. if it's .psd1 file, it could be because `CmdletsToExport`
are different for different runtimes (platforms) or frameworks.

---

### Overview (`src/PowerShell.Core.Instrumentation/README.md`)

# PowerShell.Core.Instrumentation

The `PowerShell.Core.Instrumentation.man` has actually been migrated to [PowerShell-Native](https://github.com/PowerShell/PowerShell-Native/tree/master/src/PowerShell.Core.Instrumentation) repository.
The corresponding manifest resource DLL `PowerShell.Core.Instrumentation.dll` is now produced in the release build of `PowerShell-Native` and is shipped in the `Microsoft.PowerShell.Native` NuGet package.

However, we still need to keep `PowerShell.Core.Instrumentation.man` in the PowerShell repository because the PowerShell packages for Windows ship the manifest file and `RegisterManifest.ps1` for users to register the manifest resource DLL if they want to.
Therefore, when making changes to `PowerShell.Core.Instrumentation.man`, make sure your changes are made to both repositories -- **this file needs to be kept in sync between those 2 repositories**.

---

### Overview (`src/TypeCatalogGen/README.md`)

# TypeCatalogGen

`./build.sh` runs the Core PowerShell `TypeCatalogGen.exe` under Mono
on Linux (using `dotnet-cli`). The `Runtime` folder is a facade
project that, when published, produces a list of the currently used
runtime assemblies for .NET Core. The output is
`CorePsTypeCatalog.cs`, which contains an "initialized" dictionary
that we copy into `typecatalog.cs` of `System.Management.Automation`

---

### Overview (`src/libpsl-native/README.md`)

# libpsl-native

The code under `libpsl-native` is being migrated to the [PowerShell-native](https://github.com/PowerShell/PowerShell-native) repository.
Please make PRs to the new repository.
Code under here will be removed once the move is complete.

---

### Overview (`src/powershell-native/README.md`)

# powershell-native

The code under `powershell-native` is being migrated to [PowerShell-native](https://github.com/PowerShell/PowerShell-native) repository.
Please make PRs to the new repository.
Code under here will be removed once the move is complete.

---

### Overview (`src/powershell/README.md`)

PowerShell
==========

The `powershell[.exe]` executable for PowerShell is built by
**powershell-unix** and **powershell-windows** projects,
as they are the top dependencies of the graph, and has `emitEntryPoint: true`,
meaning a native executable is produced automatically by CLI (no need to own a
separate native host).

This project is a very simple shim that provides a `Main` function for .NET CLI
to produce an app. It initializes PowerShell's custom `AssemblyLoadContext` and
then delegates to the same `Start` function in
`Microsoft.PowerShell.ConsoleHost` that the original native PowerShell host
executes; thus we share the same entry point and the same PowerShell host, but
use a different native host. This lets us take full advantage of .NET CLI's
native host.

We use this shim so that the `ConsoleHost` project and the original native host
do not have to be changed. Additionally, until .NET CLI bugs surrounding content
file deployment are solved, this shim allows us to continue with our split
`Modules` folders work-around to deploy the correct versions.

---

### Overview (`test/powershell/README.md`)

# Pester Testing Test Guide

Also see the [Writing Pester Tests](../../docs/testing-guidelines/WritingPesterTests.md)
document.

## Running Pester Tests

Go to the top level of the PowerShell repository and run: `Start-PSPester`
inside a self-hosted copy of PowerShell.

You can use `Start-PSPester -Tests SomeTestSuite*` to limit the tests run.

## Testing new `powershell` processes

Any launch of a new `powershell` process must include `-noprofile` so that
modified user and system profiles do not causes tests to fail. You also must
take care to call the development copy of PowerShell, which is *not* the first
one on the path.

Example:

```powershell
    $powershell = Join-Path -Path $PsHome -ChildPath "pwsh"
    & $powershell -noprofile -command "ExampleCommand" | Should Be "ExampleOutput"
```

## Portability

Some tests simply must be tied to certain platforms. Use Pester's
`-Skip` directive on an `It` statement to do this. For instance to run
the test only on Windows:

```powershell
It "Should do something on Windows" -Skip:($IsLinux -Or $IsMacOS) { ... }
```

Or only on Linux and OS X:

```powershell
It "Should do something on Linux" -Skip:$IsWindows { ... }
```

## Pending

When writing a test that should pass, but does not, please do not skip or delete
the test, but use `It "Should Pass" -Pending` to mark the test as pending, and
file an issue on GitHub.

---

### Overview (`test/xUnit/README.md`)

# xUnit Tests

The folder contains xUnit tests for PowerShell Core project.

## Running xUnit Tests

Go to the top level of the PowerShell repository and run full set of tests:
`Start-PSxUnit` inside a self-hosted copy of PowerShell.

Go to the test project folder and run `dotnet test -c Release`.

Use [`filter`][xunit-filter] parameter to run only needed tests:
```powershell
dotnet test -c Release --filter "FullyQualifiedName~UnitTest1   # Runs tests which have UnitTest1 in FullyQualifiedName
dotnet test --filter Name~TestMethod1   # Runs tests whose name contains TestMethod1
```

## Creating xUnit Tests

Keep the folder structure that is for Pester [../../test/powershell](../../test/powershell) and C# files [../../src](../../src).

Use namespace names started with `PSTests`.
```c#
namespace PSTests.YourNameSpace
{
}
```

[xunit-filter]: https://learn.microsoft.com/dotnet/core/testing/selective-unit-tests

---

### Overview (`tools/AttackSurfaceAnalyzer/README.md`)

# Attack Surface Analyzer Testing

This directory contains tools for running Attack Surface Analyzer (ASA) tests on PowerShell MSI installations using Docker.

## Overview

Attack Surface Analyzer is a Microsoft tool that helps analyze changes to a system's attack surface. These scripts allow you to run ASA tests locally in a clean Windows container to analyze what changes when PowerShell is installed.

## Files

- **Run-AttackSurfaceAnalyzer.ps1** - PowerShell script to run ASA tests with official MSIs
- **Summarize-AsaResults.ps1** - PowerShell script to analyze and summarize ASA results
- **docker/Dockerfile** - Multi-stage Dockerfile for building a container image with ASA pre-installed
- **README.md** - This documentation file

## Docker Architecture

The Docker implementation uses a multi-stage build to optimize the testing and result extraction process:

### Multi-Stage Build Stages

1. **asa-runner**: Main execution environment
   - Base: `mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022`
   - Contains Attack Surface Analyzer CLI tools
   - Runs the complete test workflow
   - Generates reports in both `C:\work` and `C:\reports` directories

1. **asa-reports**: Minimal results layer
   - Base: `mcr.microsoft.com/windows/nanoserver:ltsc2022`
   - Contains only the test reports from the runner stage
   - Enables clean extraction of results without container internals

1. **final**: Default stage (inherits from asa-runner)
   - Provides backward compatibility
   - Used when no specific build target is specified

### Benefits

- **Clean Result Extraction**: Reports are isolated in a dedicated layer
- **Efficient Transfer**: Only test results are copied, not the entire container filesystem
- **Fallback Support**: Script includes fallback to volume-based extraction if needed
- **Minimal Footprint**: Final results layer contains only the necessary output files

## Prerequisites

- Windows 10/11 or Windows Server
- Docker Desktop with Windows containers enabled
- PowerShell 5.1 or later
- **An official signed PowerShell MSI file** from a released build

### MSI Requirements

**Important:** This tool now requires an official, digitally signed PowerShell MSI from Microsoft releases:

- **Must be signed** by Microsoft Corporation
- **Must be from an official release** (downloaded from [PowerShell Releases](https://github.com/PowerShell/PowerShell/releases))
- **Local builds are not supported** - unsigned or development MSIs will be rejected
- The script automatically verifies the digital signature before proceeding

**Where to get official MSIs:**

- Download from: https://github.com/PowerShell/PowerShell/releases
- Look for files like: `PowerShell-7.x.x-win-x64.msi`

## Quick Start

### Option 1: Using the PowerShell Script (Recommended)

The script requires an official signed PowerShell MSI file:

```powershell
# Run ASA test with official MSI (MsiPath is required)
.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -MsiPath "C:\path\to\PowerShell-7.4.0-win-x64.msi"

# Specify custom output directory for results
.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -MsiPath ".\PowerShell-7.4.0-win-x64.msi" -OutputPath "C:\asa-results"

# Keep the temporary work directory for debugging
.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -MsiPath ".\PowerShell-7.4.0-win-x64.msi" -KeepWorkDirectory
```

The script will:

1. **Verify MSI signature** - Ensures the MSI is officially signed by Microsoft Corporation
1. Create a temporary work directory
1. Build a custom Docker container from the static Dockerfile
1. Start the Windows container with Attack Surface Analyzer
1. Take a baseline snapshot
1. Install the PowerShell MSI
1. Take a post-installation snapshot
1. Export comparison results
1. Copy results back to your specified output directory

**Security Note:** The script will reject any MSI that is not digitally signed by Microsoft Corporation to ensure analysis is performed only on official releases.

### Option 2: Using the Dockerfile

If you prefer to build and use the container image directly:

```powershell
# Build the Docker image (Dockerfile is in docker subfolder with clean context)
docker build -f tools\AttackSurfaceAnalyzer\docker\Dockerfile -t powershell-asa-test tools\AttackSurfaceAnalyzer\docker\

# Run the container with your MSI (script is built into the container)
docker run --rm --isolation process `
  -v "C:\path\to\msi\directory:C:\work" `
  powershell-asa-test
```

## Output Files

The test will generate output files in the `./asa-results/` directory (or your specified `-OutputPath`):

- **`asa.sqlite`** - SQLite database with full analysis data (primary result file)
- **`install.log`** - MSI installation log file
- **`*_summary.json.txt`** - Summary of detected changes (if generated)
- **`*_results.json.txt`** - Detailed results in JSON format (if generated)
- **`*.sarif`** - SARIF format results (if generated, can be viewed in VS Code)

## Analyzing Results

### Using the Summary Script (Recommended)

Use the included summary script to get a comprehensive analysis:

```powershell
# Basic summary of ASA results
.\tools\AttackSurfaceAnalyzer\Summarize-AsaResults.ps1

# Detailed analysis with rule breakdowns
.\tools\AttackSurfaceAnalyzer\Summarize-AsaResults.ps1 -ShowDetails

# Analyze results from a specific location
.\tools\AttackSurfaceAnalyzer\Summarize-AsaResults.ps1 -Path "C:\custom\path\asa-results.json" -ShowDetails
```

The summary script provides:

- **Overall statistics** - Total findings, analysis levels, category breakdowns
- **Rule analysis** - Which security rules were triggered and how often
- **File analysis** - Detailed breakdown of file-related security issues by rule type
- **Category cross-reference** - Shows which rules affect which categories

### Using VS Code

The SARIF files can be opened directly in VS Code with the SARIF Viewer extension to see a formatted view of the findings.

### Using PowerShell

```powershell
# Read the JSON results directly
$results = Get-Content "asa-results\asa-results.json" | ConvertFrom-Json
$results.Results.FILE_CREATED.Count  # Number of files created

# Query the SQLite database (requires SQLite tools)
# Example: List all file changes
# sqlite3 asa.sqlite "SELECT * FROM file_system WHERE change_type != 'NONE'"
```

## Troubleshooting

### Docker Not Available

The script automatically handles Docker Desktop installation and startup:

**If Docker Desktop is installed but not running:**

- The script will automatically start Docker Desktop for you
- It waits up to 60 seconds for Docker to become available
- You'll be prompted for confirmation (supports `-Confirm` and `-WhatIf`)

**If Docker Desktop is not installed:**

- The script will prompt you to install it automatically using winget
- After installation completes, start Docker Desktop and run the script again

**Manual Installation:**

1. Install Docker Desktop from https://www.docker.com/products/docker-desktop
1. Ensure Docker is running
1. Switch to Windows containers (right-click Docker tray icon → "Switch to Windows containers")

### Container Fails to Start

- Ensure you have enough disk space (containers can be large)
- Check that Windows containers are enabled in Docker settings
- Try pulling the base image manually: `docker pull mcr.microsoft.com/dotnet/sdk:9.0-windowsservercore-ltsc2022`

### MSI Signature Verification Fails

If you get signature verification errors:

- **Ensure you're using an official MSI** from [PowerShell Releases](https://github.com/PowerShell/PowerShell/releases)
- **Do not use local builds** - only signed release MSIs are supported  
- **Check certificate validity** - very old MSIs may have expired certificates
- **Verify file integrity** - redownload the MSI if it may be corrupted

### No Results Generated

- Check the install.log file for MSI installation errors
- Run with `-KeepWorkDirectory` to inspect the temporary work directory
- Verify the MSI file is valid and not corrupted

## Advanced Usage

### Parameters

The `Run-AttackSurfaceAnalyzer.ps1` script supports these parameters:

- **`-MsiPath`** (Required) - Path to the official signed PowerShell MSI file
- **`-OutputPath`** (Optional) - Directory for results (defaults to `./asa-results`)
- **`-ContainerImage`** (Optional) - Custom container base image
- **`-KeepWorkDirectory`** (Optional) - Keep temp directory for debugging

Example with custom container image:

```powershell
.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 `
  -MsiPath ".\PowerShell-7.4.0-win-x64.msi" `
  -ContainerImage "mcr.microsoft.com/dotnet/sdk:8.0-windowsservercore-ltsc2022"
```

### Debugging

To debug issues, keep the work directory and examine the files:

```powershell
.\tools\AttackSurfaceAnalyzer\Run-AttackSurfaceAnalyzer.ps1 -KeepWorkDirectory

# The script will print the work directory path
# You can then examine:
# - run-asa.ps1 - The script that runs in the container
# - install.log - MSI installation log
# - Any other generated files
```

## Integration with CI/CD

These tools were extracted from the GitHub Actions workflow to allow local testing. If you need to integrate ASA testing back into a CI/CD pipeline, you can:

1. Use the PowerShell script directly in your pipeline
1. Build and push the Docker image to a registry
1. Use the Dockerfile as a base for custom testing scenarios

## More Information

- [Attack Surface Analyzer on GitHub](https://github.com/microsoft/AttackSurfaceAnalyzer)
- [Docker for Windows Documentation](https://docs.docker.com/desktop/windows/)
- [SARIF Documentation](https://sarifweb.azurewebsites.net/)

---

### Overview (`tools/clearlyDefined/readme.md`)

# ClearlyDefined

## Purpose

This tool is intended to test if all the license data in [ClearlyDefined](https://clearlydefined.io) is present to generate the PowerShell license.
If the data is not present, it can request that ClearlyDefined gather (called Harvest in their terminology) the data.

## Use

### Testing

Run `./ClearlyDefined.ps1 -test`.

If there is any missing data, the script should write verbose messages about the missing data and throw.
If there is no missing data, the script should not throw.

### Harvesting

Run `./ClearlyDefined.ps1 -Harvest`.
The script will trigger the harvest and output the result from ClearlyDefined.
**Give ClearlyDefined 24 hours to harvest the data.**
You can use the `-Test` switch without the `-Harvest` switch to test if Harvesting is done.

## Caching

If you run in the same PowerShell session, the script will be faster due to caching.

The module will cache any results from ClearlyDefined that indicate the package is Harvested for 60 minutes.
No caching is done for packages that are not yet harvested.
To clear the cache, run with the `-ForceModuleReload` switch.

---

### Overview (`tools/performance/README.md`)

# PowerShell Performance Analysis

This directory contains useful scripts and related files for analyzing PowerShell performance.

If you use the [Windows Performance Toolkit](https://learn.microsoft.com/windows-hardware/test/wpt/), you can use the following to collect data and analyze a trace.

```PowerShell
$PowerShellGitRepo = "D:\PowerShell"
wpr -start $PowerShellGitRepo\tools\performance\PowerShell.wprp -filemode
pwsh.exe -NoProfile -Command "echo 1"
wpr -stop PowerShellTrace.etl
wpa -i wpa://.\PowerShellTrace.etl?profile=$PowerShellGitRepo\tools\performance\PowerShell.wpaProfile
```

When wpa opens, under System Activity, you'll find a section "Regions of Interest".
With the above wpaProfile, you should see a bunch of PowerShell related regions as well as GC and JIT activity.

If you use [PerfView](https://github.com/microsoft/perfview), you can collect a trace by running

```PowerShell
Invoke-PerfviewPS.ps1 -scenario { echo 1 }
perfview .\perfviewdata.etl
```

The etl files collected with perfview or wpr should contain roughly the same events.

Also note that you can collect the trace with one tool and analyze with the other.

## Symbols

PDB files are not published for PowerShell Core,
so the current recommendation is to build PowerShell yourself passing `-CrossGen` to `Start-Build`.

If profiling Windows PowerShell, symbols are generated from GAC.
wprui.exe and perfview.exe will both generate the PDB files needed.

## Files

| File | Description |
| ---- | ----------- |
| GC.Regions.xml | WPA regions of interest for GC |
| JIT.Regions.xml | WPA regions of interest for JIT |
| PowerShell.Regions.xml | WPA regions of interest for PowerShell |
| PowerShell.stacktags | PowerShell stack tags |
| PowerShell.wpaProfile | WPA profile to load regions of interest and stack tags |
| PowerShell.wprp | WPR profile to enable CLR and PowerShell ETW events |
| Invoke-PerfviewPS.ps1 | Script to run perfview and with PowerShell ETW events enabled |

---

### Overview (`test/perf/benchmarks/README.md`)

## Micro Benchmarks

This folder contains micro benchmarks that test the performance of PowerShell Engine.

### Requirement

1. A good suite of benchmarks
   Something that measures only the thing that we are interested in and _produces accurate, stable and repeatable results_.
2. A set of machine with the same configurations.
3. Automation for regression detection.

### Design Decision

1. This project is internal visible to `System.Management.Automation`.
   We want to be able to target some internal APIs to get measurements on specific scoped scenarios,
   such as measuring the time to compile AST to a delegate by the compiler.
2. This project makes `ProjectReference` to other PowerShell assemblies.
   This makes it easy to run benchmarks with the changes made in the codebase.
   To run benchmarks with a specific version of PowerShell,
   just replace the `ProjectReference` with a `PackageReference` to the `Microsoft.PowerShell.SDK` NuGet package of the corresponding version.

### Quick Start

You can run the benchmarks directly using `dotnet run` in this directory:
1. To run the benchmarks in Interactive Mode, where you will be asked which benchmark(s) to run:
   ```
   dotnet run -c Release -f net6.0
   ```

2. To list all available benchmarks ([read more](https://github.com/dotnet/performance/blob/main/docs/benchmarkdotnet.md#Listing-the-Benchmarks)):
   ```
   dotnet run -c Release -f net6.0 --list [flat/tree]
   ```

3. To filter the benchmarks using a glob pattern applied to `namespace.typeName.methodName` ([read more](https://github.com/dotnet/performance/blob/main/docs/benchmarkdotnet.md#Filtering-the-Benchmarks)]):
   ```
   dotnet run -c Release -f net6.0 --filter *script* --list flat
   ```

4. To profile the benchmarked code and produce an ETW Trace file ([read more](https://github.com/dotnet/performance/blob/main/docs/benchmarkdotnet.md#Profiling))
   ```
   dotnet run -c Release -f net6.0 --filter *script* --profiler ETW
   ```

You can also use the function `Start-Benchmarking` from the module [`perf.psm1`](../perf.psm1) to run the benchmarks:
```powershell
Start-Benchmarking [-TargetFramework <string>] [-List <string>] [-Filter <string[]>] [-Artifacts <string>] [-KeepFiles] [<CommonParameters>]

Start-Benchmarking [-TargetPSVersion <string>] [-Filter <string[]>] [-Artifacts <string>] [-KeepFiles] [<CommonParameters>]

Start-Benchmarking -Runtime <string[]> [-Filter <string[]>] [-Artifacts <string>] [-KeepFiles] [<CommonParameters>]
```
Run `Get-Help Start-Benchmarking -Full` to see the description of each parameter.

### Regression Detection

We use the tool [`ResultsComparer`](../dotnet-tools/ResultsComparer) to compare the provided benchmark results.
See the [README.md](../dotnet-tools/ResultsComparer/README.md) for `ResultsComparer` for more details.

The module `perf.psm1` also provides `Compare-BenchmarkResult` that wraps `ResultsComparer`.
Here is an example of using it:

```
/* Detailed source-code truncated for AI context efficiency. */
```

## References

- [Getting started with BenchmarkDotNet](https://benchmarkdotnet.org/articles/guides/getting-started.html)
- [Micro-benchmark Design Guidelines](https://github.com/dotnet/performance/blob/main/docs/microbenchmark-design-guidelines.md)
- [Adam SITNIK: Powerful benchmarking in .NET](https://www.youtube.com/watch?v=pdcrSG4tOLI&t=351s)

---

### Overview (`test/perf/dotnet-tools/README.md`)

## Tools

The tools here are copied from [dotnet/performance](https://github.com/dotnet/performance),
the performance testing repository for the .NET runtime and framework libraries.

- [BenchmarkDotNet.Extensions](https://github.com/dotnet/performance/tree/main/src/harness/BenchmarkDotNet.Extensions)
  - It provides the needed extensions for running benchmarks,
    such as the `RecommendedConfig` which defines the set of recommended configurations for running the dotnet benchmarks.
- [Reporting](https://github.com/dotnet/performance/tree/main/src/tools/Reporting)
  - It provides additional result reporting support
    which may be useful to us when running our benchmarks in lab.
- [ResultsComparer](https://github.com/dotnet/performance/tree/main/src/tools/ResultsComparer)
  - It's a tool for comparing different benchmark results.
    It's very useful to show the regression of new changes by comparing its benchmark results to the baseline results.

---

### Overview (`test/tools/CodeCoverageAutomation/README.md`)

# Code Coverage Automation

The script Start-CodeCoverageRun.ps1 automates the execution of tests and uploading the results to Coveralls.io.

The script is self contained and can be executed on any Windows system which supports Powershell v5.0 or above. It has not been tested on Powershell v6.0.

## Execution

The virtual machine hosting the script has a scheduled task to start the tests at 5 am PDT.

The script follows the steps below:

1. Download the code coverage binaries package from Azure DevOps Windows nightly builds artifacts (CodeCoverage.zip).
2. Download the OpenCover powershell module from Azure DevOps Windows nightly builds artifacts. (OpenCover.zip)
3. Download the tests from Azure DevOps Windows nightly builds artifacts (tests.zip)
4. Download Coveralls.net from [here](https://github.com/csMACnz/coveralls.net/releases/download/0.7.0/coveralls.net.0.7.0.nupkg)
5. Invoke 'Install-OpenCover' to install OpenCover toolset.
6. Invoke 'Invoke-OpenCover' to execute tests.
7. Invoke powershell to get the git commit ID of the downloaded daily build package.
8. Using the commit ID get committer info like, message, author and email using the github REST API.
9. Invoke 'csmacnz.Coveralls.exe' to upload the coverage results to Coveralls.net

The uploaded coverage data can be viewed at: https://coveralls.io/github/PowerShell/PowerShell

---

### Overview (`test/tools/WebListener/README.md`)

# WebListener App

ASP.NET Core app for testing HTTP and HTTPS Requests.

## Run with `dotnet`

```bash
dotnet restore
dotnet publish --output bin --configuration Release
cd bin
dotnet WebListener.dll ServerCert.pfx password 8083 8084 8085 8086
```

**NOTE**: `ServerCert.pfx` is no longer a static asset
and you will need to create your own certificate for this purpose.
The `SelfSignedCertificate` module in the PowerShell Gallery provides this functionality.

The test site can then be accessed via `http://localhost:8083/`, `https://localhost:8084/`, `https://localhost:8085/`, or `https://localhost:8086/`.

The `WebListener.dll` takes 6 arguments:

* The path to the Server Certificate
* The Server Certificate Password
* The TCP Port to bind on for HTTP
* The TCP Port to bind on for HTTPS using TLS 1.2
* The TCP Port to bind on for HTTPS using TLS 1.1
* The TCP Port to bind on for HTTPS using TLS 1.0

## Run With WebListener Module

```powershell
Import-Module .\build.psm1
Publish-PSTestTools
$Listener = Start-WebListener -HttpPort 8083 -HttpsPort 8084 -Tls11Port 8085 -TlsPort 8086

```
## Tests

### / or /Home/

Returns a static HTML page containing links and descriptions of the available tests in WebListener. This can be used as a default or general test where no specific test functionality or return data is required.

### /Auth/Basic/

Provides a mock Basic authentication challenge. If a basic authorization header is sent, then the same results as /Get/ are returned.

```powershell
$credential = Get-Credential
$uri = Get-WebListenerUrl -Test 'Auth' -TestValue 'Basic' -Https
Invoke-RestMethod -Uri $uri -Credential $credential -SkipCertificateCheck
```

```json
{
    "headers":{
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
        "Connection": "Keep-Alive",
        "Authorization": "Basic dGVzdHVzZXI6dGVzdHBhc3N3b3Jk",
        "Host": "localhost:8084"
    },
    "origin": "127.0.0.1",
    "args": {},
    "url": "https://localhost:8084/Auth/Basic"
}
```

### /Auth/Negotiate/

Provides a mock Negotiate authentication challenge. If a basic authorization header is sent, then the same results as /Get/ are returned.

```powershell
$uri = Get-WebListenerUrl -Test 'Auth' -TestValue 'Negotiate' -Https
Invoke-RestMethod -Uri $uri -UseDefaultCredential -SkipCertificateCheck
```

```json
{
    "headers":{
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
        "Connection": "Keep-Alive",
        "Authorization": "Negotiate jjaguasgtisi7tiqkagasjjajvs",
        "Host": "localhost:8084"
    },
    "origin": "127.0.0.1",
    "args": {},
    "url": "https://localhost:8084/Auth/Negotiate"
}
```

### /Auth/NTLM/

Provides a mock NTLM authentication challenge. If a basic authorization header is sent, then the same results as /Get/ are returned.

```powershell
$uri = Get-WebListenerUrl -Test 'Auth' -TestValue 'NTLM' -Https
Invoke-RestMethod -Uri $uri -UseDefaultCredential -SkipCertificateCheck
```

```json
{
    "headers":{
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
        "Connection": "Keep-Alive",
        "Authorization": "NTLM jjaguasgtisi7tiqkagasjjajvs",
        "Host": "localhost:8084"
    },
    "origin": "127.0.0.1",
    "args": {},
    "url": "https://localhost:8084/Auth/NTLM"
}
```

### /Cert/

Returns a JSON object containing the details of the Client Certificate if one is provided in the request.

```powershell
$certificate = Get-WebListenerClientCertificate
$uri = Get-WebListenerUrl -Test 'Cert' -Https
Invoke-RestMethod -Uri $uri -Certificate $certificate
```

Response when certificate is provided in request:

```json
{
  "Status": "OK",
  "IssuerName": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US",
  "SubjectName": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US",
  "NotAfter": "2044-12-26T12:16:46-06:00",
  "Issuer": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US",
  "Subject": "E=randd@adatum.com, CN=adatum.com, OU=R&D, O=A. Datum Corporation, L=Redmond, S=Washington, C=US",
  "NotBefore": "2017-08-10T13:16:46-05:00",
  "Thumbprint": "2DECF1348FF21B780F45D316A039B5EB4C6312F7"
}
```

Response when certificate is not provided in request:

```json
{
  "Status": "FAILED"
}
```

### /Compression/Brotli/

Returns the same results as the Get test with brotli compression.

```powershell
$uri = Get-WebListenerUrl -Test 'Compression' -TestValue 'Brotli'
Invoke-RestMethod -Uri $uri
```

```json
{
  "args": {},
  "origin": "127.0.0.1",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) PowerShell/6.0.0",
    "Host": "localhost:8083"
  },
  "url": "http://localhost:8083/Compression/Brotli"
}
```

### /Compression/Deflate/

Returns the same results as the Get test with deflate compression.

```powershell
$uri = Get-WebListenerUrl -Test 'Compression' -TestValue 'Deflate'
Invoke-RestMethod -Uri $uri
```

```json
{
  "args": {},
  "origin": "127.0.0.1",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) PowerShell/6.0.0",
    "Host": "localhost:8083"
  },
  "url": "http://localhost:8083/Compression/Deflate"
}
```

### /Compression/Gzip/

Returns the same results as the Get test with gzip compression.

```powershell
$uri = Get-WebListenerUrl -Test 'Compression' -TestValue 'Gzip'
Invoke-RestMethod -Uri $uri
```

```json
{
  "args": {},
  "origin": "127.0.0.1",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) PowerShell/6.0.0",
    "Host": "localhost:8083"
  },
  "url": "http://localhost:8083/Compression/Gzip"
}
```

### /Delay/

Returns the same results as the Get test. If a number is supplied, the server will wait that many seconds before returning a response. This can be used to test timeouts.

```powershell
$uri = Get-WebListenerUrl -Test 'Delay' -TestValue '5'
Invoke-RestMethod -Uri $uri
```

After 5 Seconds:

```json
{
  "args": {
  },
  "origin": "127.0.0.1",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT; Windows NT 10.0; en-US) WindowsPowerShell/5.1.15063.608",
    "Host": "localhost:8083"
  },
  "url": "http://localhost:8083/Delay/5"
}
```

### /Delete/

Returns the same results as the Get test. Will only accept the `DELETE` request method.

```powershell
$uri = Get-WebListenerUrl -Test 'Delete'
$Body = @{id = 12345} | ConvertTo-Json -Compress
Invoke-RestMethod -Uri $uri -Body $body -Method 'Delete'
```

```json
{
  "method": "DELETE",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
    "Connection": "Keep-Alive",
    "Host": "localhost:8083",
    "Content-Length": "12"
  },
  "origin": "127.0.0.1",
  "url": "http://localhost:8083/Delete",
  "args": {},
  "data": "{\"id\":12345}"
}
```

### /Dos/

Returns HTML designed to create denial of service against specific RegEx Expressions

#### Image Parsing RegEx

```powershell
$uri = Get-WebListenerUrl -Test 'Dos' -query @{
                dosType='img'
                dosLength='5000'
            }
Invoke-RestMethod -Uri $uri -Body $body -Method 'Delete'
```

Return the following followed by 5,000 spaces.

```html
<img
```

#### Charset Parsing RegEx

```powershell
$uri = Get-WebListenerUrl -Test 'Dos' -query @{
                dosType='charset'
                dosLength='5000'
            }
Invoke-RestMethod -Uri $uri -Body $body -Method 'Delete'
```

Return the following followed by 5,000 spaces.

```html
<meta
```

### /Encoding/Utf8/

Returns page containing UTF-8 data.

```powershell
$uri = Get-WebListenerUrl -Test 'Encoding' -TestValue 'Utf8'
Invoke-RestMethod -Uri $uri
```

### /Get/

Returns a JSON object containing the Request URL, Request Headers, GET Query Fields and Values, and Origin IP. This emulates the functionality of [HttpBin's get test](https://httpbin.org/get).

```powershell
$uri = Get-WebListenerUrl -Test 'Get'
Invoke-RestMethod -Uri $uri -Body @{TestField = 'TestValue'}
```

```json
{
  "origin": "127.0.0.1",
  "url": "http://localhost:8083/Get?TestField=TestValue",
  "method": "GET",
  "args": {
    "TestField": "TestValue"
  },
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
    "Connection": "Keep-Alive",
    "Host": "localhost:8083"
  }
}
```

### /Link/

Returns Link response headers to test paginated results. The endpoint accepts 3 query items:

* `linknumber` - The current link number. This determines the current page. If not supplied or less than 1, this will be set to 1.
* `maxlinks` - The maximum number of links. This determines the last page. If not supplied or less than 1, this will be set to 3.
* `type` - The type of link to return. When not supplied or not in the list below, `default` will be used.
  * `default` - Does not return any special test links and returns `next` link if one is available.
  * `norel` - Returns a Link header that does not include the `rel=` portion. Suppresses `next` link.
  * `nourl` - Returns a Link header that does not include the URI portion. Suppresses `next` link.
  * `malformed` - Returns a malformed Link header. Suppresses `next` link.
  * `multiple` - Returns multiple Link headers instead of a single Link header and returns `next` link if one is available.
  * `nowhitespace` - Returns `default` links without any whitespace between the semicolon and `rel`
  * `extrawhitespace` - Returns `default` links with double whitespace between the semicolon and `rel`

The body will contain the same results as `/Get/` with the addition of the `type`, `linknumber`, and `maxlinks` for the current page.

```powershell
$Query = @{
    linknumber = 1
    maxlinks = 3
    type = 'default'
}
$Uri =  Get-WebListenerUrl -Test 'Link' -Query $Query
Invoke-RestMethod -Uri $uri -FollowRelLink -MaximumFollowRelLink 1
```

Headers:

```none
HTTP/1.1 200 OK
Date: Sat, 06 Jan 2018 14:27:36 GMT
Content-Type: application/json; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
Link: <http://localhost:8083/Link/?maxlinks=3&linknumber=3>; rel="last",<http://localhost:8083/Link/?maxlinks=3&linknumber=1>; rel="first",<http://localhost:8083/Link/?maxlinks=3&linknumber=1>; rel="self",<http://localhost:8083/Link/?maxlinks=3&linknumber=2>; rel="next"
```

Body:

```json
{
    "type": "default",
    "url": "http://localhost:8083/Link/?maxlinks=3&linknumber=1&type=default",
    "maxlinks": 3,
    "linknumber": 1,
    "headers": {
        "User-Agent": "insomnia/5.12.4",
        "Accept": "*/*",
        "Content-Length": "0",
        "Host": "localhost:8083",
        "Content-Type": "application/json"
    },
    "args": {
        "linknumber": "1",
        "maxlinks": "3",
        "type": "default"
    },
    "origin": "127.0.0.1",
    "method": "GET"
}
```

### /Multipart/

#### GET

Provides an HTML form for `multipart/form-data` submission.

#### POST

Accepts a `multipart/form-data` submission and returns a JSON object containing information about the submission including the items and files submitted.

```powershell
$uri = Get-WebListenerUrl -Test 'Multipart'
Invoke-RestMethod -Uri $uri -Body $multipartData -Method 'POST'
```

```json
{
  "Files": [
    {
      "ContentDisposition": "form-data; name=fileData; filename=test.txt",
      "Headers": {
        "Content-Disposition": [
          "form-data; name=fileData; filename=test.txt"
        ],
        "Content-Type": [
          "text/plain"
        ]
      },
      "FileName": "test.txt",
      "Length": 15,
      "ContentType": "text/plain",
      "Name": "fileData",
      "Content": "Test Contents\r\n"
    }
  ],
  "Items": {
    "stringData": [
      "TestValue"
    ]
  },
  "Boundary": "83027bde-fd9b-4ea0-b1ca-a1f661d01ada",
  "Headers": {
    "Content-Type": "multipart/form-data; boundary=\"83027bde-fd9b-4ea0-b1ca-a1f661d01ada\"",
    "Connection": "Keep-Alive",
    "Content-Length": "336",
    "Host": "localhost:8083",
    "User-Agent": "Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) WindowsPowerShell/6.0.0"
  }
}
```

### /Patch/

Returns the same results as the Get test. Will only accept the `PATCH` request method.

```powershell
$uri = Get-WebListenerUrl -Test 'Patch'
$Body = @{id = 12345} | ConvertTo-Json -Compress
Invoke-RestMethod -Uri $uri -Body $body -Method 'Patch'
```

```json
{
  "method": "PATCH",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
    "Connection": "Keep-Alive",
    "Host": "localhost:8083",
    "Content-Length": "12"
  },
  "origin": "127.0.0.1",
  "url": "http://localhost:8083/Patch",
  "args": {},
  "data": "{\"id\":12345}"
}
```

### /Post/

Returns the same results as the Get test. Will only accept the `POST` request method. If the POST request is sent with a forms based content type the body will be interpreted as a form instead of raw data.

```powershell
$uri = Get-WebListenerUrl -Test 'Post'
$Body = @{id = 12345}
Invoke-RestMethod -Uri $uri -Body $body -Method 'Post'
```

```json
{
  "method": "POST",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
    "Connection": "Keep-Alive",
    "Host": "localhost:8083",
    "Content-Type": "application/x-www-form-urlencoded",
    "Content-Length": "8"
  },
  "form": {
    "id": [
      "12345"
    ]
  },
  "origin": "127.0.0.1",
  "url": "http://localhost:8083/Post",
  "args": {}
}
```

Otherwise, the body will be interpreted as raw data.

```powershell
$uri = Get-WebListenerUrl -Test 'Post'
$Body = @{id = 12345} | ConvertTo-Json -Compress
Invoke-RestMethod -Uri $uri -Body $body -Method 'Post' -ContentType 'application/json'
```

```json
{
  "method": "POST",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
    "Connection": "Keep-Alive",
    "Host": "localhost:8083",
    "Content-Type": "application/json",
    "Content-Length": "12"
  },
  "origin": "127.0.0.1",
  "url": "http://localhost:8083/Post",
  "args": {},
  "data": "{\"id\":12345}"
}
```

### /Put/

Returns the same results as the Get test. Will only accept the `PUT` request method.

```powershell
$uri = Get-WebListenerUrl -Test 'Put'
$Body = @{id = 12345} | ConvertTo-Json -Compress
Invoke-RestMethod -Uri $uri -Body $body -Method 'Put'
```

```json
{
  "method": "PUT",
  "headers": {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.15063; en-US) PowerShell/6.0.0",
    "Connection": "Keep-Alive",
    "Host": "localhost:8083",
    "Content-Length": "12"
  },
  "origin": "127.0.0.1",
  "url": "http://localhost:8083/Put",
  "args": {},
  "data": "{\"id\":12345}"
}
```

### /Redirect/

Will `302` redirect to `/Get/`. If a number is supplied, redirect will occur that many times. Can be used to test maximum redirects.
If the `type` query field is supplied the corresponding `System.Net.HttpStatusCode` will be returned instead of `302`.
If `type` is `relative`, the redirect URI will be relative instead of absolute.

```powershell
$uri = Get-WebListenerUrl -Test 'Redirect' -TestValue '2'
Invoke-RestMethod -Uri $uri
```

Request 1:

```none
GET http://localhost:8083/Redirect/2 HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) WindowsPowerShell/6.0.0
Host: localhost:8083
```

Response 1:

```none
HTTP/1.1 302 Found
Date: Fri, 15 Sep 2017 10:46:41 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
Location: /Redirect/1

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/Redirect/1">/Redirect/1</a>.  If not click the link.
```

Request 2:

```none
GET http://localhost:8083/Redirect/1 HTTP/1.1
Connection: Keep-Alive
User-Agent: Mozilla/5.0 (Windows NT; Microsoft Windows 10.0.15063 ; en-US) WindowsPowerShell/6.0.0
Host: localhost:8083
```

Response 2:

```none
HTTP/1.1 302 Found
Date: Fri, 15 Sep 2017 10:46:41 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked
Location: /Get/

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>Redirecting...</title>
<h1>Redirecting...</h1>
<p>You should be redirected automatically to target URL: <a href="/Get/">/Get/</a>.  If not click the link.
```

### /Response/

Will return a response crafted from the query string. The following four fields are supported:

* `body` - a string containing the response body
* `statuscode` - the HTTP Status Code to return
* `contenttype` - The `Content-Type` response header
* `headers` - a JSON string containing response headers. `Content-Type` will be ignored in `headers`. Use `contenttype` instead.
* `responsephrase` - the HTTP response phrase to return

```powershell
$Query = @{
    statsucode = 200
    responsephrase = 'OK'
    contenttype = 'application/json'
    body = '{"key1": "value1"}'
    headers = @{
        "X-Header" = "Response header value"
    } | ConvertTo-Json
}
$Uri =  Get-WebListenerUrl -Test 'Response' -Query $Query
Invoke-RestMethod -Uri $uri
```

Response headers:

```none
Content-Type: application/json
X-Header: Response header value
```

Response Body:

```json
{"key1": "value1"}
```

### /ResponseHeaders/

Will return the response headers passed in query string. The response body will be the supplied headers as a JSON object.

```powershell
$uri = Get-WebListenerUrl -Test 'ResponseHeaders' -Query @{'Content-Type' = 'custom'; 'x-header-01' = 'value01'; 'x-header-02' = 'value02'}
Invoke-RestMethod -Uri $uri
```

Response Headers:

```none
HTTP/1.1 200 OK
Date: Sun, 08 Oct 2017 18:20:38 GMT
Transfer-Encoding: chunked
Server: Kestrel
x-header-02: value02
x-header-01: value01
Content-Type: custom
```

Body:

```json
{
    "Content-Type": "custom",
    "x-header-02": "value02",
    "x-header-01": "value01"
}
```

### /Resume/

This endpoint simulates the download of a 20 byte file with support for resuming with the use of the `Range` HTTP request header.
The bytes returned are numbered 1 to 20 inclusive.
If the `Range` header is greater than 20, the endpoint will return a `416 Requested Range Not Satisfiable` response.
The endpoint also returns an `X-WebListener-Has-Range` response header containing `true` or `false` if the HTTP Request contains a `Range` request header.
The endpoint will also return an `X-WebListener-Request-Range` response header which contains the `Range` header value if one was present.

```powershell
$uri = Get-WebListenerUrl -Test 'Resume'
$response = Invoke-WebRequest -Uri $uri -Headers @{"Range" = "bytes=0-"}
```

Response Headers:

```none
HTTP/1.1 206 PartialContent
Date: Tue, 20 Mar 2018 08:45:42 GMT
Server: Kestrel
X-WebListener-Has-Range: true
X-WebListener-Request-Range: bytes=0-
Content-Length: 20
Content-Type: application/octet-stream
Content-Range: bytes 0-19/20
```

### /Resume/Bytes/{NumberBytes}

This endpoint emulates a partial download of the same 20 bytes provided by the `/Resume/` endpoint.
The endpoint will return `{NumberBytes}` bytes of the 20 bytes.
For example `/Resume/Bytes/5` will return bytes 1 through 5 inclusive of the 20 byte file.

```powershell
$uri = Get-WebListenerUrl -Test 'Resume' -TestValue 'Bytes/5'
$response = Invoke-WebRequest -Uri $uri
```

Response Headers:

```none
HTTP/1.1 200 OK
Date: Tue, 20 Mar 2018 08:50:57 GMT
Server: Kestrel
Content-Length: 5
Content-Type: application/octet-stream
```

### /Resume/NoResume

This endpoint is the same as `/Resume/` with the exception that it ignores the `Range` HTTP request header.
This endpoint always returns the full 20 bytes and a `200` status.
The `X-WebListener-Has-Range` and `X-WebListener-Request-Range` headers are also returned the same as the `/Resume/` endpoint.

```powershell
$uri = Get-WebListenerUrl -Test 'Resume' -TestValue 'NoResume'
$response = Invoke-WebRequest -Uri $uri
```

Response Headers:

```none
HTTP/1.1 200 OK
Date: Tue, 20 Mar 2018 08:48:21 GMT
Server: Kestrel
X-WebListener-Has-Range: false
Content-Length: 20
Content-Type: application/octet-stream
```

### /Retry/{sessionId}/{failureCode}/{failureCount}

This endpoint causes the failure specified by `failureCode` for `failureCount` number of times.
After that a status 200 is returned with body containing the number of times the failure was caused.

```powershell
$response = Invoke-WebRequest -Uri 'http://127.0.0.1:8083/Retry?failureCode=599&failureCount=2&sessionid=100&' -MaximumRetryCount 2 -RetryIntervalSec 1
```

Response Body:

```json
{
  "failureResponsesSent":2,
  "sessionId":100
}
```

---

### Overview (`.github/actions/infrastructure/get-changed-files/README.md`)

# Get Changed Files Action

A reusable composite action that retrieves the list of files changed in a pull request or push event.

## Features

- Supports both `pull_request` and `push` events
- Optional filtering by file pattern
- Returns files as JSON array for easy consumption
- Filters out deleted files (only returns added, modified, or renamed files)
- Handles up to 100 changed files per request

## Usage

### Basic Usage (Pull Requests Only)

```yaml
- name: Get changed files
  id: changed-files
  uses: "./.github/actions/infrastructure/get-changed-files"

- name: Process files
  run: |
    echo "Changed files: ${{ steps.changed-files.outputs.files }}"
    echo "Count: ${{ steps.changed-files.outputs.count }}"
```

### With Filtering

```yaml
# Get only markdown files
- name: Get changed markdown files
  id: changed-md
  uses: "./.github/actions/infrastructure/get-changed-files"
  with:
    filter: '*.md'

# Get only GitHub workflow/action files
- name: Get changed GitHub files
  id: changed-github
  uses: "./.github/actions/infrastructure/get-changed-files"
  with:
    filter: '.github/'
```

### Support Both PR and Push Events

```yaml
- name: Get changed files
  id: changed-files
  uses: "./.github/actions/infrastructure/get-changed-files"
  with:
    event-types: 'pull_request,push'
```

## Inputs

| Name | Description | Required | Default |
|------|-------------|----------|---------|
| `filter` | Optional filter pattern (e.g., `*.md` for markdown files, `.github/` for GitHub files) | No | `''` |
| `event-types` | Comma-separated list of event types to support (`pull_request`, `push`) | No | `pull_request` |

## Outputs

| Name | Description |
|------|-------------|
| `files` | JSON array of changed file paths |
| `count` | Number of changed files |

## Filter Patterns

The action supports simple filter patterns:

- **Extension matching**: Use `*.ext` to match files with a specific extension
  - Example: `*.md` matches all markdown files
  - Example: `*.yml` matches all YAML files

- **Path prefix matching**: Use a path prefix to match files in a directory
  - Example: `.github/` matches all files in the `.github` directory
  - Example: `tools/` matches all files in the `tools` directory

## Example: Processing Changed Files

```yaml
- name: Get changed files
  id: changed-files
  uses: "./.github/actions/infrastructure/get-changed-files"

- name: Process each file
  shell: pwsh
  env:
    CHANGED_FILES: ${{ steps.changed-files.outputs.files }}
  run: |
    $changedFilesJson = $env:CHANGED_FILES
    $changedFiles = $changedFilesJson | ConvertFrom-Json
    
    foreach ($file in $changedFiles) {
      Write-Host "Processing: $file"
      # Your processing logic here
    }
```

## Limitations

- Simple filter patterns only (no complex glob or regex patterns)

## Pagination

The action automatically handles pagination to fetch **all** changed files in a PR, regardless of how many files were changed:

- Fetches files in batches of 100 per page
- Continues fetching until all files are retrieved
- Logs a note when pagination occurs, showing the total file count
- **No file limit** - all changed files will be processed, even in very large PRs

This ensures that critical workflows (such as merge conflict checking, link validation, etc.) don't miss files due to pagination limits.

## Related Actions

- **markdownlinks**: Uses this pattern to get changed markdown files
- **merge-conflict-checker**: Uses this pattern to get changed files for conflict detection
- **path-filters**: Similar functionality but with more complex filtering logic

---

### Overview (`.github/actions/infrastructure/markdownlinks/README.md`)

# Verify Markdown Links Action

A GitHub composite action that verifies all links in markdown files using PowerShell and Markdig.

## Features

- ✅ Parses markdown files using Markdig (built into PowerShell 7)
- ✅ Extracts all link types: inline links, reference links, and autolinks
- ✅ Verifies HTTP/HTTPS links with configurable timeouts and retries
- ✅ Validates local file references
- ✅ Supports excluding specific URL patterns
- ✅ Provides detailed error reporting with file locations
- ✅ Outputs metrics for CI/CD integration

## Usage

### Basic Usage

```yaml
- name: Verify Markdown Links
  uses: ./.github/actions/infrastructure/markdownlinks
  with:
    path: './CHANGELOG'
```

### Advanced Usage

```yaml
- name: Verify Markdown Links
  uses: ./.github/actions/infrastructure/markdownlinks
  with:
    path: './docs'
    fail-on-error: 'true'
    timeout: 30
    max-retries: 2
    exclude-patterns: '*.example.com/*,*://localhost/*'
```

### With Outputs

```yaml
- name: Verify Markdown Links
  id: verify-links
  uses: ./.github/actions/infrastructure/markdownlinks
  with:
    path: './CHANGELOG'
    fail-on-error: 'false'

- name: Display Results
  run: |
    echo "Total links: ${{ steps.verify-links.outputs.total-links }}"
    echo "Passed: ${{ steps.verify-links.outputs.passed-links }}"
    echo "Failed: ${{ steps.verify-links.outputs.failed-links }}"
    echo "Skipped: ${{ steps.verify-links.outputs.skipped-links }}"
```

## Inputs

| Input | Description | Required | Default |
|-------|-------------|----------|---------|
| `path` | Path to the directory containing markdown files to verify | No | `./CHANGELOG` |
| `exclude-patterns` | Comma-separated list of URL patterns to exclude from verification | No | `''` |
| `fail-on-error` | Whether to fail the action if any links are broken | No | `true` |
| `timeout` | Timeout in seconds for HTTP requests | No | `30` |
| `max-retries` | Maximum number of retries for failed requests | No | `2` |

## Outputs

| Output | Description |
|--------|-------------|
| `total-links` | Total number of unique links checked |
| `passed-links` | Number of links that passed verification |
| `failed-links` | Number of links that failed verification |
| `skipped-links` | Number of links that were skipped |

## Excluded Link Types

The action automatically skips the following link types:

- **Anchor links** (`#section-name`) - Would require full markdown parsing
- **Email links** (`mailto:user@example.com`) - Cannot be verified without sending email

## GitHub Workflow Test

This section provides a workflow example and instructions for testing the link verification action.

### Testing the Workflow

To test that the workflow properly detects broken links:

1. Make change to this file (e.g., this README.md file already contains one in the [Broken Link Test](#broken-link-test) section)
1. The workflow will run and should fail, reporting the broken link(s)
1. Revert your change to this file
1. Push again to verify the workflow passes

### Example Workflow Configuration

```yaml
name: Verify Links

on:
  push:
    branches: [ main ]
    paths:
      - '**/*.md'
  pull_request:
    branches: [ main ]
    paths:
      - '**/*.md'
  schedule:
    # Run weekly to catch external link rot
    - cron: '0 0 * * 0'

jobs:
  verify-links:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Verify CHANGELOG Links
        uses: ./.github/actions/infrastructure/markdownlinks
        with:
          path: './CHANGELOG'
          fail-on-error: 'true'

      - name: Verify Documentation Links
        uses: ./.github/actions/infrastructure/markdownlinks
        with:
          path: './docs'
          fail-on-error: 'false'
          exclude-patterns: '*.internal.example.com/*'
```

## How It Works

1. **Parse Markdown**: Uses `Parse-MarkdownLink.ps1` to extract all links from markdown files using Markdig
2. **Deduplicate**: Groups links by URL to avoid checking the same link multiple times
3. **Verify Links**:
   - HTTP/HTTPS links: Makes HEAD/GET requests with configurable timeout and retries
   - Local file references: Checks if the file exists relative to the markdown file
   - Excluded patterns: Skips links matching the exclude patterns
4. **Report Results**: Displays detailed results with file locations for failed links
5. **Set Outputs**: Provides metrics for downstream steps

## Error Output Example

```
✗ FAILED: https://example.com/broken-link - HTTP 404
    Found in: /path/to/file.md:42:15
    Found in: /path/to/other.md:100:20

Link Verification Summary
============================================================
Total URLs checked: 150
Passed: 145
Failed: 2
Skipped: 3

Failed Links:
  • https://example.com/broken-link
    Error: HTTP 404
    Occurrences: 2
```

## Requirements

- PowerShell 7+ (includes Markdig)
- Runs on: `ubuntu-latest`, `windows-latest`, `macos-latest`

## Broken Link Test

- [Broken Link](https://github.com/PowerShell/PowerShell/wiki/NonExistentPage404)

## License

Same as the PowerShell repository.

---

### Overview (`.github/actions/infrastructure/merge-conflict-checker/README.md`)

# Merge Conflict Checker

This composite GitHub Action checks for Git merge conflict markers in files changed in pull requests.

## Purpose

Automatically detects leftover merge conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) in pull request files to prevent them from being merged into the codebase.

## Usage

### In a Workflow

```yaml
- name: Check for merge conflict markers
  uses: "./.github/actions/infrastructure/merge-conflict-checker"
```

### Complete Example

```yaml
jobs:
  merge_conflict_check:
    name: Check for Merge Conflict Markers
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    permissions:
      pull-requests: read
      contents: read
    steps:
      - name: checkout
        uses: actions/checkout@v5

      - name: Check for merge conflict markers
        uses: "./.github/actions/infrastructure/merge-conflict-checker"
```

## How It Works

1. **File Detection**: Uses GitHub's API to get the list of files changed in the pull request
2. **Marker Scanning**: Reads each changed file and searches for the following markers:
   - `<<<<<<<` (conflict start marker)
   - `=======` (conflict separator)
   - `>>>>>>>` (conflict end marker)
3. **Result Reporting**: 
   - If markers are found, the action fails and lists all affected files
   - If no markers are found, the action succeeds

## Outputs

- `files-checked`: Number of files that were checked
- `conflicts-found`: Number of files containing merge conflict markers

## Behavior

- **Event Support**: Only works with `pull_request` events
- **File Handling**:
  - Checks only files that were added, modified, or renamed
  - Skips deleted files
  - **Filters out `*.cs` files** (C# files are excluded from merge conflict checking)
  - Skips binary/unreadable files
  - Skips directories
- **Empty File List**: Gracefully handles cases where no files need checking (e.g., PRs that only delete files)

## Example Output

When conflict markers are detected:

```
❌ Merge conflict markers detected in the following files:
  - src/example.cs
    Markers found: <<<<<<<, =======, >>>>>>>
  - README.md
    Markers found: <<<<<<<, =======, >>>>>>>

Please resolve these conflicts before merging.
```

When no markers are found:

```
✅ No merge conflict markers found
```

## Integration

This action is integrated into the `linux-ci.yml` workflow and runs automatically on all pull requests to ensure code quality before merging.

---

### Overview (`src/System.Management.Automation/engine/ComInterop/README.md`)

# ComInterop

The ComInterop code shipped in PowerShell comes from [dotnet/runtime](https://github.com/dotnet/runtime) with _a considerable amount of refactoring work_ to make it work properly with PowerShell.

> **NOTE: Do not modify the ComInterop code unless for fixing a bug. We want to keep minimal diffs when comparing with the .NET 5.0 ComInterop code base.**

There are 3 sources of the ComInterop code as our references:

1. [The .NET Framework version](https://github.com/IronLanguages/main/tree/ipy-2.7-maint/Runtime/Microsoft.Dynamic/ComInterop).
   The code was archived in 2012.

2. [The .NET 5.0 version](https://github.com/dotnet/runtime/tree/master/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/ComInterop).
   It was merged into .NET 5.0 in May 2020 through the PR [dotnet/runtime#33060](https://github.com/dotnet/runtime/pull/33060).
   It's based on the .NET Framework version code with quite amount of refactoring work.

3. [The legacy ComInterop code from Windows PowerShell](https://github.com/PowerShell/PowerShell/tree/v7.0.0/src/System.Management.Automation/engine/ComInterop).
   The legacy code has always been in the repository, but it was excluded from compilation.
   It was based on the .NET Framework version code with a considerable amount of refactoring work to make it work properly with Windows PowerShell.

## Code Refreshing

The ComInterop code was refreshed and enabled in compilation in PowerShell 7.1, August 2020.
It was done manually by:

- A careful **three-way comparison** across all the code sources listed above:
  - Compare (3) to (1) to get the PowerShell specific changes
  - Compare (2) to (1) to get the .NET 5.0 changes

- Applying the PowerShell specific changes from (3) to (2), with necessary further refactoring

- A careful review of the new PowerShell specific changes applied to (2), again using the three-way comparison:
  - Compare the refreshed ComInterop code with (3) to get the differences
  - Analyze the differences to make sure they are either the pure .NET 5.0 changes over the .NET Framework code,
    or the refactoring changes that is necessary to apply the PowerShell specific changes.

## Code Layout Changes

The major changes in code layout are recorded below.

### Removed Source Files

The following source files that existed in (1) and (3) were removed in (2):

```none
ComDispIds.cs
ComEventSink.cs
ComEventSinkProxy.cs
ComParamDesc.cs
ComType.cs
ComTypeLibInfo.cs
ComTypeLibMemberDesc.cs
TypeLibInfoMetaObject.cs
```

I examined them all and it was mainly a clean-up work done in .NET 5.0:

- The code in `ComParamDesc.cs`, `ComType.cs`, `ComTypeLibInfo.cs`, `ComTypeLibMemberDesc.cs` and `TypeLibInfoMetaObject.cs`
  are not used or not needed, and thus removed.
- The code in `ComDispIds.cs`, `ComEventSink.cs` and `ComEventSinkProxy.cs` were moved or refactored to different files.

### New Source Files

Some source files were refactored and moved to the `System.Runtime.InteropServices` namespace in .NET 5.0,
they can be found [here](https://github.com/dotnet/runtime/tree/master/src/libraries/Common/src/System/Runtime/InteropServices).
In PowerShell, the corresponding source files are placed under `engine\ComInterop\InteropServices`.

Additionally, `ComEventsSink.Extended.cs` and `Variant.Extended.cs` under `engine\ComInterop` are new in .NET 5.0.
Combined with the files `ComEventsSink.cs` and `Variant.cs` under `engine\ComInterop\InteropServices`,
they are the refactored replacement of the old `ComEventSink.cs`, `ComEventSinkProxy.cs` and `Variant.cs` files in .NET Framework.

---

### Overview (`test/perf/dotnet-tools/ResultsComparer/README.md`)

# Results Comparer

This simple tool allows for easy comparison of provided benchmark results.

It can be used to compare:
* historical results (eg. before and after my changes)
* results for different OSes (eg. Windows vs Ubuntu)
* results for different CPU architectures (eg. x64 vs ARM64)
* results for different target frameworks (eg. .NET Core 3.1 vs 5.0)

All you need to provide is:
* `--base` - path to folder/file with baseline results
* `--diff` - path to folder/file with diff results
* `--threshold`  - threshold for Statistical Test. Examples: 5%, 10ms, 100ns, 1s

Optional arguments:
* `--top` - filter the diff to top/bottom `N` results
* `--noise` - noise threshold for Statistical Test. The difference for 1.0ns and 1.1ns is 10%, but it's just a noise. Examples: 0.5ns 1ns. The default value is 0.3ns.
* `--csv` - path to exported CSV results. Optional.
* `-f|--filter` - filter the benchmarks by name using glob pattern(s). Optional.

Sample: compare the results stored in `C:\results\windows` vs `C:\results\ubuntu` using `1%` threshold and print only TOP 10.

```cmd
dotnet run --base "C:\results\windows" --diff "C:\results\ubuntu" --threshold 1% --top 10
```

**Note**: the tool supports only `*full.json` results exported by BenchmarkDotNet. This exporter is enabled by default in this repository.

## Sample results

| Slower                                                          | diff/base | Base Median (ns) | Diff Median (ns) | Modality|
| --------------------------------------------------------------- | ---------:| ----------------:| ----------------:| -------:|
| PerfLabTests.BlockCopyPerf.CallBlockCopy(numElements: 100)      |      1.60 |             9.22 |            14.76 |         |
| System.Tests.Perf_String.Trim_CharArr(s: "Test", c: [' ', ' ']) |      1.41 |             6.18 |             8.72 |         |

| Faster                              | base/diff | Base Median (ns) | Diff Median (ns) | Modality|
| ----------------------------------- | ---------:| ----------------:| ----------------:| -------:|
| System.Tests.Perf_Array.ArrayCopy3D |      1.31 |           372.71 |           284.73 |         |

If there is no difference or if there is no match (we use full benchmark names to match the benchmarks), then the results are omitted.

---

### Overview (`test/tools/Modules/UnixSocket/README.md`)

# UnixSocket Module

A PowerShell module for managing the UnixSocket App.

## Running UnixSocket

```powershell
Import-Module .\build.psm1
Publish-PSTestTools
$Listener = Start-UnixSocket
```

## Stopping UnixSocket

```powershell
Stop-UnixSocket
```

---

### Overview (`test/tools/Modules/WebListener/README.md`)

# WebListener Module

A PowerShell module for managing the WebListener App.

When the WebListener is started from this module,
it will automatically generate two fresh certificates,
`ClientCert.pfx` and `ServerCert.pfx` using the `SelfSignedCertificate` module.

The generated Self-Signed Certificate `ServerCert.pfx` has a randomly generated password
and is issued for the Client and Server Authentication key usages.
This certificate is used by the WebListener App for SSL/TLS.

The generated Self-Signed Certificate `ClientCert.pfx` has a randomly generated password
and is not issued for any specific key usage.
This Certificate is used for Client Certificate Authentication with the WebListener App.
The port used for `-HttpsPort` will use TLS 1.2.

# Running WebListener

```powershell
Import-Module .\build.psm1
Publish-PSTestTools
$Listener = Start-WebListener -HttpPort 8083 -HttpsPort 8084 -Tls11Port 8085 -TlsPort 8086
```

# Stopping WebListener

```powershell
Stop-WebListener
```

---

### DOCSMIGRATION (`docs/DOCSMIGRATION.md`)

# Documentation Migration

The docs folder in this repository contains documentation about the PowerShell source code and build
environment.

User-focused documentation has been moved to the [MicrosoftDocs/PowerShell-Docs][01] repository.

The files from the `learning-powershell` folder have been removed from this repository. This list
provides links to suitable replacements.

- **create-powershell-scripts.md**
  - [about_Scripts][06]
- **debugging-from-commandline.md**
  - [about_Debuggers][04]
- **powershell-beginners-guide.md**
  - [PowerShell 101][09]
- **README.md**
  - [Install PowerShell on Windows, Linux, and macOS][07]
  - [Using Visual Studio Code (VS Code)][11]
  - [Pester Guides][02]
  - [Writing Pester Tests Guidelines][03]
  - [PowerShell learning resources][08]
- **working-with-powershell-objects.md**
  - [about_Object_Creation][05]
  - [Crescendo overview][10]


[01]: https://github.com/MicrosoftDocs/PowerShell-Docs
[02]: https://github.com/pester/Pester
[03]: https://github.com/PowerShell/PowerShell/blob/master/docs/testing-guidelines/WritingPesterTests.md
[04]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_debuggers
[05]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_object_creation
[06]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_scripts
[07]: https://learn.microsoft.com/powershell/scripting/install/installing-powershell
[08]: https://learn.microsoft.com/powershell/scripting/learn/more-powershell-learning
[09]: https://learn.microsoft.com/powershell/scripting/learn/ps101/00-introduction
[10]: https://learn.microsoft.com/powershell/utility-modules/crescendo/overview?view=ps-modules
[11]: https://learn.microsoft.com/powershell/scripting/dev-cross-plat/vscode/using-vscode

---

### FAQ (`docs/FAQ.md`)

# Frequently Asked Questions

## Where can I learn PowerShell's syntax?

- [What is PowerShell?][12]
- [Discover PowerShell][09]
- [PowerShell 101][11]
- [PowerShell learning resources][10]

## What are the best practices and styles?

The [PoshCode][03] unofficial guide is our reference.

## What are PowerShell's scoping rules?

- Variables are created in your current scope unless explicitly indicated.
- Variables are visible in a child scope unless explicitly indicated.
- Variables created in a child scope are not visible to a parent unless explicitly indicated.
- Variables may be placed explicitly in a scope.

### Things that create a scope

- [about_Functions_Advanced][04]
- [about Operators - Call operator][06] (`& { }`)
- [about Scopes][08]

### Things that operate in the current scope

- [about Operators - Dot source operator][07] (`. { }`)
- [about Language Keywords][05] (`if .. else`, `for`, `switch`, etc.)

## Why didn't an error throw an exception?

Error handling in PowerShell is unique, as not all errors result in catchable exceptions by default.
Setting `$ErrorActionPreference = 'Stop'` will likely do what you want; that is, cause
non-terminating errors instead of terminating. Read the [GitHub issue][02] for more information.

## Where do I get the PowerShell Core SDK package?

The SDK NuGet package **Microsoft.PowerShell.SDK** is provided for developers to write C# code
targeting PowerShell. PowerShell NuGet packages are published to [Microsoft.PowerShell.SDK][13] on
NuGet.org.

To use the `Microsoft.PowerShell.SDK` NuGet package, declare `PackageReference` tags in your
`.csproj` file as follows:

```xml
<ItemGroup>
  <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.3.5" />
  <PackageReference Include="Microsoft.PowerShell.Commands.Diagnostics" Version="7.3.5" />
  <PackageReference Include="Microsoft.WSMan.Management" Version="7.3.5"/>
</ItemGroup>
```

## Why did my build fail?

There are few common issues with the build. The easiest way to resolve most issues with the build is
to run `Start-PSBuild -Clean`.

### Dependency changed

If package dependencies were changed in any `project.json`, you need to manually run
`dotnet restore` to update your local dependency graphs. `Start-PSBuild -Restore` can automatically
do this.

### Resource changed

`Start-PSBuild` automatically calls `Start-ResGen` on the very first run. On subsequent runs, you
may need to explicitly use `Start-PSBuild -ResGen` command.

Try it, when you see compilation error about *strings.

[More details][01] about resource.

### TypeGen

Similar to `-ResGen` parameter, there is `-TypeGen` parameter that triggers regeneration of type
catalog.

## Why did `Start-PSBuild` tell me to update `dotnet`?

We depend on the latest version of the .NET CLI, as we use the output of `dotnet --info` to
determine the current runtime identifier. Without this information, our build function can't know
where `dotnet` is going to place the build artifacts.

You can automatically install this using `Start-PSBootstrap`.
**However, you must first manually uninstall other versions of the CLI.**

If you have installed by using any of the following means:

- `MSI`
- `exe`
- `apt-get`
- `pkg`

You *must* manually uninstall it.

Additionally, if you've just unzipped their binary drops (or used their obtain scripts, which do
essentially the same thing), you must manually delete the folder, as the .NET CLI team re-engineered
how their binaries are setup, such that new packages' binaries get stomped on by old packages'
binaries.


[01]: dev-process/resx-files.md
[02]: https://github.com/MicrosoftDocs/PowerShell-Docs/issues/1583
[03]: https://github.com/PoshCode/PowerShellPracticeAndStyle
[04]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_functions_advanced
[05]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_language_keywords
[06]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_operators#call-operator-
[07]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_operators#dot-sourcing-operator-
[08]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_scopes
[09]: https://learn.microsoft.com/powershell/scripting/discover-powershell
[10]: https://learn.microsoft.com/powershell/scripting/learn/more-powershell-learning
[11]: https://learn.microsoft.com/powershell/scripting/learn/ps101/00-introduction
[12]: https://learn.microsoft.com/powershell/scripting/overview
[13]: https://www.nuget.org/packages/Microsoft.PowerShell.SDK

---

### Building Internals (`docs/building/internals.md`)

# Internals of build process

The purpose of this document is to explain build process **internals** with subtle nuances.
This document is not by any means complete.
The ultimate source of truth is the code in `.\build.psm1` that's getting executed on the corresponding CI system.

This document assumes that you can successfully build PowerShell from sources for your platform.

## Top directory

We are calling `dotnet` tool build for `$Top` directory

- `src\powershell-win-core` for CoreCLR on Windows.
- `src\powershell-unix` for CoreCLR on Linux and macOS.

### Dummy dependencies

We use dummy dependencies between projects to leverage `dotnet` build functionality.
For example, `src\powershell-win-core\powershell-win-core.csproj` has dependency on `Microsoft.PowerShell.Commands.Diagnostics.csproj`,
but in reality, there is no build dependency.

Dummy dependencies allow us to build just `$Top` folder, instead of building several folders.

### Dummy dependencies rules

If assembly is part of CoreCLR build,
it should be listed as a dependency for `$Top` folder (`src\powershell-unix` or `src\powershell-win-core`)

## Preliminary steps

### Bundled modules and early-access feeds

The package references in [`PSGalleryModules.csproj`](../../src/Modules/PSGalleryModules.csproj)
select the bundled module versions. Their restore sources are configured in
[`src/Modules/nuget.config`](../../src/Modules/nuget.config), not in the project file.

`Switch-PSNugetConfig -Source Private -UseEarlyAccessModules` enables the
`powershell-module-earlyaccess` Azure Artifacts feed alongside the existing PowerShell
feed for released modules. The `UseEarlyAccessModules` switch is independent of
the .NET feed selected by `Source` and can be used with any source mode.
Without the switch, bundled modules use only the normal module source.
For public source modes, the normal module source is PowerShell Gallery.
Update a module's package-reference version to consume an internal version.
Internal versions should be distinct from released versions because NuGet caches packages by ID and version.

In Azure Pipelines, enable the `UseEarlyAccessModules` build parameter (default: `false`).
This does not require `IsEarlyAccess`, `EARLY_ACCESS_FEED`, or an early-access .NET SDK.
The flags can also be enabled together. The shared
[`insert-nuget-config-azfeed.yml`](../../.pipelines/templates/insert-nuget-config-azfeed.yml)
template installs the Azure Artifacts Credential Provider and supplies an Azure DevOps
access token through the secret `VSS_NUGET_EXTERNAL_FEED_ENDPOINTS` variable.
The `powershell-net-early-access` service connection identity must have read access
to the module feed. The existing PowerShell feed continues to use its separate PAT.
For local restores, install the Azure Artifacts Credential Provider and use
`Restore-PSPackage -ProjectDirs .\src\Modules -PSModule -Force -InteractiveAuth`
with an identity that has read access to both feeds.

### ResGen

Until the .NET CLI `dotnet-resgen` tool supports the generation of strongly typed resource access classes
(tracked by [Microsoft/msbuild #2272](https://github.com/Microsoft/msbuild/issues/2272)),
we run our own C# [ResGen tool](../../src/ResGen).
While the `Start-PSBuild` command runs this automatically via the `Start-ResGen` function,
it does *not* require PowerShell.
The same command can be run manually:

```sh
cd src/ResGen
dotnet restore
dotnet run
```

Running the program does the following work:

- For each project, given a `resources` folder, create a `gen` folder.
- For each `*.resx` file from the `resources` folder,
  create a strongly typed C# resource access class,
  and write it to the corresponding `*.cs` file in the `gen` folder.

These files are *not* automatically updated on each build,
as the project lacks the ability to detect changes.
Thus, running it for every build would break incremental recompilation.

If you pull new commits and get an error about missing strings,
you likely need to delete the `gen` folders and re-run the tool.

### Type Catalog

A pre-generated catalog of C# types is used in PowerShell to help type resolution.
Generating this catalog is a pre-build step that is run via `Start-TypeGen`,
which `Start-PSBuild` calls.
Again, however, PowerShell is not required.
The necessary steps can be run manually:

```sh
cd ../TypeCatalogGen
dotnet restore
dotnet run ../System.Management.Automation/CoreCLR/CorePsTypeCatalog.cs powershell.inc
```

The file `powershell.inc` is generated by running a custom MSBuild target.
`Start-TypeGen` handles generating this file,
but you can also do it manually by navigating to the `src` directory and running the following commands:

```sh
targetFile="Microsoft.PowerShell.SDK/obj/Microsoft.PowerShell.SDK.csproj.TypeCatalog.targets"
cat > $targetFile <<-"EOF"
<Project>
    <Target Name="_GetDependencies"
            DependsOnTargets="ResolveAssemblyReferencesDesignTime">
        <ItemGroup>
            <_RefAssemblyPath Include="%(_ReferencesFromRAR.HintPath)%3B"  Condition=" '%(_ReferencesFromRAR.NuGetPackageId)' != 'Microsoft.Management.Infrastructure' "/>
        </ItemGroup>
        <WriteLinesToFile File="$(_DependencyFile)" Lines="@(_RefAssemblyPath)" Overwrite="true" />
    </Target>
</Project>
EOF
dotnet msbuild Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj /t:_GetDependencies "/property:DesignTimeBuild=true;_DependencyFile=$(pwd)/TypeCatalogGen/powershell.inc" /nologo
```

`powershell.inc` contains the resolved paths to the DLLs of each dependency of PowerShell,
and is taken as input to the [`TypeCatalogGen`](../../src/TypeCatalogGen) tool,
which generates the source file `CorePsTypeCatalog.cs` for the `System.Management.Automation` project.

The error `The name 'InitializeTypeCatalog' does not exist in the current context`
indicates that the `CorePsTypeCatalog.cs` source file does not exist,
so follow the steps to generate it.

## Native Components

On Windows, PowerShell Core depends on the WinRM plugin `pwrshplugin.dll` to enable remoting over WinRM.
On Linux/macOS, PowerShell Core depends on the binary `libpsl-native.so/libpsl-native.dylib` to provide some necessary supports.

Building those native components requires setting up additional dependencies,
which could be a burden to those who don't seek to make changes to the native components.
In the meantime, the native component code seldom changes,
so it doesn't make sense to always build them with `Start-PSBuild`.
Therefore, we decided to wrap the native components into NuGet packages,
so that we only need to build them once when changes are made,
and then reuse the produced binaries for many builds subsequently.

The NuGet package for `pwrshplugin.dll` is `psrp.windows`,
and the NuGet package for `libpsl-native` is `libpsl`.

### Windows packages: PSRP.Windows and PowerShell.Core.Instrumentation

To build `pwrshplugin.dll` and `PowerShell.Core.Instrumentation.dll`, you need to install Visual Studio 2017 and run `Start-PSBootstrap -BuildWindowsNative` to install the prerequisites.

Ensure the following individual components are selected:

- [ ] VC++ 2017 v141 toolset (x86, x64)
- [ ] Visual C++ compilers and libraries for ARM
- [ ] Visual C++ compilers and libraries for ARM64
- [ ] Visual C++ tools for CMake
- [ ] Visual C++ ATL Support
- [ ] Windows 10 SDK (10.0.16299.0) for Desktop C++ (ARM and ARM64)
- [ ] Windows 10 SDK (10.0.16299.0) for Desktop C++ (x86 and x64)

Ensure [CMake](https://cmake.org/download/) 3.10.0 or newer is installed which supports VS2017 and ARM64 generator.

Then run `Start-BuildNativeWindowsBinaries` to build the binary.
For example, the following builds the release flavor of the binary targeting arm64 architecture.

```powershell
Start-BuildNativeWindowsBinaries -Configuration Release -Arch x64_arm64
```

Be sure to build and test for all supported architectures: `x86`, `x64`, `x64_arm`, and `x64_arm64`.

The `x64_arm` and `x64_arm64` architectures mean that the host system needs to be x64 to cross-compile to ARM.
When building for multiple architectures, be sure to use the `-clean` switch as cmake will cache the previous run and the wrong compiler will be used to generate the subsequent architectures.

After that, the binary `pwrshplugin.dll`, its PDB file, and `powershell.core.instrumentation.dll` will be placed under `src\powershell-win-core`.

To create a new NuGet package for `pwrshplugin.dll`, first you need to get the `psrp.windows.nuspec` from an existing `psrp.windows` package.
You can find it at `~/.nuget/packages/psrp.windows` on your windows machine if you have recently built PowerShell on it.
Or you can download the existing package from [powershell-core feed](https://powershell.myget.org/feed/powershell-core/package/nuget/psrp.windows).
Once you get `psrp.windows.nuspec`, copy it to an empty folder and update the `<version>` element.

After building successfully, copy the produced files to the same folder,
and create the same layout of files as in the existing package.
The layout of files should look like this:

```none
\---runtimes
    +---win-x64
    |   \---native
    |           pwrshplugin.dll
    |           pwrshplugin.pdb
    |
    +---win-x86
    |   \---native
    |           pwrshplugin.dll
    |           pwrshplugin.pdb
    +---win-arm
    |   \---native
    |           pwrshplugin.dll
    |           pwrshplugin.pdb
    \---win-arm64
        \---native
                pwrshplugin.dll
                pwrshplugin.pdb
```

Have the DLLs signed with `authenticode dual` certificate and run `nuget pack` from the parent of the `runtimes` folder where `psrp.windows.nuspec` resides.
Be sure to use the latest recommended version of [nuget.exe](https://www.nuget.org/downloads).

Publish the latest nupkg to https://powershell.myget.org/feed/powershell-core/package/nuget/psrp.windows.

`PowerShell.Core.Instrumentation.dll` NuGet package is created the same way, but in a separate directory following the same layout above.
To create a new NuGet package for `PowerShell.Core.Instrumentation.dll`, you will need the `PowerShell.Core.Instrumentation.nuspec` found in the repo under `src\PowerShell.Core.Instrumentation`.

Publish the latest nupkg to https://powershell.myget.org/feed/powershell-core/package/nuget/PowerShell.Core.Instrumentation.

### libpsl

For `linux-arm`, you need to run `Start-PSBootstrap -BuildLinuxArm` to install additional prerequisites to build `libpsl-native`.
Note that currently you can build `linux-arm` only on a Ubuntu machine.

For `linux-x64` and macOS, the initial run of `Start-PSBootstrap` would be enough -- no additional prerequisite required.

After making sure the prerequisites are met, run `Start-BuildNativeUnixBinaries` to build the binary:

```powershell
## Build targeting linux-x64 or macOS
Start-BuildNativeUnixBinaries

## Build targeting linux-arm
Start-BuildNativeUnixBinaries -BuildLinuxArm
```

After the build succeeds, the binary `libpsl-native.so` (`libpsl-native.dylib` on macOS) will be placed under `src/powershell-unix`.

To create a new NuGet package for `libpsl-native`, first you need to get the `libpsl.nuspec` from an existing `libpsl` package.
You can find it at `~/.nuget/packages/libpsl` on your Linux or macOS machine if you have recently built PowerShell on it.
Or you can download the existing package from [powershell-core feed](https://powershell.myget.org/feed/powershell-core/package/nuget/libpsl).
Once you get `psrp.windows.nuspec`, copy it to an empty folder on your Windows machine.

Then you need to build three binaries of `libpsl-native` targeting `linux-x64`, `linux-arm` and `osx` respectively.
**Please note that, in order for the `linux-x64` binary `libpsl-native.so` to be portable to all other Linux distributions,
the `linux-x64` binary needs to be built on CentOS 7**
(.NET Core Linux native binaries are also built on CentOS 7  to ensure that they don't depend on newer `glibc`).

After building successfully, copy those three binaries to the same folder,
and create the same layout of files as in the existing package.
The layout of files should look like this:

```none
└── runtimes
    ├── linux-arm
    │   └── native
    │       └── libpsl-native.so
    ├── linux-x64
    │   └── native
    │       └── libpsl-native.so
    └── osx
        └── native
            └── libpsl-native.dylib
```

Lastly, run `nuget pack .` from within the folder. Note that you may need the latest `nuget.exe`.

---

### Building Linux (`docs/building/linux.md`)

# Build PowerShell on Linux

This guide will walk you through building PowerShell on Linux.
We'll start by showing how to set up your environment from scratch.

## Environment

These instructions are written assuming Ubuntu 24.04 LTS (the CI uses ubuntu-latest).
The build module works on a best-effort basis for other distributions.

### Git Setup

Using Git requires it to be set up correctly;
refer to the [Working with the PowerShell Repository](../git/README.md),
[Readme](../../README.md), and [Contributing Guidelines](../../.github/CONTRIBUTING.md).

**This guide assumes that you have recursively cloned the PowerShell repository and `cd`ed into it.**

### Toolchain Setup

We use the [.NET Command-Line Interface][dotnet-cli] (`dotnet`) to build the managed components.

Installing the toolchain is as easy as running `Start-PSBootstrap` in PowerShell.
Of course, this requires a self-hosted copy of PowerShell on Linux.

Fortunately, this is as easy as [downloading and installing the package](https://learn.microsoft.com/en-us/powershell/scripting/install/install-other-linux#binary-archives).
The `./tools/install-powershell.sh` script will also install the PowerShell package.

In Bash:

```sh
./tools/install-powershell.sh

pwsh
```

You should now be in a PowerShell console host that is installed.
Just import our module, bootstrap the dependencies, and build!

In PowerShell:

```powershell
Import-Module ./build.psm1
Start-PSBootstrap -Scenario Both
```

The `Start-PSBootstrap` function does the following:

- Installs build dependencies and packaging tools via `apt-get` (or equivalent package manager)
- Downloads and installs the .NET SDK (currently version 10.0.100-rc.1) to `~/.dotnet`

If you want to use `dotnet` outside of `Start-PSBuild`, add `~/.dotnet` to your `PATH` environment variable.

[dotnet-cli]: https://learn.microsoft.com/dotnet/core/tools/

## Build using our module

We maintain a [PowerShell module](../../build.psm1) with the function `Start-PSBuild` to build PowerShell.
Since this is PowerShell code, it requires self-hosting.
If you have followed the toolchain setup section above, you should have PowerShell Core installed.

```powershell
Import-Module ./build.psm1
Start-PSBuild -UseNuGetOrg
```

> The PowerShell project by default references packages from the private Azure Artifacts feed, which requires authentication. The `-UseNuGetOrg` flag reconfigures the build to use the public NuGet.org feed instead.

Congratulations! If everything went right, PowerShell is now built.
The `Start-PSBuild` script will output the location of the executable:

`./src/powershell-unix/bin/Debug/net11.0/linux-x64/publish/pwsh`.

You should now be running the PowerShell Core that you just built, if you run the above executable.
You can run our cross-platform Pester tests with `Start-PSPester -UseNuGetOrg`, and our xUnit tests with `Start-PSxUnit`.

---

### Building Macos (`docs/building/macos.md`)

# Build PowerShell on macOS

This guide supplements the [Linux instructions](./linux.md), as
building on macOS is almost identical.

.NET Core 2.x (and by transitivity, us) only supports macOS 10.13+.

## Environment

You will want [Homebrew](https://brew.sh/) or [MacPorts](https://www.macports.org/), the missing package manager for macOS.
Once installed, follow the same instructions to download and
install a self-hosted copy of PowerShell on your macOS machine.
From `pwsh.exe`, run `Import-Module ./build.psm1` and use `Start-PSBootstrap` to install the dependencies.

The `Start-PSBootstrap` function does the following:

- Uses `brew` or `port` to install OpenSSL, and GNU WGet
- Uninstalls any prior versions of .NET CLI
- Downloads and installs .NET Core SDK to `~/.dotnet`

If you want to use `dotnet` outside of `Start-PSBuild`,
add `~/.dotnet` to your `PATH` environment variable.

### error: Too many open files

Due to a [bug][809] in NuGet, the `dotnet restore` command will fail without the limit increased.
Run `ulimit -n 2048` to fix this in your session;
add it to your shell's profile to fix it permanently.

We cannot do this for you in the build module due to #[847][].

[809]: https://github.com/dotnet/cli/issues/809
[847]: https://github.com/PowerShell/PowerShell/issues/847

## Build using our module

Start a PowerShell session by running `pwsh`, and then use `Start-PSBuild -UseNuGetOrg` from the module.

After building, PowerShell will be at `./src/powershell-unix/bin/Debug/net6.0/osx-x64/publish/pwsh`.

> The PowerShell project by default references packages from the private Azure Artifacts feed, which requires authentication. The `-UseNuGetOrg` flag reconfigures the build to use the public NuGet.org feed instead.

---

### Building Windows Core (`docs/building/windows-core.md`)

# Build PowerShell on Windows for .NET Core

This guide will walk you through building PowerShell on Windows, targeting .NET Core.
We'll start by showing how to set up your environment from scratch.

## Environment

These instructions are tested on Windows 10 and Windows Server 2012
R2, though they should work anywhere the dependencies work.

### Git Setup

Using Git requires it to be set up correctly; refer to the
[Readme](../../README.md) and
[Contributing Guidelines](../../.github/CONTRIBUTING.md).

This guide assumes that you have recursively cloned the PowerShell repository and `cd`ed into it.

### Visual Studio

Install [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/). The Community edition is available free of charge.

The PowerShell/PowerShell repository requires at least Visual Studio 2019 16.7.

### Visual Studio Code

Building PowerShell using [Visual Studio Code](https://code.visualstudio.com/) depends on the PowerShell executable to be called `pwsh` which means
that you must have PowerShell Core 6 Beta.9 (or newer) installed to successfully build this project (typically for the purpose of debugging).

### .NET CLI

We use the [.NET command-line interface][dotnet-cli] (`dotnet`) to build PowerShell.
The version we are currently using is mentioned in [`global.json`](../../global.json#L3) at the root of this repository.
The `Start-PSBootstrap` function will automatically install it and add it to your path:

```powershell
Import-Module ./build.psm1
Start-PSBootstrap -Scenario Dotnet
```

Or you can call `Install-Dotnet` directly:

```powershell
Install-Dotnet
```

It removes the previously installed version of .NET CLI and installs the version that PowerShell Core depends on.
If you have any problems installing `dotnet`, please see their [documentation][cli-docs].

[dotnet-cli]: https://learn.microsoft.com/dotnet/core/tools/
[cli-docs]: https://www.microsoft.com/net/core#windowscmd

## Build using our module

We maintain a [PowerShell module](../../build.psm1) with the function `Start-PSBuild` to build PowerShell.

We do not recommend using Visual Studio Dev Environment Terminal to build the source code.

```powershell
Import-Module ./build.psm1
Start-PSBuild -Clean -PSModuleRestore -UseNuGetOrg
```

> The PowerShell project by default references packages from the private Azure Artifacts feed, which requires authentication. The `-UseNuGetOrg` flag reconfigures the build to use the public NuGet.org feed instead.

Congratulations! If everything went right, PowerShell is now built and executable as `./src/powershell-win-core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe`.

This location is of the form `./[project]/bin/[configuration]/[framework]/[rid]/publish/[binary name]`,
and our project is `powershell`, configuration is `Debug` by default,
framework is `net6.0`, runtime identifier is `win7-x64` by default,
and binary name is `pwsh`.
The function `Get-PSOutput` will return the path to the executable;
thus you can execute the development copy via `& (Get-PSOutput)`.

The `powershell` project is the .NET Core PowerShell host.
It is the top-level project, so `dotnet build` transitively builds all its dependencies,
and emits a `pwsh` executable.
The cross-platform host has built-in documentation via `--help`.

You can run our cross-platform Pester tests with `Start-PSPester`.

```powershell
Import-Module ./build.psm1
Start-PSPester -UseNuGetOrg
```

## Building in Visual Studio

We currently have the issue [#3400](https://github.com/PowerShell/PowerShell/issues/3400) tracking this task.

---

### Cmdlet Example Command Line Simple Example (`docs/cmdlet-example/command-line-simple-example.md`)

# Creating a cross-platform binary module with the .NET Core command-line interface tools

This example uses the [.NET Core command-line interface tools][dotnet-cli] (aka
`dotnet` CLI) to demonstrate how to create a binary module that is portable across operating
systems supported by **PowerShell Core** as well as **Windows PowerShell** version 3 and higher.

Because the binary module's assembly will be created as a .NET Standard 2.0 class library,
the same assembly can be imported into both PowerShell Core and Windows PowerShell.
This means you do not have to build and distribute separate assemblies that target these two
different implementations of PowerShell.

## Prerequisites

* PowerShell Core and/or Windows PowerShell

  For this example, you can use any operating system that is supported by PowerShell Core.
  To see if your operating system is supported and to get instructions on how to install
  PowerShell Core on your operating system, see the [Get PowerShell][pscore-os] topic in
  the PowerShell repo's [README.md][readme] file.

  Note: On Windows 10 Anniversary Update or higher, you can use the [Windows Subsystem for
  Linux][wsl] (WSL) console to build the module. In order to import and use the module, you'll need
  to install PowerShell Core for the distribution and version of Linux you're running.
  You can get that version info by running the command `lsb_release -a` from the WSL console.

* .NET Core 2.x SDK

  Download and install the [.NET Core 2.x SDK][net-core-sdk] for your operating system.
  It is recommended that you use a package manager to install the SDK on Linux.
  See these [instructions][linux-install] on how to install the SDK on Linux.
  Be sure to pick your distribution of Linux e.g. RHEL, Debian, etc to get the
  appropriate instructions for your platform.

## Create the .NET Standard 2.0 Binary Module

1. Verify you are running the 2.0.0 version of the `dotnet` CLI.

   ```powershell
   dotnet --version
   ```

   This should output `2.0.0` or higher. If it returns a major version of 1, make sure you have
   installed the .NET Core 2.x SDK and have restarted your shell to get the newer version of
   the SDK tools.

1. Use the `dotnet` CLI to create a starter `classlib` project based on .NET Standard 2.0
   (the default for classlib projects).

   ```powershell
   dotnet new classlib --name MyModule
   ```

1. Add a `global.json` file that specifies that the project requires the `2.0.0` version of
   the .NET Core SDK.  This is necessary to prevent issues if you have more than one
   version of the .NET Core SDK installed.

   ```powershell
   cd MyModule
   dotnet new globaljson --sdk-version 2.0.0
   ```

1. Add the [PowerShell Standard Library][ps-stdlib] package to the project file.
   This package provides the `System.Management.Automation` assembly.

   Note: As newer versions of this library are released, update the version number
   in this command to match the latest version.

   ```powershell
   dotnet add package PowerShellStandard.Library --version 3.0.0-preview-01
   ```

1. Add source code for a simple PowerShell command to the `Class1.cs` file by opening
   that file in an editor and replacing the existing code with the following code.

   ```csharp
   using System;
   using System.Management.Automation;

   namespace MyModule
   {
       [Cmdlet(VerbsCommunications.Write, "TimestampedMessage")]
       public class WriteTimestampedMessageCommand : PSCmdlet
       {
           [Parameter(Position=1)]
           public string Message { get; set; } = string.Empty;

           protected override void EndProcessing()
           {
               string timestamp = DateTime.Now.ToString("u");
               this.WriteObject($"[{timestamp}] - {this.Message}");
               base.EndProcessing();
           }
       }
   }
   ```

1. Build the project.

   ```powershell
   dotnet build
   ```

1. Import the binary module and invoke the new command.

   Note: The previous steps could have been performed in a different shell such as
   Bash if you're on Linux.  For this step, make sure you are running PowerShell Core.

   ```powershell
   cd 'bin/Debug/netstandard2.0'
   Import-Module ./MyModule.dll
   Write-TimestampedMessage "Test message."
   ```

## Using a .NET Standard 2.0 based binary module in Windows PowerShell

You may have heard that a .NET assembly compiled as a .NET Standard 2.0 class library
will load into both .NET Core 2.x applications such as PowerShell Core and
.NET Framework 4.6.1 (or higher) applications such as Windows PowerShell.
This allows you to build a single, cross-platform binary module.

Unfortunately, this works best when the .NET Framework application, in this case
Windows PowerShell, has either been compiled against a .NET Standard 2.0 library or with
support declared for .NET Standard libraries.  In which case, the build system can provide the
appropriate binding redirects and facade and shim assemblies so that the .NET Standard 2.0
library can find the .NET Framework types it needs within the context of the running
application.

Fortunately, this has been fixed in .NET Framework 4.7.1 and in the Windows 10 Fall
Creators Update. This version of the .NET Framework allows existing applications to
"just work" without the need to modify and/or re-compile them. On these systems, a
.NET Standard 2.0 based binary module will work in Windows PowerShell.

However, for Windows systems that have not been updated to .NET Framework 4.7.1 such a
binary module will not run correctly in Windows PowerShell.

Let's see what happens when you attempt to use this module in **Windows PowerShell** on
Windows 10 CU (1703 or lower) without .NET Framework 4.7.1 installed.

1. Copy `MyModule.dll` to a folder on a Windows machine.

1. Import the module.

   ```powershell
   Import-Module .\MyModule.dll
   ```

   Note: The module should import without errors.

1. Execute the `Write-TimestampedMessage` command.

   ```powershell
   Write-TimestampedMessage "Test message."
   ```

   This will result in the following error:

   ```text
   Write-TimestampedMessage : Could not load file or assembly 'netstandard, Version=2.0.0.0, Culture=neutral,
   PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified.
   At line:1 char:1
   + Write-TimestampedMessage "Test message."
   + ~~~~~~~~~~~~~~~~~~~~~~~~
       + CategoryInfo          : NotSpecified: (:) [], FileNotFoundException
       + FullyQualifiedErrorId : System.IO.FileNotFoundException
   ```

If the command worked, congratulations! Your system was probably updated to
.NET Framework 4.7.1.  Otherwise, this error indicates that the `MyModule.dll` assembly
can't find the `netstandard.dll` "implementation" assembly for the version of the
.NET Framework that Windows PowerShell is using.

### The fix for missing netstandard.dll

If you install (or already have) the .NET Core SDK for Windows, you can
find the `netstandard.dll` implementation assembly for .NET 4.6.1 in the following directory:
`C:\Program Files\dotnet\sdk\<version-number>\Microsoft\Microsoft.NET.Build.Extensions\net461\lib`.
Note that, the version number in the path may vary depending on the installed SDK.

If you copy `netstandard.dll` from this directory to the directory containing
`MyModule.dll`, the `Write-TimestampedMessage` command will work.  Let's try that.

1. Install [.NET Core SDK for Windows][net-core-sdk], if it isn't already installed.

1. Start a new Windows PowerShell console. Remember that once a binary assembly is
   loaded into PowerShell it can't be unloaded. Restarting PowerShell is necessary to
   get it to reload `MyModule.dll`.

1. Copy the `netstandard.dll` implementation assembly for .NET 4.6.1 to the module's directory.

   ```powershell
   cd 'path-to-where-you-copied-module.dll'
   Copy-Item 'C:\Program Files\dotnet\sdk\<version-number>\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll' .
   ```

1. Import the module and execute the command:

   ```powershell
   Import-Module .\MyModule.dll
   Write-TimestampedMessage "Test message."
   ```

   Now the command should succeed.

   Note: If it fails, restart Windows PowerShell to make sure
   you don't have a previously loaded version of the assembly in the session and repeat
   step 4.

If you use additional libraries there may be more work involved. This approach has
been successfully tested using types from `System.Xml` and `System.Web`.

## Wrap-up

In a few steps, we have built a PowerShell binary module using a .NET Standard 2.0
class library that will run in PowerShell Core on multiple operating systems.
It will also run in Windows PowerShell on Windows systems that have been updated to
.NET Framework 4.7.1 as well as the Windows 10 Fall Creators Update which comes with that
version pre-installed.  Furthermore, this binary module can be built on Linux
and macOS as well as Windows using the .NET Core 2.x SDK command-line tools.

For more information on .NET Standard, check out the [documentation][net-std-docs]
and the [.NET Standard YouTube channel][net-std-chan].

[dotnet-cli]:    https://learn.microsoft.com/dotnet/core/tools/
[net-core-sdk]:  https://www.microsoft.com/net/download/core
[net-std-docs]:  https://learn.microsoft.com/dotnet/standard/net-standard
[net-std-chan]:  https://www.youtube.com/playlist?list=PLRAdsfhKI4OWx321A_pr-7HhRNk7wOLLY
[pscore-os]:     https://github.com/powershell/powershell#get-powershell
[readme]:        ../../README.md
[linux-install]: https://www.microsoft.com/net/core#linuxubuntu
[ps-stdlib]:     https://www.nuget.org/packages/PowerShellStandard.Library/
[wsl]:           https://msdn.microsoft.com/commandline/wsl/about

---

### Cmdlet Example Visual Studio Simple Example (`docs/cmdlet-example/visual-studio-simple-example.md`)

# Building a C# Cmdlet with Visual Studio

This document describes steps for building a C# Cmdlet with Visual Studio in 2 ways:

* [Building a C# Cmdlet for PowerShell Core](#building-a-c-cmdlet-for-powershell-core-with-visual-studio)
* [Building a C# Cmdlet for PowerShell Standard 3.0](#building-a-c-cmdlet-for-powershell-standard-30-with-visual-studio)

## Building a C# Cmdlet for PowerShell Core with Visual Studio

This demonstrates how to build your own C# cmdlet for PowerShell Core with Visual Studio.
Targeting for PowerShell Core means that the cmdlet may not work against Windows PowerShell if you take dependencies on new APIs introduced in PowerShell Core.

We will use the free [Visual Studio Community 2017](https://visualstudio.microsoft.com/vs/).

1. When installing Visual Studio 2017 select `.NET Core cross-platform development` under `Other Toolsets`
  

1. Create new C# project `SendGreeting` of type `Class Library (.NET Core)`
  

1. Now we need to setup PowerShell Core reference assemblies.
  In `Solution Explorer` right click on project `Dependencies` and select `Manage NuGet Packages...`
In the top-right corner of the package manager click on the small `Settings` sprocket icon that is to the right from `Package source` dropdown.
By default, there will be only `nuget.org` package source in `Available package sources` list.
Add another package source with name `powershell-core` and source `https://powershell.myget.org/F/powershell-core/api/v3/index.json`


1. In the package manager select new `powershell-core` in `Package source` dropdown, select `Browse` tab, type in `System.Management.Automation` in the search and select `Include prerelease`.
  It should find `System.Management.Automation` package, select it and it will show package details; install it using `Install` button.


1. Add the code of cmdlet:

    ```csharp
    using System.Management.Automation;  // PowerShell namespace.

    namespace SendGreeting
    {
        // Declare the class as a cmdlet and specify and
        // appropriate verb and noun for the cmdlet name.
        [Cmdlet(VerbsCommunications.Send, "Greeting")]
        public class SendGreetingCommand : Cmdlet
        {
            // Declare the parameters for the cmdlet.
            [Parameter(Mandatory = true)]
            public string Name { get; set; }

            // Override the ProcessRecord method to process
            // the supplied user name and write out a
            // greeting to the user by calling the WriteObject
            // method.
            protected override void ProcessRecord()
            {
                WriteObject("Hello " + Name + "!");
            }
        }
    }
    ```

    At this point everything should look like this:
    

1. Build solution (F6); The `Output` window will print the location of generated cmdlet DLL:
  

1. Start PowerShell Core, run `Import-Module` on DLL path from previous step and run cmdlet:
  
You can also run the same cmdlet on Linux and other systems that PowerShell Core supports:


## Building a C# Cmdlet for PowerShell Standard 3.0 with Visual Studio

Steps below show how to build your own C# cmdlet for PowerShell Standard 3.0 with Visual Studio.
Targeting PowerShell Standard 3.0 means that the same module will work against PowerShell Core as well as Windows PowerShell v3 and newer,
however, you are limited to a subset of the available PowerShell APIs.

We will use the free [Visual Studio Community 2017](https://visualstudio.microsoft.com/vs/).

1. When installing Visual Studio 2017 select `.NET Core cross-platform development` under `Other Toolsets`
  

1. Create new C# project `SendGreetingStd` of type `Class Library (.NET Standard)`
  

1. On project properties verify that `Target framework` is `.NET Standard 2.0`:<br />
  

1. Now we need to setup reference assemblies.
  In `Solution Explorer` right click on project `Dependencies` and select `Manage NuGet Packages...`
In the top-right corner of the package manager select `nuget.org` package source, select `Browse` tab, type in `PowerShellStandard.Library` in the search and select `Include prerelease`.
It should find `PowerShellStandard.Library` package, select it and it will show package details; install it using `Install` button.


1. Add the code of cmdlet:

    ```csharp
    using System.Management.Automation;  // PowerShell namespace.

    namespace SendGreeting
    {
        // Declare the class as a cmdlet and specify and
        // appropriate verb and noun for the cmdlet name.
        [Cmdlet(VerbsCommunications.Send, "Greeting")]
        public class SendGreetingCommand : Cmdlet
        {
            // Declare the parameters for the cmdlet.
            [Parameter(Mandatory = true)]
            public string Name { get; set; }

            // Override the ProcessRecord method to process
            // the supplied user name and write out a
            // greeting to the user by calling the WriteObject
            // method.
            protected override void ProcessRecord()
            {
                WriteObject("Hello " + Name + "!");
            }
        }
    }
    ```

    At this point everything should look like this:
    

1. Build solution (F6); The `Output` window will print the location of generated cmdlet DLL:
  

1. Now cmdlet can be run on systems supported by PowerShell Standard;<br />
  For example:<br />
  On PowerShell Core on Windows:

On PowerShell Core on Linux:

On Windows PowerShell on Windows (this requires [.NET Framework 4.7.1](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net471)

---

### Community Governance (`docs/community/governance.md`)

# PowerShell Governance

## Terms

* [**PowerShell Committee**](#powershell-committee): A committee of project owners who are responsible for design decisions,
  approving [RFCs][RFC-repo], and approving new maintainers/committee members
* [**Repository maintainer**](#repository-maintainers): An individual responsible for merging pull requests (PRs) into `master` when all requirements are met (code review, tests, docs, and RFC approval as applicable).
  Repository Maintainers are the only people with write permissions for the `master` branch.
* [**Working Groups (WGs)**](#working-groups) are collections of contributors responsible for
  providing expertise on a specific area of PowerShell in order to help establish consensus within
  the community and Committee.
* **Corporation**: The Corporation owns the PowerShell repository and, under extreme circumstances,
  reserves the right to dissolve or reform the PowerShell Committee, the Project Leads, and the Corporate Maintainer.
  The Corporation for PowerShell is Microsoft.
* **Corporate Maintainer**: The Corporate Maintainer is an entity, person or set of persons,
  with the ability to veto decisions made by the PowerShell Committee or any other collaborators on the PowerShell project.
  This veto power will be used with restraint since it is intended that the community drive the project.
  The Corporate Maintainer is determined by the Corporation both initially and in continuation.
  The initial Corporate Maintainer for PowerShell is Jeffrey Snover ([jpsnover](https://github.com/jpsnover)).
* [**RFC process**][RFC-repo]: The "request-for-comments" (RFC) process whereby design decisions get made.

## PowerShell Committee

The PowerShell Committee and its members (aka Committee Members) are the primary caretakers of the PowerShell experience, including the PowerShell language, design, and project.

### Current Committee Members

* Bruce Payette ([BrucePay](https://github.com/BrucePay))
* Jim Truher ([JamesWTruher](https://github.com/JamesWTruher))
* Paul Higinbotham ([paulhigin](https://github.com/paulhigin))
* Rob Holt ([rjmholt](https://github.com/rjmholt))
* Steve Lee ([SteveL-MSFT](https://github.com/SteveL-MSFT))

### Committee Member Responsibilities

Committee Members are responsible for reviewing and approving [PowerShell RFCs][RFC-repo] proposing new features or design changes.

#### Changes that require an [RFC][RFC-repo]

The following types of decisions require a written RFC and ample time for the community to respond with their feedback before a contributor begins work on the issue:

* new features or capabilities in PowerShell (e.g. PowerShell classes, PSRP over SSH, etc.)
* anything that might require a breaking change, as defined in our [Breaking Changes Contract][breaking-changes]
* new modules, cmdlets, or parameters that ship in the core PowerShell modules (e.g. `Microsoft.PowerShell.*`, `PackageManagement`, `PSReadLine`)
* the addition of new PowerShell Committee Members or Repository Maintainers
* any changes to the process of maintaining the PowerShell repository (including the responsibilities of Committee Members, Repository Maintainers, and Area Experts)

#### Changes that don't require an RFC

In some cases, a new feature or behavior may be deemed small enough to forgo the RFC process
(e.g. changing the default PSReadline `EditMode` to `Emacs` on Mac/Linux).
In these cases, [issues marked as `1 - Planning`][issue-process] require only a simple majority of Committee Members to sign off.
After that, a Repository Maintainer should relabel the issue as `2 - Ready` so that a contributor can begin working on it.

If any Committee Members feels like this behavior is large enough to warrant an RFC, they can add the label `RFC-required` and the issue owner is expected to follow the RFC process.

#### Committee Member DOs and DON'Ts

As a PowerShell Committee Member:

1. **DO** enforce the [Code of Conduct][coc] by taking reports of abuse and violations to the committee for resolution
1. **DO** reply to issues and pull requests with design opinions
  (this could include offering support for good work or exciting new features)
1. **DO** encourage healthy discussion about the direction of PowerShell
1. **DO** raise "red flags" on PRs that haven't followed the proper RFC process when applicable
1. **DO** contribute to documentation and best practices
1. **DO** maintain a presence in the PowerShell community outside of GitHub (Twitter, blogs, Stack Overflow, Reddit, Hacker News, etc.)
1. **DO** heavily incorporate community feedback into the weight of your decisions
1. **DO** be polite and respectful to a wide variety of opinions and perspectives
1. **DO** make sure contributors are following the [contributing guidelines](../../.github/CONTRIBUTING.md)

1. **DON'T** constantly raise "red flags" for unimportant or minor problems to the point that the progress of the project is being slowed
1. **DON'T** offer up your opinions as the absolute opinion of the PowerShell Committee.
  Members are encouraged to share their opinions, but they should be presented as such.

### PowerShell Committee Membership

The initial PowerShell Committee consists of Microsoft employees.
It is expected that over time, PowerShell experts in the community will be made Committee Members.
Membership is heavily dependent on the level of contribution and expertise: individuals who contribute in meaningful ways to the project will be recognized accordingly.

At any point in time, a Committee Member can nominate a strong community member to join the Committee.
Nominations should be submitted in the form of [RFCs][RFC-repo] detailing why that individual is qualified and how they will contribute.
After the RFC has been discussed, a unanimous vote will be required for the new Committee Member to be confirmed.

### PowerShell Committee Code of Conduct Enforcement

As stated in the [contributing guidelines](../../.github/CONTRIBUTING.md#code-of-conduct-enforcement):

Reports of abuse will be reviewed by the PowerShell Committee and if it has been determined that violations of the
[Code of Conduct][coc] has occurred, then a temporary ban may be imposed.
The duration of the temporary ban will depend on the impact and/or severity of the infraction.
This can vary from 1 day, a few days, a week, and up to 30 days.
Repeat offenses may result in a permanent ban from the PowerShell org.

Microsoft employees on the PowerShell committee should review the available support at
[aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support).

## Repository Maintainers

Repository Maintainers are trusted stewards of the PowerShell community/repository responsible for maintaining consistency and quality of PowerShell code.
One of their primary responsibilities is merging pull requests after all requirements have been fulfilled.

For more information on Repository Maintainers--their responsibilities, who they are, and how one becomes a Maintainer--see the [README for Repository Maintainers][maintainers].

## Working Groups

[Working Groups (WGs)][wg] are collections of contributors with knowledge of specific components or
technologies in the PowerShell domain.
They are responsible for issue triage/acceptance, code reviews, and providing their expertise to
others in issues, PRs, and RFC discussions,
as well as to the Committee when said expertise is helpful in broader discussions.

They have [write access](https://docs.github.com/en/free-pro-team@latest/github/setting-up-and-managing-organizations-and-teams/repository-permission-levels-for-an-organization) to the PowerShell repository which gives them the power to:

1. `git push` to all branches *except* `master`.
1. Merge pull requests to all branches *except* `master` (though this should not be common given that [`master`is the only long-living branch](../git/README.md#understand-branches)).
1. Assign labels, milestones, and people to [issues](https://guides.github.com/features/issues/).

### Working Group Responsibilities

If you are a member of a Working Group, you are expected to be actively involved in any development, design, or contributions in the focus area of the WG.
More information on the responsibilities of Working Groups can be found [here][wg],
while current WG definitions and membership can be found [here][wg-definitions].

If you are a Working Group member:

1. **DO** triage and contribute to discussions in issues and PRs that have `WG-*` labels assigned
1. **DO** regularly communicate with other members of your WG to coordinate decisions about
   whether issues should move forward
1. **DO** make decisions on whether or not issues should proceed forward with implementations or RFCs
1. **DO** assign the [correct labels][issue-process] to issues
1. **DO** assign yourself to issues and PRs labeled with your area of expertise only when you are actively
   working on or implementing them
1. **DO** code reviews for PRs where you're assigned or in your WG
   (while reviewing PRs, leave your comment even if everything looks good - a simple "Looks good to me" or "LGTM" will suffice, so that we know someone has already taken a look at it).
1. **DO** ensure that contributors are following the [contributor guidelines](../../.github/CONTRIBUTING.md)
   and [Code of Conduct](https://github.com/PowerShell/PowerShell/blob/master/CODE_OF_CONDUCT.md)
1. **DO** ensure that contributions [include Pester tests][pester] for all new/changed functionality
1. **DO** ensure that contributions [include documentation][docs-contributing] for all new-/changed functionality
1. **DO** encourage contributions to refer to issues in their pull request description (e.g. `Resolves issue #123`)
1. **DO** encourage contributions to have meaningful titles for all PRs,
   editing their title if necessary to ensure that changelogs convey useful and accurate information
1. **DO** verify that all contributions are following the [Coding Guidelines](../dev-process/coding-guidelines.md)

1. **DON'T** create new features, new designs, or change behaviors without following the [RFC][RFC-repo] or approval process

## Issue Management Process

See our [Issue Management Process][issue-process]

## Pull Request Process

See our [Pull Request Process][pull-request-process]

[RFC-repo]: https://github.com/PowerShell/PowerShell-RFC
[pester]: ../testing-guidelines/WritingPesterTests.md
[breaking-changes]: ../dev-process/breaking-change-contract.md
[issue-process]: ../maintainers/issue-management.md
[coc]: ../../CODE_OF_CONDUCT.md
[pull-request-process]: ../../.github/CONTRIBUTING.md#lifecycle-of-a-pull-request
[docs-contributing]: https://github.com/PowerShell/PowerShell-Docs/blob/staging/CONTRIBUTING.md
[maintainers]: ../maintainers/README.md
[wg]: ./working-group.md
[wg-definitions]: ./working-group-definitions.md

---

### Community Working Group Definitions (`docs/community/working-group-definitions.md`)

# Working Group Definitions

This document maintains a list of the current PowerShell [Working Groups (WG)](working-group.md),
as well as their definitions, membership, and a non-exhaustive set of examples of topics that fall
within the purview of that WG.

For an up-to-date list of the issue/PR labels associated with these WGs,
see [Issue Management](../maintainers/issue-management.md)

## Desired State Configuration (DSC)

The Desired State Configuration (DSC) WG manages all facets of DSC in PowerShell 7,
including language features (like the `Configuration` keyword)
and the `PSDesiredStateConfiguration` module.

Today, DSC is integrated into the PowerShell language, and we need to manage it as such.

### Members

* @TravisEz13
* @theJasonHelmick
* @anmenaga
* @gaelcolas
* @michaeltlombardi
* @SteveL-MSFT

## Developer Experience

The PowerShell developer experience includes the **development of modules** (in C#, PowerShell script, etc.),
as well as the experience of **hosting PowerShell and its APIs** in other applications and language runtimes.
Special consideration should be given to topics like **backwards compatibility** with Windows PowerShell
(e.g. with **PowerShell Standard**) and **integration with related developer tools**
(e.g. .NET CLI or the PowerShell extension for Visual Studio Code).

### Members

* @JamesWTruher (PS Standard, module authoring)
* @adityapatwardhan (SDK)
* @michaeltlombardi
* @SeeminglyScience
* @bergmeister

## Engine

The PowerShell engine is one of the largest and most complex aspects of the codebase.
The Engine WG should be focused on the
**implementation and maintenance of core PowerShell engine code**.
This includes (but is not limited to):

* The language parser
* The command and parameter binders
* The module and provider systems
  * `*-Item` cmdlets
  * Providers
* Performance
* Componentization
* AssemblyLoadContext

It's worth noting that the Engine WG is not responsible for the definition of the PowerShell language.
This should be handled by the Language WG instead.
However, it's expected that many issues will require input from both WGs.

### Members

* @daxian-dbw
* @JamesWTruher
* @rkeithhill
* @vexx32
* @SeeminglyScience
* @IISResetMe
* @powercode
* @kilasuit

## Interactive UX

While much of PowerShell can be used through both interactive and non-interactive means,
some of the PowerShell user experience is exclusively interactive.
These topics include (but are not limited to):

* Console
* Help System
* Tab completion / IntelliSense
* Markdown rendering
* PSReadLine
* Debugging

### Members

* @theJasonHelmick
* @daxian-dbw (PSReadline / IntelliSense)
* @adityapatwardhan (Markdown / help system)
* @JamesWTruher (cmdlet design)
* @SeeminglyScience
* @sdwheeler
* @kilasuit
* @FriedrichWeinmann
* @StevenBucher98

## Language

The Language WG is distinct from the Engine WG in that they deal with the abstract definition
of the PowerShell language itself.
While all WGs will be working closely with the PowerShell Committee (and may share members),
it's likely that the Language WG will work especially close with them,
particularly given the long-lasting effects of language decisions.

### Members

* @JamesWTruher
* @daxian-dbw
* @SeeminglyScience

## Remoting

The Remoting WG should focus on topics like the **PowerShell Remoting Protocol (PSRP)**,
the **protocols implemented under PSRP** (e.g. WinRM and SSH),
and **other protocols used for remoting** (e.g. "pure SSH" as opposed to SSH over PSRP).
Given the commonality of serialization boundaries, the Remoting WG should also focus on
**the PowerShell job system**.

### Members

* @anmenaga
* @TravisEz13

## Cmdlets and Modules

The Cmdlet WG should focus on core/inbox modules whose source code lives within the
`PowerShell/PowerShell` repository,
including the proposal of new cmdlets and parameters, improvements and bugfixes to existing
cmdlets/parameters, and breaking changes.

However, some modules that ship as part of the PowerShell package are managed in other source repositories.
These modules are owned by the maintainers of those individual repositories.
These modules include:

* [`Microsoft.PowerShell.Archive`](https://github.com/PowerShell/Microsoft.PowerShell.Archive)
* [`PackageManagement` (formerly `OneGet`)](https://github.com/OneGet/oneget)
* [`PowerShellGet`](https://github.com/PowerShell/PowerShellGet)
* [`PSDesiredStateConfiguration`](https://github.com/PowerShell/xPSDesiredStateConfiguration)
  (Note: this community repository maintains a slightly different version of this module on the Gallery,
  but should be used for future development of `PSDesiredStateConfiguration`.)
* [`PSReadLine`](https://github.com/PowerShell/PSReadLine)
* [`ThreadJob`](https://github.com/PowerShell/Modules/tree/master/Modules/Microsoft.PowerShell.ThreadJob)

### Members

* @JamesWTruher
* @SteveL-MSFT
* @jdhitsolutions
* @TobiasPSP
* @doctordns
* @kilasuit

## Security

The Security WG should be brought into any issues or pull requests which may have security implications
in order to provide their expertise, concerns, and guidance.

### Members

* @TravisEz13
* @SydneySmithReal
* @anamnavi
* @SteveL-MSFT

## Explicitly not Working Groups

Some areas of ownership in PowerShell specifically do not have Working Groups.
For the sake of completeness, these are listed below:

### Build

Build includes everything that is needed to build, compile, and package PowerShell.
This bucket is also not oriented a customer-facing deliverable and is already something handled by Maintainers,
so we don't need to address it as part of the WGs.

* Build
  * `build.psm1`
  * `install-powershell.ps1`
  * Build infrastructure and automation
* Packaging
  * Scripts
  * Infrastructure

### Quality

Similar to the topic of building PowerShell, quality
(including **test code**, **test infrastructure**, and **code coverage**)
should be managed by the PowerShell Maintainers.

* Test code
  * Pester unit tests
  * xUnit unit tests
* Test infrastructure
  * Nightlies
  * CI
* Code coverage
* Pester

---

### Community Working Group (`docs/community/working-group.md`)

# Working Groups

Working Groups (WGs) are collections of contributors with knowledge of specific components or
technologies in the PowerShell domain.
They are responsible for issue triage/acceptance, code reviews, and providing their expertise to
others in issues, PRs, and RFC discussions.

The list, description, and membership of the existing Working Groups is available
[here](working-group-definitions.md).

## Terms

* **Contributor** is used interchangeably within this doc as anyone participating in issues or
  contributing code, RFCs, documentations, tests, bug reports, etc.,
  regardless of their status with the PowerShell project.
* **Repository Maintainers** are trusted stewards of the PowerShell repository responsible for
  maintaining consistency and quality of PowerShell code.
  One of their primary responsibilities is merging pull requests after all requirements have been fulfilled.
  (Learn more about the Repository Maintainers [here](https://github.com/PowerShell/PowerShell/tree/master/docs/maintainers).)
* The **PowerShell Committee** is responsible for the design and governance of the PowerShell project,
  primarily by voting to accept or reject review-for-comment (RFC) documents.
  (Learn more about the PowerShell Committee [here](https://github.com/PowerShell/PowerShell/blob/master/docs/community/governance.md#powershell-committee).)
* A **Working Group** is a collection of people responsible for providing expertise on a specific
  area of PowerShell in order to help establish consensus within the community and Committee.
  The responsibilities of Working Groups are outlined below.
  (Note: while some experts within Working Groups may have more specific expertise in a sub-topic
  of the team,
  the intent is that each team is holistically and collectively responsible for making decisions
  within the larger topic space.)

## Goals

In designing the WG process, the Committee had a few goals:

1. Increase the velocity of innovation without compromising the stability of PowerShell
1. Reduce the time spent by contributors on writing/reviewing PRs and RFCs that are not feasible
1. Increase the formal authority of subject matter experts (SMEs) inside and outside of Microsoft
1. Decrease the volume of required technical discussions held by the Committee

## Process

This process is represented within the [`process_diagram.vsdx` Visio diagram](process_diagram.vsdx):



1. A contributor has an idea for PowerShell
1. The contributor files an issue informally describing the idea,
   including some rationale as to why it should happen and a few use cases to show how it could work,
   as well as to determine viability and value to the community.
   This should include examples of expected input and output so that others understand how the feature would function in the real world.
1. The issue gets triaged into an [Area label](https://github.com/PowerShell/PowerShell/blob/master/docs/maintainers/issue-management.md#feature-areas)
   by Maintainers.
   This area label maps to one or more Working Groups.
1. If the Working Group determines that an idea can be prototyped or built outside of the PowerShell repo
   (e.g. as a module),
   contributors should start that idea outside of the PowerShell project.
   Given that the issue is no longer directly relevant to the PowerShell project, it should be closed
   (with a link to the new project, if available).
   If the implementation turns out to be successful and particularly popular,
   and a contributor believes that it would be overwhelmingly valuable to include in the primary PowerShell package,
   they can restart the process in a new issue proposing that the functionality be
   incorporated directly into the primary PowerShell package.
1. After the issue is filed, interested contributors should discuss the
   feasibility and approach of the idea in the issue.
   The Working Group that owns that Area is expected to contribute to this discussion.
   Working groups may have their own criteria to consider in their areas.
1. After an appropriately exhaustive discussion/conversation
   (i.e. the Working Group has determined that no new arguments are being made),
   the Working Group makes a call on whether they believe the idea should continue through this process.
   Note: this should be done via a best effort of consensus among the Working Group.
   We don't currently have hard requirements for how this should be done,
   but some ideas include:

   * a single member of the Working Group makes a proposal as a comment and other members should
     "react" on GitHub with up/down thumbs
   * Working Groups communicate privately through their own established channel to reach consensus

   It's worth noting that Working Group members who repeatedly speak on behalf of the Working Group without
   consensus, they may be censured or removed from the team.

### Working Groups reject the proposal

If the Working Group says the idea should not pursued, the process stops.
Some reasons for rejection include (but are not limited to):

* the idea can be implemented and validated for usefulness and popularity outside of the primary PowerShell repo/package
* the idea is difficult/impossible to implement
* the implementation would introduce undesirable (and possibly breaking) changes to PowerShell
* other reasons specific to individual Working Groups

In the instance that the contributor feels they have compelling arguments showing that the
Working Group is incorrect in their rejection,
they can appeal to the PowerShell Committee by mentioning `@PowerShell/PowerShell-Committee`,
upon which a maintainer will add the `Review-Committee` label to the issue and reopen it.
Then, the PS Committee will discuss further with the Working Group and others to make a final call on
whether or not the issue should be pursued further.

Be sure to enumerate your reasons for appeal, as unfounded appeals may be rejected for consideration
by the Committee until reasons are given.

### Working groups believe the proposal has merit and/or potential

If the idea passes the preliminary acceptance criteria for the Working Group,
the process proceeds on one of a few different paths:

#### "RFC Not Required"

In some cases, a proposed idea is determined by the Working Group to be small, uncontroversial, or simple,
such that an RFC is not required (to be determined by the Working Group).
In these circumstances, the Working Group should mark the issue as "RFC not required",
upon which it can move directly to the code PR phase to be reviewed by Working Groups and Maintainers.

The Committee still holds the authority to require an RFC if they see an "RFC Not Required" issue
that they feel needs more exposition before merging.

In cases of minor breaking changes, Maintainers or Working Groups can add the `Review - Committee` label to get
additional opinions from the Committee.

#### RFC/Prototype Process

If an idea has any significant design or ecosystem implications,
*cannot* be prototyped or built outside of the PowerShell repo,
and the community and Working Groups agree that the idea is worth pursuing,
a contributor (who may or may not be the original issue filer) must do two things:

* Write an RFC as a [Draft PR](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests)
  into `PowerShell/PowerShell-RFC`
* Prototype the implementation as a [Draft PR](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests)
  into `PowerShell/PowerShell`

In both cases, the intention is to provide Working Groups and other contributors who care about the
idea an opportunity to provide feedback on the design and implementation.

Either of these two steps can be done first, but both are required in order to have code accepted
into the PowerShell repository, including experimental features.

Note: When "Draft" is capitalized in this document, I'm referring to the
[Draft pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests#draft-pull-requests)
feature on GitHub.
We intend to use this feature liberally to mark the lifecycle of an idea through to implementation.

#### RFCs

The existing RFC process uses folders as a way to move an RFC through a multi-stage process
(Draft -> Experimental -> Accepted/Final).
However, it was difficult to reconcile this process with the benefits of PR reviews.

With the introduction of Draft PRs on GitHub, we are reorienting the acceptance process around the PR itself.
Going forward, an RFC will have three stages:

1. A Draft PR, denoting that the RFC is still in the review period, openly soliciting comments,
   and that it may continue to be significantly iterated upon with revisions, edits, and responses to
   community feedback or concerns.
1. After a minimum of two months of discussion, the RFC/PR author marks the PR as
   [ready for review](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-stage-of-a-pull-request),
   upon which the RFC will enter the Committee's review queue to discuss the RFC contents and comments,
   and make a decision on whether it is reasonable to pursue.
   If after this review, the Committee determines that the intent of the RFC is not reasonable
   (e.g. there may be irreconcilable issues with the design,
   or the intent may not fit with the principles of PowerShell),
   they will reject the PR and the process terminates.
1. In most cases, the Committee will choose to wait for the code PR to be merged as experimental,
   and leverage user feedback or telemetry to determine if the RFC PR should be merged.
1. Finally, the Committee will choose to either merge or close the RFC PR,
   marking the RFC as either accepted or rejected, respectively.

#### Experiments

Often times, implementing an idea can demonstrate opportunities or challenges that were not well
understood when the idea was formulated.
Similarly, a "simple" code change can have far reaching effects that are not well understood
until you're able to experiment with an idea within working code.

To that end, it's required that *some* implementation exist before the Committee will consider an
RFC for acceptance.
That way, contributors can compile the PR branch to play with a working iteration of the idea
as a way to understand whether the feature is working as expected and valuable.

In most cases, as long as an RFC has already been written and published as a draft,
Working Groups or the Committee will approve the feature for incorporation as an experimental feature,
so that it can be trialed with greater usage as part of a preview release.
In addition to increasing the scope of those who can provide real-world feedback on the feature,
this enables us to use telemetry to understand if users are turning off the feature in large numbers.

Note: today, this will be done on a case-by-case basis, but over time, the Committee will establish
firmer guidelines around when PRs should be merged as experimental.

Experiments should be complete to the extent that they serve as reasonable indicators of the user experience.
In the case that breaking changes are required of the feature, the break should be made in the prototype
so that users can experiment with whether or not the break has a significant negative effect.

#### Reporting Working Group members abuse

Working group members are individuals and in many cases volunteers.
There may be situations where a working group member might exhibit behavior that is objectionable,
exceed the authority defined in this document or violate the [Code of Conduct](../../CODE_OF_CONDUCT.md).
We recommend to report such issues by using the [Report Content](https://docs.github.com/communities/maintaining-your-safety-on-github/reporting-abuse-or-spam) mechanism to bring it to the attention of the maintainers to review.

---

### Dev Process Breaking Change Contract (`docs/dev-process/breaking-change-contract.md`)

# Breaking Changes

We have a serious commitment to backwards compatibility with all earlier versions of PowerShell – including the language, cmdlets, APIs and the various protocols (e.g. PowerShell Remoting Protocol) and data formats (e.g. cdxml).

Below is a summary of our approach to handing breaking changes including what kinds of things constitute breaking changes, how we categorize them, and how we decide what we're willing to take.

Note that these rules only apply to existing stable features that have shipped in a supported release. New features marked as “in preview” that are still under development may be modified from one preview release to the next.
These are **not** considered breaking changes.

To help triage breaking changes, we classify them in to four buckets:

1. Public Contract
1. Reasonable Grey Area
1. Unlikely Grey Area
1. Clearly Non-Public

## Bucket 1: Public Contract

Any change that is a clear violation of the public contract.

### Unacceptable changes

+ A code change that results in a change to the existing behavior observed for a given input with an API, protocol or the PowerShell language.
+ Renaming or removing a public type, type member, or type parameter; renaming or removing a cmdlet or cmdlet parameter (note: it is possible to rename a cmdlet parameter if a parameter alias is added.

This is an acceptable solution for PowerShell scripts but may break .NET code that depends on the name of the original member on the cmdlet object type.)

+ Decreasing the range of accepted values within a given parameter.
+ Changing the value of a public constant or enum member; changing the type of a cmdlet parameter to a more restrictive type.
    + Example: A cmdlet with a parameter -p1 that was previously type as [object] cannot be changed to be or a more restrictive type such as [int].
+ Making an incompatible change to any protocol without increasing the protocol version number.

### Acceptable changes

+ Any existing behavior that results in an error message generally may be changed to provide new functionality.
+ A new instance field is added to a type (this impacts .NET serialization but not PowerShell serialization and so is considered acceptable.)
+ Adding new types, new type members and new cmdlets
+ Making changes to the protocols with a protocol version increment. Older versions of the protocol would still need to be maintained to allow communication with earlier systems. This would require that protocol negotiation take place between the two systems. In addition to any protocol code changes, the Microsoft Open Specification program requires that the formal protocol specification for a protocol be updated in a timely manner.  An example of a MS protocol specification document (MS-PSRP) can be found at: https://msdn.microsoft.com/library/mt242417.aspx

## Bucket 2: Reasonable Grey Area

Change of behavior that customers would have reasonably depended on.

Examples:

+ Change in timing/order of events (even when not specified in docs)
    + Example: PowerShell events are handled by interleaving their execution with the execution of the main pipeline thread. Where and when this interleaving occurs might change. This order of execution is not specified but is deterministic so changing it might break some scripts.
+ Change in parsing of input and throwing new errors (even if parsing behavior is not specified in the docs)
    + Example: a script may be using a JSON parser that is forgiving to minor syntactic errors in the JSON text. Changing that parser to be more rigorous in its processing would result in errors being thrown when no error was generated in the past thus breaking scripts.

Judiciously making changes in these type of features require judgement: how predictable, obvious, consistent was the behavior?
In general, a significant external preview of the change would need to be done also possibly requiring an RFC to be created to allow for community input on the proposal.

## Bucket 3: Unlikely Grey Area

Change of behavior that customers could have depended on, but probably wouldn't.

Examples:

+ correcting behavior in a subtle corner case that has no obvious utility.

    + Example: the existing behavior of the PowerShell cd called without arguments is to do nothing. Changing this behavior to be consistent with UNIX shells which typically set the CWD to the user’s home directory

    + Example: changes to formatting for an object type. We have always considered the output formatting of an object to be a user experience issue and thus open for change. Since PowerShell pipes objects not text, changes to the way an object is rendered to text is generally considered to be allowed.

As with type 2 changes, these require judgement: what is reasonable and what’s not?

## Bucket 4: Clearly Non-Public

Changes to surface area or behavior that is clearly internal or non-breaking in theory, but breaks an app.

Examples:

+ Changes to internal APIs that break private reflection.
+ Changes to APIs in the `System.Management.Automation.Internal` namespace (even if they are public, they are still considered internal and subject to change).
+ Renaming a parameter set (see related discussion [here](https://github.com/PowerShell/PowerShell/issues/10058)).

It is impossible to evolve a code base without making such changes, so we don't require up-front approval for these, but we will sometimes have to go back and
revisit such change if there's too much pain inflicted on the ecosystem through a popular app or library.

## What This Means for Contributors

+ All bucket 1, 2, and 3 breaking changes require contacting team at @powershell/powershell.
+ If you're not sure into which bucket a given change falls, contact us as well.
+ It doesn't matter if the existing behavior is "wrong", we still need to think through the implications. PowerShell has been in broad use for over 10 years so we be must be extremely sensitive to breaking existing users and scripts.
+ If a change is deemed too breaking, we can help identify alternatives such as introducing a new API or cmdlet and obsoleting the old one.

Request for clarifications or suggested alterations to this document should be done by opening issues against this document.

---

### Dev Process Coding Guidelines (`docs/dev-process/coding-guidelines.md`)

# C# Coding Guidelines

## Coding Conventions

As a general rule, our coding convention is to follow the style of the surrounding code.
So if a file happens to differ in style from conventions defined here
(e.g. private members are named `m_member` rather than `_member`),
the existing style in that file takes precedence.

When making changes, you may find some existing code goes against the conventions defined here.
In such cases, please avoid reformatting any existing code when submitting a PR as it obscures the functional changes of the PR.
A separate PR should be submitted for style-only changes.
We also run the [.NET code formatter tool](https://github.com/dotnet/codeformatter) regularly to keep consistent formatting.

### Naming Conventions

* Use meaningful, descriptive words for names.
  For method names, it's encouraged to use `VerbObject` pair such as **`LoadModule`**.

* Use `_camelCase` to name internal and private fields and use `readonly` where possible.
  Prefix instance fields with `_`, static fields with `s_` and thread static fields with `t_`.
  When used on static fields, `readonly` should come after `static` (i.e. `static readonly` not `readonly static`).

* Use `camelCase` to name non-constant local variables.

* Use `PascalCase` to name constant local variables and fields.
  The only exception is for interop code where the constant should exactly match the name and value of the code you are calling via interop (e.g. `const int ERROR_SUCCESS = 0`).

* Use `PascalCase` to name types and all other type members.

### Layout Conventions

* Use four spaces of indentation (no tabs).

* Avoid more than one blank empty line at any time.

* Avoid trailing spaces at the end of a line.

* Braces usually go on their own lines,
  with the exception of single line statements that are properly indented.

* Namespace imports should be specified at the top of the file,
  outside of `namespace` declarations.

* Fields should be specified at the top within type declarations.
  For those that serve as backing fields for properties,
  they should be specified next to the corresponding properties.

* Preprocessor directives like `#if` and `#endif` should be placed at the beginning of a line,
  without any leading spaces.

* File encoding should be `ASCII`.
  All `BOM` encodings should be avoided.
  Tests that need a `BOM` encoding file should generate the file on the fly.

### Member Conventions

* Use of `this` is neither encouraged nor discouraged.

* Use `nameof(<member-name>)` instead of `"<member-name>"` whenever possible and relevant.
  The motivation is to easily and more accurately find references.

* Always specify the visibility, even if it's the default (i.e. `private string _foo` not `string _foo`).
  Visibility should be the first modifier (i.e. `public abstract` not `abstract public`).

* Make members private where possible.
  Avoid declaring public members unless it's absolutely necessary.

* Public members in a namespace that ends with `Internal`,
  for example `System.Management.Automation.Internal` are not considered a supported public API.
  Such members are necessarily public as implementation details in code shared between C# and PowerShell script,
  or must be available publicly by generated code.

### Commenting Conventions

* Place the comment on a separate line, not at the end of a line of code.

* Begin comment text with an uppercase letter.
  It's recommended to end comment text with a period but not required.

* Add comments where the code is not trivial or could be confusing.

* Add comments where a reviewer needs help to understand the code.

* Update/remove existing comments when you are changing the corresponding code.

* Make sure the added/updated comments are meaningful, accurate and easy to understand.

### Documentation comments

* Create documentation using [XML documentation comments](https://learn.microsoft.com/dotnet/csharp/language-reference/xmldoc/) so that Visual Studio and other IDEs can use IntelliSense to show quick information about types or members.

* Publicly visible types and their members must be documented.
  Internal and private members may use doc comments but it is not required.

* Documentation text should be written using complete sentences ending with full stops.

## Performance Considerations

PowerShell has a lot of performance sensitive code as well as a lot of inefficient code.
We have some guidelines that we typically apply widely even in less important code because code and patterns are copied,
and we want certain inefficient code to stay out of the performance critical code.

Some general guidelines:

* Avoid LINQ - it can create lots of avoidable garbage.
  Instead, iterate through a collection directly using `for` or `foreach` loop.

* Between `for` and `foreach`,
  `for` is slightly preferred when you're uncertain if `foreach` allocates an iterator.

* Avoid `params` arrays, prefer adding overloads with 1, 2, 3, and maybe more parameters.

* Be aware of APIs such as `String.Split(params char[])` that do not provide overloads to avoid array allocation.
  When calling such APIs, reuse a static array when possible (e.g. `Utils.Separators.Colon`).

* Avoid using string interpolations and overloads with implicit parameters such as `Culture` and `StringComparison`.
  Instead, use overloads with more explicit parameters such as `String.Format(IFormatProvider, String, Object[])` and `Equals(String, String, StringComparison)`.

* Avoid unnecessary memory allocation in a loop.
  Move the memory allocation outside the loop if possible.

* Avoid gratuitous exceptions as much as possible.
  Exception handling can be expensive due to cache misses and page faults when accessing the handling code and data.
  Finding and designing away exception-heavy code can result in a decent performance win.
  For example, you should stay away from things like using exceptions for control flow.

* Avoid `if (obj is Example) { example = (Example)obj }` when casting an object to a type.
  Instead, use `var example = obj as Example` or the C# 7 syntax `if (obj is Example example) {...}` as appropriate.
  In this way you can avoid converting to the type twice.

* Use generic collections instead of the non-generic ones such as `ArrayList` and `Hashtable` to avoid type casting and unnecessary boxing whenever possible.

* Use collection constructor overloads that take an initial capacity for collection types that have them.
  Internally, `List<T>`, `Dictionary<TKey, TValue>`,
  and the other generic collections use one or more arrays to hold valid data.
  Whenever resizing is needed,
  one or more new arrays double the size of existing arrays are created and items from the existing arrays are copied.
  Setting an approximate initial capacity will reduce the number of resizing operations.

* Use `dict.TryGetValue` instead of `dict.Contains` and `dict[..]` when retrieving value from a `Dictionary`.
  In this way you can avoid hashing the key twice.

* It's OK to use the `+` operator to concatenate one-off short strings.
  But when dealing with strings in loops or large amounts of text,
  use a `StringBuilder` object.

## Security Considerations

Security is an important aspect of PowerShell and we need to be very careful about changes that may introduce security risks,
such as code injection caused by the lack of input validation,
privilege escalation due to the misuse of impersonation,
or data privacy breach with a plain text password.

Reviewers of a PR should be sensitive to changes that may affect security.
Some security related keywords may serve as good indicators,
such as `password`, `crypto`, `encryption`, `decryption`, `certificate`, `authenticate`, `ssl/tls` and `protected data`.

When facing a PR with such changes,
the reviewers should request a designated security Subject Matter Expert (SME) to review the PR.
Currently, [@PaulHigin](https://github.com/PaulHigin) and [@TravisEz13](https://github.com/TravisEz13) are our security SMEs.
See [CODEOWNERS](../../.github/CODEOWNERS) for more information about the area experts.

## Best Practices

* Avoid hard-coding anything unless it's absolutely necessary.

* Avoid a method that is too long and complex.
  In such case, separate it to multiple methods or even a nested class as you see fit.

* Use the `using` statement instead of `try/finally` if the only code in the `finally` block is to call the `Dispose` method.

* Use of object initializers (e.g. `new Example { Name = "Name", ID = 1 }`) is encouraged for better readability,
  but not required.

* Stick to the `DRY` principle -- Don't Repeat Yourself.
    * Wrap the commonly used code in methods,
      or even put it in a utility class if that makes sense,
      so that the same code can be reused (e.g. `StringToBase64Converter.Base64ToString(string)`).
    * Check if the code for the same purpose already exists in the code base before inventing your own wheel.
    * Avoid repeating literal strings in code. Instead, use `const` variable to hold the string.
    * Resource strings used for errors or UI should be put in resource files (`.resx`) so that they can be localized later.

* Use of new C# language syntax is encouraged.
  But avoid refactoring any existing code using new language syntax when submitting a PR
  as it obscures the functional changes of the PR.
  A separate PR should be submitted for such refactoring without any functional changes.

* Consider using the `Interlocked` class instead of the `lock` statement to atomically change simple states. The `Interlocked` class provides better performance for updates that must be atomic.

* Here are some useful links for your reference:
  * [Framework Design Guidelines](https://learn.microsoft.com/dotnet/standard/design-guidelines/index) - Naming, Design and Usage guidelines including:
    * [Arrays](https://learn.microsoft.com/dotnet/standard/design-guidelines/arrays)
    * [Collections](https://learn.microsoft.com/dotnet/standard/design-guidelines/guidelines-for-collections)
    * [Exceptions](https://learn.microsoft.com/dotnet/standard/design-guidelines/exceptions)
  * [Best Practices for Developing World-Ready Applications](https://learn.microsoft.com/dotnet/core/extensions/best-practices-for-developing-world-ready-apps) - Unicode, Culture, Encoding and Localization.
  * [Best Practices for Exceptions](https://learn.microsoft.com/dotnet/standard/exceptions/best-practices-for-exceptions)
  * [Best Practices for Using Strings in .NET](https://learn.microsoft.com/dotnet/standard/base-types/best-practices-strings)
  * [Best Practices for Regular Expressions in .NET](https://learn.microsoft.com/dotnet/standard/base-types/best-practices)
  * [Serialization Guidelines](https://learn.microsoft.com/dotnet/standard/serialization/serialization-guidelines)
  * [Managed Threading Best Practices](https://learn.microsoft.com/dotnet/standard/threading/managed-threading-best-practices)

## Portable Code

There are 3 primary preprocessor macros we use during builds:

* `DEBUG` - guard code that should not be included in release builds
* `CORECLR` - guard code that differs between Full CLR and CoreCLR
* `UNIX` - guard code that is specific to Unix (Linux and macOS)

Any other preprocessor defines found in the source are used for one-off custom builds,
typically to help debug specific scenarios.

Here are some general guidelines for writing portable code:

* We are in the process of cleaning up Full CLR specific code (code enclosed in `!CORECLR`),
  so do not use `CORECLR` or `!CORECLR` in new code.
  PowerShell Core targets .NET Core only and all new changes should support .NET Core only.

* The PowerShell code base started on Windows and depends on many Win32 APIs through P/Invoke.
  Going forward, we try to depend on .NET Core to handle platform differences,
  so avoid adding new P/Invoke calls where a suitable alternative exists in .NET Core.

* Try to minimize the use of `#if UNIX`.
  When absolutely necessary, avoid duplicating more code than necessary,
  and instead prefer introducing helper functions to minimize the platform differences.

* When adding platform dependent code (`Windows` vs. `UNIX`), prefer preprocessor directives over runtime checks.
  However, runtime checks are acceptable if it would greatly improve readability
  without causing performance concerns in performance-sensitive code.

* We produce a single binary for all UNIX variants,
  so runtime checks are currently necessary for some of them (e.g. macOS vs. Linux).

---

### Dev Process Resx Files (`docs/dev-process/resx-files.md`)

# Resources

Resources are `.resx` files with string values that we use for error messages and such.
They live in `src\<project>\resources` folders.

At the moment `dotnet cli` doesn't support generating C# bindings (strongly typed resource files).

We are using our own `Start-ResGen` to generate them.

Usually it's called as part of the regular build with

```powershell
Start-PSBuild -ResGen
```

If you see compilation errors related to resources, try to call `Start-ResGen` explicitly.

```powershell
Start-ResGen
```

## Editing `.resx` files

**Don't edit** `.resx` files from Visual Studio.
It will try to create `.cs` files for you and you will get whole bunch of hard-to-understand errors.

To edit a resource file, use any **plain text editor**.
A resource file is a simple XML file, and it's easy to edit.

## Convert `.txt` resource files into `.resx` files

`dotnet cli` doesn't support embedding old-fashioned `.txt` resource.
You can do a one-time conversion of `.txt` resources into `.resx` files with a helper function:

```powershell
# example, converting all .txt resources under src\Microsoft.WSMan.Management\resources
Convert-TxtResourceToXml -Path src\Microsoft.WSMan.Management\resources
```

`.resx` files would be placed next to `.txt` files.

---

### Git Basics (`docs/git/basics.md`)

# Getting started with Git

We are using Git version 2.9.0, but any recent version should be good.
It's recommended to learn the `git` command-line tool for full
cross-platform experience and a deeper understanding of Git itself.

## Install

### Windows

Install [Git for Windows][].

During the installation process, choose these recommended settings:

* Use Git from the Windows Command Prompt
* Use OpenSSH
* Checkout Windows-style, commit Unix-style line endings
* Use Windows' default console window
* Enable file system caching

[Git for Windows]: https://git-scm.com/download/win

### Linux

Install by using the package manager on your system.
A list of all the package managers and commands can be found [here][linux-git-dl].

### Interactive tutorials

There are (too) many Git tutorials on the internet. Here we post
references to our favorites.

#### Hello World

If you're new to Git, learn the following commands: `checkout`, `branch`,
`pull`, `push`, `merge`.

Use GitHub's [Hello World][] to learn how to create a feature branch, commit
changes, and issue a pull request.

[Hello World]: https://guides.github.com/activities/hello-world/

#### Githug

[Githug](https://github.com/Gazler/githug) is a great gamified way to
learn Git in couple hours. After finishing 50+ real-world scenarios
you will have a pretty good idea about what and when you can do with
Git.

## Authentication

### Windows

On Windows, the best way to use Git securely is [Git Credential Manager for Windows][manager].
It's included in the official Git installer for Windows.

#### Linux and macOS

If you do not have a preferred method of authentication, enable the storage
credential helper, which will cache your credentials in plaintext on your
system, so use a [token][].

```sh
git config --global credential.helper store
```

Alternatively, you can use [SSH key][].
In this case, you may want to use git-ssh even for HTTPS Git URLs.

```none
git config --global url.git@github.com:.insteadOf https://github.com/
```

[SSH key]: https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/#generating-a-new-ssh-key
[token]: https://help.github.com/articles/creating-an-access-token-for-command-line-use/
[manager]: https://github.com/Microsoft/Git-Credential-Manager-for-Windows
[linux-git-dl]: https://git-scm.com/download/linux

---

### Maintainers Best Practice (`docs/maintainers/best-practice.md`)

# Maintainer Best Practices

## PR Types

- Feature-work PR: A PR that implements an RFC, which usually involves relatively large set of changes.
- Regular PR: A bug fix or an enhancement change that are not backed by an RFC.

## Review PRs

- Ask the author to reword the PR title based on guidelines in [Contributing](../../.github/CONTRIBUTING.md).
- Ask the author to apply `[feature]` tag to trigger full test builds if it's necessary.
- Label the PR with `Breaking-Change`, `Documentation Needed` and `Area-XXX` as appropriate.
- When labelling a PR with `Review-Committee`, leave a detailed comment to summarize the issue you want the committee to look into.
  It's recommended to include examples to explain/demonstrate behaviors.

## Merge PRs

- Use `Squash and merge` by default to keep clean commit history in Master branch.

  &nbsp;&nbsp;&nbsp;&nbsp;

- Use `Create a merge commit` for feature-work PRs **only if** the commit history of the PR is reasonably clean.
  After using this option, GitHub will make it your default option for merging a PR.
  Do remember to change the default back to `Squash and merge` as it will be useful next time.

  &nbsp;&nbsp;&nbsp;&nbsp;

- Avoid `Rebase and merge` unless you have a strong argument for using it.

- Before clicking `Confirm squash and merge` or `Confirm merge`,
  make sure you run through the following steps:

  1. The commit title should be a short summary of the PR.

     - When merging with the `Squash and merge` option,
       the PR title will be used as the commit title by default.
       **Reword the title as needed** to make sure it makes sense (can be used without change in `CHANGELOG.md`).

     - When merging with the `Create a merge commit` option,
       the default commit title would be `Merge pull request XXX from YYY`.
       **Replace it with a short summary of the PR**, and add the PR number to the end, like `(#1234)`.

  1. The optional extended description is required for feature-work PRs, or regular PRs with breaking changes.
     For other PRs, it's not required but good to have based on the judgement of the maintainer.

     - If a PR introduces breaking changes from the previous stable release,
       make sure you put the tag `[breaking change]` at the first line of the extended description,
       and start the description text from the second line.

  1. Use the present tense and imperative mood for both the commit title and description.

---

### Maintainers Issue Management (`docs/maintainers/issue-management.md`)

# Issue Management

## Security Vulnerabilities

If you believe that there is a security vulnerability in PowerShell,
first follow the [vulnerability issue reporting policy](../../.github/SECURITY.md) before submitting an issue.

## Long-living issue labels

Issue labels for PowerShell/PowerShell can be found [here](https://github.com/powershell/powershell/labels).

### Issue and PR Labels

Issues are opened for many different reasons.
We use the following labels for issue classifications:

* `Issue-Announcement`: the issue is for discussing an [Announcement](https://github.com/PowerShell/Announcements)
* `Issue-Bug`: the issue is reporting a bug
* `Issue-Code Cleanup`: the issue is for cleaning up the code with no impact on functionality
* `Issue-Discussion`: the issue may not have a clear classification yet.
  The issue may generate an [RFC][ln-rfc] or may be reclassified as a bug or enhancement.
* `Issue-Enhancement`: the issue is more of a feature request than a bug.
* `Issue-Meta`: an issue used to track multiple issues.
* `Issue-Question`: ideally support can be provided via other mechanisms,
  but sometimes folks do open an issue to get a question answered and we will use this label for such issues.

[ln-rfc]: https://github.com/PowerShell/PowerShell-RFC

When an issue is resolved, the following labels are used to describe the resolution:

* `Resolution-Answered`: the issue was an `Issue-Question` and was answered.
* `Resolution-By Design`: the issue is not considered a bug, the behavior is working as designed.
* `Resolution-Duplicate`: the issue is a duplicate - there must be a comment linking to another issue.
* `Resolution-External`: the issue cannot be address by this repo.  Should be addressed externally.
* `Resolution-Fixed`: the issue has been fixed and should be referenced from a PR.
* `Resolution-Won't Fix`: the issue may be considered a bug or enhancement but won't be fixed.
  If there is an inadequate explanation as to why the issue was closed,
  anyone should feel free to reopen the issue.

### Feature areas

These labels describe what feature area of PowerShell that an issue affects.
Those labels denoted by `WG-*` are owned by a Working Group (WG) defined
[here](../community/working-group-definitions.md):

* `Area-Maintainers-Build`: build issues
* `Area-Cmdlets-Core`: cmdlets in the Microsoft.PowerShell.Core module
* `Area-Cmdlets-Utility`: cmdlets in the Microsoft.PowerShell.Utility module
* `Area-Cmdlets-Management`: cmdlets in the Microsoft.PowerShell.Management module
* `Area-Documentation`: PowerShell *repo* documentation issues, general PowerShell doc issues go [here](https://github.com/PowerShell/PowerShell-Docs/issues)
* `Area-DSC`: DSC related issues
* `Area-PowerShellGet`: PowerShellGet related issues
* `Area-SideBySide`: side by side support
* `WG-DevEx-Portability`: anything related to authoring cross-platform or cross-architecture
  modules, cmdlets, and scripts
* `WG-DevEx-SDK`: anything related to hosting PowerShell as a runtime, PowerShell's APIs,
   PowerShell Standard, or the development of modules and cmdlets
* `WG-Engine`: core PowerShell engine, interpreter, and runtime
* `WG-Engine-Performance`: core PowerShell engine, interpreter, and runtime performance
* `WG-Engine-Providers`: built-in PowerShell providers such as FileSystem, Certificates,
   Registry, etc. (or anything returned by `Get-PSProvider`)
* `WG-Interactive-Console`: the console experience
* `WG-Interactive-Debugging`: debugging PowerShell script
* `WG-Interactive-HelpSystem`: anything related to the help infrastructure and formatting of help
* `WG-Interactive-IntelliSense`: tab completion
* `WG-Interactive-PSReadline`: PSReadline related issues
* `WG-Language`: parser, language semantics
* `WG-Quality-Test`: issues in a test or in test infrastructure
* `WG-Remoting`: PSRP issues with any transport layer
* `WG-Security`: security related areas such as [JEA](https://github.com/powershell/JEA)

### Operating Systems

These are for issues that are specific to certain Operating Systems:

* `OS-Linux`
* `OS-macOS`
* `OS-Windows`
* `OS-WSL`: Windows Subsystem for Linux

### Process Tags

The following labels are used on PRs:

* `Review - Needed` : The PR is being reviewed.  Please see [Pull Request - Code Review](https://github.com/PowerShell/PowerShell/blob/master/.github/CONTRIBUTING.md#pull-request---code-review)
* `Review - Waiting on Author` : The PR was reviewed by the team and requires changes or comments from the author before being accepted.
* `Review - Abandoned` : The PR was not updated for a significant number of days (the exact number could vary over time).
  Maintainers should look into such PRs and re-evaluate them.
* `Review - Committee` : The PR/Issue needs a review from [powershell-committee](../community/governance.md#powershell-committee)

### Miscellaneous labels

* `Blocked` : An issue cannot be addressed due to external factors,
  but should not be closed because those external factors are temporary.
* `BVT/DRT` : An issue affecting or exposed by tests that have not been open sourced.
* `Changelog Needed` : The PR requires an addition to the changelog,
  and should be removed when it has been added.
* `Committee-Reviewed` : The PR/Issue has been reviewed by the [powershell-committee](../community/governance.md#powershell-committee)
* `Compliance` : Issues with the compliance label are required to be fixed either in the long term or short term for
  Microsoft to continue to sign and release packages from the project as official Microsoft packages.
  The time frame in which it needs to be fixed should be identified in the issue.
* `Documentation Needed` : The PR has changes that require a documentation change or new documentation added to [PowerShell-Docs](https://github.com/powershell/powershell-docs)
* `First-Time-Issue` : An issue that is identified as being easy and a good candidate for first time contributors
* `Hackathon` or `Hacktoberfest` : An issue that would be a good candidate for hackathons such as `Hacktoberfest` or `Hackillinois`
* `Porting` : An issue that affects a feature not yet ported to other platforms.
* `Up-for-Grabs` : We've acknowledged the issue but have no immediate plans to address it.
  If you're looking for a way to contribute, these issues can be a good place to start.
* `Usability` : This label is used to help us filter issues that might be higher priority
  because they more directly affect the usability of a particular feature or area.
* `Waiting - DotNetCore` : An issue waiting on a fix/change in DotNetCore.

---

### Maintainers Releasing (`docs/maintainers/releasing.md`)

# PowerShell Core Releasing Process

## Release Steps

When creating a release milestone, you should send meeting invites to maintainers to book the release day and the previous day.
This is to make sure they have enough time to work on the release.

The following release procedure should be started on the previous day of the target release day.
This is to make sure we have enough buffer time to publish the release on the target day.

Before starting the following release procedure, open an issue and list all those steps as to-do tasks.
Check the task when you finish one.
This is to help track the release preparation work.

> Note: Step 2, 3 and 4 can be done in parallel.

1. Create a branch named `release-<Release Tag>` in our private repository.
   All release related changes should happen in this branch.
1. Prepare packages
   - [Build release packages](#building-packages).
   - Sign the MSI packages and DEB/RPM packages.
   - Install and verify the packages.
1. Update documentation, scripts and Dockerfiles
   - Summarize the changelog for the release. It should be reviewed by PM(s) to make it more user-friendly.
   - Update [CHANGELOG.md](../../CHANGELOG.md) with the finalized changelog draft.
   - Update other documents and scripts to use the new package names and links.
1. Verify the release Dockerfiles.
1. [Create NuGet packages](#nuget-packages) and publish them to [powershell-core feed][ps-core-feed].
1. [Create the release tag](#release-tag) and push the tag to `PowerShell/PowerShell` repository.
1. Create the draft and publish the release in GitHub.
1. Merge the `release-<Release Tag>` branch to `master` in `powershell/powershell` and delete the `release-<Release Tag>` branch.
1. Publish Linux packages to Microsoft YUM/APT repositories.
1. [Update the homebrew formula](#homebrew) for the macOS package.
   This task usually will be taken care of by the community,
   so we can wait for one day or two and see if the homebrew formula has already been updated,
   and only do the update if it hasn't.

## Building Packages

> Note: Linux and Windows packages are taken care of by our release build pipeline in VSTS,
while the macOS package needs to be built separately on a macOS.

The release build should be started based on the `release` branch.
The release Git tag won't be created until all release preparation tasks are done,
so the to-be-used release tag should be passed to the release build as an argument.

> When creating the packages, please ensure that the file path does not contain user names.
That is, clone to `/PowerShell` on Unix, and `C:\PowerShell` for Windows.
The debug symbols include the absolute path to the sources when built,
so it should appear `/PowerShell/src/powershell/System.Management.Automation`,
not `/home/username/src/PowerShell/...`.

### Packaging Overview

The `tools/packaging` module contains a `Start-PSPackage` function to build packages.
It **requires** that PowerShell Core has been built via `Start-PSBuild` from the `build.psm1` module.

#### Windows

`Start-PSPackage` supports creating ZIP and MSIX packages for Windows.
When called without `-Type` on Windows, it defaults to creating both ZIP and MSIX packages.
The packages *must* be published in release mode,
so make sure `-Configuration Release` is specified when running `Start-PSBuild`.

Note that PowerShell is always self-contained, thus using it does not require installing it.
The output of `Start-PSBuild` includes a `pwsh.exe` executable which can simply be launched.

#### Linux / macOS

The `Start-PSPackage` function delegates to `New-UnixPackage`.

For **Linux** (Debian-based distributions), it relies on the [Effing Package Management][fpm] project,
which makes building packages a breeze.

For **macOS**, it uses native packaging tools (`pkgbuild` and `productbuild`) from Xcode Command Line Tools,
eliminating the need for Ruby or fpm.

For **Linux** (Red Hat-based distributions), it uses `rpmbuild` directly.

The PowerShell man-page is generated from the Markdown-like file
[`assets/pwsh.1.ronn`][man] using [Ronn][].
The function `Start-PSBootstrap -Package` will install these tools.

To modify any property of the packages, edit the `New-UnixPackage` function.
Please also refer to the function for details on the package properties
(such as the description, maintainer, vendor, URL,
license, category, dependencies, and file layout).

> Note that the only configuration on Linux and macOS is `Linux`,
> which is release (i.e. not debug) configuration.

To support side-by-side Unix packages, we use the following design:

We will maintain a `powershell` package
which owns the `/usr/bin/pwsh` symlink,
is the latest version, and is upgradeable.
This is the only package named `powershell`
and similarly is the only package owning any symlinks,
executables, or man-pages named `powershell`.
Until we have a package repository,
this package will contain actual PowerShell bits
(i.e. it is not a meta-package).
These bits are installed to `/opt/microsoft/powershell/6.0.0-alpha.8/`,
where the version will change with each update
(and is the prerelease version).
On macOS, the prefix is `/usr/local`,
instead of `/opt/microsoft` because it is derived from BSD.

> When we have access to package repositories where dependencies can be properly resolved,
> this `powershell` package can become a meta-package which auto-installs the latest package,
> and so only owns the symlink.

For explicitly versioned packages, say for PowerShell 6.0,
we will maintain separate packages named in the form `powershell6.0`,
which owns the binary `powershell6.0`, the symlink `powershell6.0`,
the man-page `powershell6.0`,
and is installed to `/opt/microsoft/powershell/6.0/`.
Specifically this package owns nothing named `powershell`,
as only the `powershell` package owns those files.
This package is upgradeable, but should only be updated with hot-fixes.
This is a necessary consequence of Unix package managers,
as files among packages *cannot* conflict.
From a user-experience perspective,
if the user requires a specific version of PowerShell,
they should not be required to use an absolute path,
and instead should be given a binary with the version in the name.
This pattern is followed by many other languages
(Python being the most obvious example).
This same pattern can be followed for versions 6.1, 7.0, etc.,
and can be used for patch version (e.g. 6.0.1).
Use `Start-PSPackage -Name powershell6.0` to generate
the versioned `powershell6.0` package.
Without `-Name` specified, the primary `powershell`
package will instead be created.

[fpm]: https://github.com/jordansissel/fpm
[man]: ../../assets/manpage/pwsh.1.ronn
[ronn]: https://github.com/rtomayko/ronn

### Build and Packaging Examples

On macOS or a supported Linux distro, run the following commands:

```powershell
# Install dependencies
Start-PSBootstrap -Package

# Build for v6.0.0-beta.1 release
Start-PSBuild -Clean -Crossgen -PSModuleRestore -ReleaseTag v6.0.0-beta.1

# Create package for v6.0.0-beta.1 release
Start-PSPackage -ReleaseTag v6.0.0-beta.1
```

On Windows, the `-Runtime` parameter should be specified for `Start-PSBuild` to indicate what version of OS the build is targeting.

```powershell
# Install dependencies
Start-PSBootstrap -Package

# Build for v6.0.0-beta.1 release targeting Windows universal package, set -Runtime to win7-x64
Start-PSBuild -Clean -CrossGen -PSModuleRestore -Runtime win7-x64 -Configuration Release -ReleaseTag v6.0.0-beta.1
```

```powershell
# Create packages for v6.0.0-beta.1 release targeting Windows universal package.
# 'win7-x64' / 'win7-x86' should be used for -WindowsRuntime.
Start-PSPackage -Type zip -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64'
Start-PSPackage -Type msix -ReleaseTag v6.0.0-beta.1 -WindowsRuntime 'win7-x64'
```

## NuGet Packages

The NuGet packages for hosting PowerShell for Windows and non-Windows are being built-in our release build pipeline.
The assemblies from the individual Windows and Linux builds are consumed and packed into NuGet packages.
These are then released to [powershell-core feed][ps-core-feed].

[ps-core-feed]: https://powershell.myget.org/gallery/powershell-core

## Release Tag

PowerShell releases use [Semantic Versioning][semver].
Until we hit 6.0, each sprint results in a bump to the build number,
so `v6.0.0-alpha.7` goes to `v6.0.0-alpha.8`.

When a particular commit is chosen as a release,
we create an [annotated tag][tag] that names the release.
An annotated tag has a message (like a commit),
and is *not* the same as a lightweight tag.
Create one with `git tag -a v6.0.0-alpha.7 -m <message-here>`,
and use the release changelogs as the message.
Our convention is to prepend the `v` to the semantic version.
The summary (first line) of the annotated tag message should be the full release title,
e.g. 'v6.0.0-alpha.7 release of PowerShellCore'.

When the annotated tag is finalized, push it with `git push --tags`.
GitHub will see the tag and present it as an option when creating a new [release][].
Start the release, use the annotated tag's summary as the title,
and save the release as a draft while you upload the binary packages.

[semver]: https://semver.org/
[tag]: https://git-scm.com/book/en/v2/Git-Basics-Tagging
[release]: https://help.github.com/articles/creating-releases/

## Homebrew

After the release, update homebrew formula.
You need macOS to do it.

There are 2 homebrew formulas: main and preview.

### Main

Update it on stable releases.

1. Wait for a PR to show up in https://github.com/powershell/homebrew-tap, review and merge it.

### Preview

Update it on preview releases.

1. Wait for a PR to show up in https://github.com/powershell/homebrew-tap, review and merge it.

---

### Testing Guidelines PowerShellCoreTestStatus (`docs/testing-guidelines/PowerShellCoreTestStatus.md`)

# PowerShell Core Test Status

Testing has been a major part of PowerShell since its inception and PowerShell Core is no exception to that. We will continue to add tests to the repository over time, but we did not want to wait for the  

## Test Information

Here are some statistics about our current test coverage:

- More than 3000 tests have been created and are part of the repository
- More than 2200 tests are run as part of our CI system
    - More than 1000 tests have been created to validate the PowerShell Core Engine and Language
    - More than 1200 tests have been created to validate the PowerShell Core cmdlets

## PowerShell Cmdlets
The follow table represents the test coverage of the PowerShell Core Cmdlets in relation to the delivery platform as of 2016-08-17:

| Name | Linux | Windows | Test Coverage |
|---|---|---|:---:|
|Get-Acl||delivered||
|Set-Acl||delivered||
|Export-Alias|delivered|delivered|yes|
|Get-Alias|delivered|delivered|adhoc|
|Import-Alias|delivered|delivered|yes|
|New-Alias|delivered|delivered|yes|
|Set-Alias|delivered|delivered|yes|
|Compress-Archive|delivered|delivered|yes|
|Expand-Archive|delivered|delivered|yes|
|Register-ArgumentCompleter|delivered|delivered|yes|
|Get-AuthenticodeSignature||delivered||
|Set-AuthenticodeSignature||delivered||
|Export-BinaryMiLog||delivered||
|Import-BinaryMiLog||delivered||
|Get-ChildItem|delivered|delivered|yes|
|Get-CimAssociatedInstance||delivered||
|Get-CimClass||delivered|yes|
|Register-CimIndicationEvent||delivered||
|Get-CimInstance||delivered||
|New-CimInstance||delivered||
|Remove-CimInstance||delivered||
|Set-CimInstance||delivered||
|Invoke-CimMethod||delivered||
|Get-CimSession||delivered||
|New-CimSession||delivered||
|Remove-CimSession||delivered||
|New-CimSessionOption||delivered||
|Export-Clixml|delivered|delivered|yes|
|Import-Clixml|delivered|delivered|yes|
|Find-Command|delivered|delivered|adhoc|
|Get-Command|delivered|delivered|yes|
|Invoke-Command|delivered|delivered|yes|
|Measure-Command|delivered|delivered|yes|
|Rename-Computer||delivered||
|Restart-Computer||delivered||
|Stop-Computer||delivered||
|Get-ComputerInfo||delivered||
|Test-Connection||delivered||
|Add-Content|delivered|delivered|yes|
|Clear-Content|delivered|delivered|yes|
|Get-Content|delivered|delivered|yes|
|Set-Content|delivered|delivered|yes|
|Get-Credential|delivered|delivered|adhoc|
|ConvertFrom-Csv|delivered|delivered|yes|
|ConvertTo-Csv|delivered|delivered|yes|
|Export-Csv|delivered|delivered|yes|
|Import-Csv|delivered|delivered|yes|
|Get-Culture|delivered|delivered|yes|
|Format-Custom|delivered|delivered|yes|
|Get-Date|delivered|delivered|yes|
|Set-Date|delivered|delivered||
|Write-Debug|delivered|delivered|yes|
|Wait-Debugger|delivered|delivered||
|Out-Default|delivered|delivered|adhoc|
|Find-DscResource|delivered|delivered||
|Register-EngineEvent|delivered|delivered|yes|
|Write-Error|delivered|delivered|yes|
|Get-Event|delivered|delivered|yes|
|New-Event|delivered|delivered|yes|
|Remove-Event|delivered|delivered|yes|
|Unregister-Event|delivered|delivered|yes|
|Wait-Event|delivered|delivered|yes|
|Get-EventSubscriber|delivered|delivered|yes|
|Get-ExecutionPolicy|delivered|delivered|yes|
|Set-ExecutionPolicy|delivered|delivered|yes|
|Invoke-Expression|delivered|delivered|yes|
|Out-File|delivered|delivered|yes|
|Unblock-File||delivered||
|New-FileCatalog||delivered|yes|
|Test-FileCatalog||delivered|yes|
|Get-FileHash|delivered|delivered|yes|
|Export-FormatData|delivered|delivered|yes|
|Get-FormatData|delivered|delivered|yes|
|Update-FormatData|delivered|delivered|yes|
|New-Guid|delivered|delivered|yes|
|Get-Help|delivered|delivered|yes|
|Save-Help|delivered|delivered|adhoc|
|Update-Help|delivered|delivered|adhoc|
|Format-Hex|delivered|delivered|yes|
|Add-History|delivered|delivered|adhoc|
|Clear-History|delivered|delivered|adhoc|
|Get-History|delivered|delivered|adhoc|
|Invoke-History|delivered|delivered|adhoc|
|Get-Host|delivered|delivered|yes|
|Out-Host|delivered|delivered|yes|
|Read-Host|delivered|delivered|adhoc|
|Write-Host|delivered|delivered|yes|
|Write-Information|delivered|delivered|adhoc|
|Get-InstalledModule|delivered|delivered|yes|
|Get-InstalledScript|delivered|delivered||
|Clear-Item|delivered|delivered|adhoc|
|Copy-Item|delivered|delivered|yes|
|Get-Item|delivered|delivered|yes|
|Invoke-Item|delivered|delivered|yes|
|Move-Item|delivered|delivered|adhoc|
|New-Item|delivered|delivered|yes|
|Remove-Item|delivered|delivered|yes|
|Rename-Item|delivered|delivered|adhoc|
|Set-Item|delivered|delivered|adhoc|
|Clear-ItemProperty|delivered|delivered|adhoc|
|Copy-ItemProperty|delivered|delivered|adhoc|
|Get-ItemProperty|delivered|delivered|yes|
|Move-ItemProperty|delivered|delivered||
|New-ItemProperty|delivered|delivered|adhoc|
|Remove-ItemProperty|delivered|delivered|adhoc|
|Rename-ItemProperty|delivered|delivered|adhoc|
|Set-ItemProperty|delivered|delivered|yes|
|Get-ItemPropertyValue|delivered|delivered||
|Debug-Job|delivered|delivered|adhoc|
|Get-Job|delivered|delivered|adhoc|
|Receive-Job|delivered|delivered|yes|
|Remove-Job|delivered|delivered|adhoc|
|Start-Job|delivered|delivered|yes|
|Stop-Job|delivered|delivered|adhoc|
|Wait-Job|delivered|delivered|adhoc|
|ConvertFrom-Json|delivered|delivered|yes|
|ConvertTo-Json|delivered|delivered|yes|
|Format-List|delivered|delivered|yes|
|Get-LocalGroup||delivered||
|New-LocalGroup||delivered||
|Remove-LocalGroup||delivered||
|Rename-LocalGroup||delivered||
|Set-LocalGroup||delivered||
|Add-LocalGroupMember||delivered||
|Get-LocalGroupMember||delivered||
|Remove-LocalGroupMember||delivered||
|Import-LocalizedData|delivered|delivered|yes|
|Disable-LocalUser||delivered||
|Enable-LocalUser||delivered||
|Get-LocalUser||delivered||
|New-LocalUser||delivered||
|Remove-LocalUser||delivered||
|Rename-LocalUser||delivered||
|Set-LocalUser||delivered||
|Get-Location|delivered|delivered|yes|
|Pop-Location|delivered|delivered|yes|
|Push-Location|delivered|delivered|yes|
|Set-Location|delivered|delivered|yes|
|Get-LogProperties||delivered||
|Set-LogProperties||delivered||
|Add-Member|delivered|delivered|yes|
|Get-Member|delivered|delivered|yes|
|Find-Module|delivered|delivered|adhoc|
|Get-Module|delivered|delivered|yes|
|Import-Module|delivered|delivered|yes|
|Install-Module|delivered|delivered|adhoc|
|New-Module|delivered|delivered|yes|
|Publish-Module|delivered|delivered||
|Remove-Module|delivered|delivered|yes|
|Save-Module|delivered|delivered|adhoc|
|Uninstall-Module|delivered|delivered||
|Update-Module|delivered|delivered||
|New-ModuleManifest|delivered|delivered|yes|
|Test-ModuleManifest|delivered|delivered||
|Update-ModuleManifest|delivered|delivered||
|Export-ModuleMember|delivered|delivered|yes|
|Out-Null|delivered|delivered|yes|
|Compare-Object|delivered|delivered|yes|
|ForEach-Object|delivered|delivered|yes|
|Group-Object|delivered|delivered|yes|
|Measure-Object|delivered|delivered|yes|
|New-Object|delivered|delivered|yes|
|Select-Object|delivered|delivered|yes|
|Sort-Object|delivered|delivered|yes|
|Tee-Object|delivered|delivered|yes|
|Where-Object|delivered|delivered|yes|
|Register-ObjectEvent|delivered|delivered|yes|
|Write-Output|delivered|delivered|yes|
|Find-Package|delivered|delivered|yes|
|Get-Package|delivered|delivered|yes|
|Install-Package|delivered|delivered|yes|
|Save-Package|delivered|delivered|yes|
|Uninstall-Package|delivered|delivered|yes|
|Find-PackageProvider|delivered|delivered|yes|
|Get-PackageProvider|delivered|delivered|yes|
|Import-PackageProvider|delivered|delivered|yes|
|Install-PackageProvider|delivered|delivered|yes|
|Get-PackageSource|delivered|delivered|yes|
|Register-PackageSource|delivered|delivered|yes|
|Set-PackageSource|delivered|delivered|yes|
|Unregister-PackageSource|delivered|delivered|yes|
|Convert-Path|delivered|delivered|adhoc|
|Join-Path|delivered|delivered|yes|
|Resolve-Path|delivered|delivered|adhoc|
|Split-Path|delivered|delivered|yes|
|Test-Path|delivered|delivered|yes|
|Import-PowerShellDataFile|delivered|delivered|yes|
|Debug-Process|delivered|delivered||
|Get-Process|delivered|delivered|yes|
|Start-Process|delivered|delivered|yes|
|Stop-Process|delivered|delivered|yes|
|Wait-Process|delivered|delivered||
|Write-Progress|delivered|delivered|yes|
|Disable-PSBreakpoint|delivered|delivered||
|Enable-PSBreakpoint|delivered|delivered||
|Get-PSBreakpoint|delivered|delivered|yes|
|Remove-PSBreakpoint|delivered|delivered|yes|
|Set-PSBreakpoint|delivered|delivered|yes|
|Get-PSCallStack|delivered|delivered|adhoc|
|Set-PSDebug|delivered|delivered|yes|
|Get-PSDrive|delivered|delivered|yes|
|New-PSDrive|delivered|delivered|yes|
|Remove-PSDrive|delivered|delivered|yes|
|Enter-PSHostProcess|delivered|delivered|yes|
|Exit-PSHostProcess|delivered|delivered|yes|
|Get-PSHostProcessInfo|delivered|delivered|fails on Linux|
|Get-PSProvider|delivered|delivered|yes|
|Get-PSReadlineKeyHandler|delivered|delivered|yes|
|Remove-PSReadlineKeyHandler|delivered|delivered||
|Set-PSReadlineKeyHandler|delivered|delivered|yes|
|Get-PSReadlineOption|delivered|delivered|yes|
|Set-PSReadlineOption|delivered|delivered|yes|
|Get-PSRepository|delivered|delivered||
|Register-PSRepository|delivered|delivered||
|Set-PSRepository|delivered|delivered||
|Unregister-PSRepository|delivered|delivered||
|New-PSRoleCapabilityFile|delivered|delivered||
|Connect-PSSession|delivered|delivered|adhoc|
|Disconnect-PSSession|delivered|delivered|adhoc|
|Enter-PSSession|delivered|delivered|adhoc|
|Exit-PSSession|delivered|delivered|adhoc|
|Get-PSSession|delivered|delivered|adhoc|
|New-PSSession|delivered|delivered|yes|
|Receive-PSSession|delivered|delivered|adhoc|
|Remove-PSSession|delivered|delivered|yes|
|Get-PSSessionCapability|delivered|delivered||
|Disable-PSSessionConfiguration|delivered|delivered||
|Enable-PSSessionConfiguration|delivered|delivered||
|Get-PSSessionConfiguration|delivered|delivered||
|Register-PSSessionConfiguration|delivered|delivered|yes|
|Set-PSSessionConfiguration|delivered|delivered||
|Unregister-PSSessionConfiguration|delivered|delivered|yes|
|New-PSSessionConfigurationFile|delivered|delivered|yes|
|Test-PSSessionConfigurationFile|delivered|delivered||
|New-PSSessionOption|delivered|delivered||
|Disable-PSTrace||delivered||
|Enable-PSTrace||delivered||
|New-PSTransportOption|delivered|delivered||
|Disable-PSWSManCombinedTrace||delivered||
|Enable-PSWSManCombinedTrace||delivered||
|Get-Random|delivered|delivered|yes|
|Invoke-RestMethod|delivered|delivered|yes|
|Find-RoleCapability|delivered|delivered||
|Debug-Runspace|delivered|delivered||
|Get-Runspace|delivered|delivered|yes|
|Disable-RunspaceDebug|delivered|delivered||
|Enable-RunspaceDebug|delivered|delivered||
|Get-RunspaceDebug|delivered|delivered|yes|
|Find-Script|delivered|delivered||
|Install-Script|delivered|delivered||
|Publish-Script|delivered|delivered||
|Save-Script|delivered|delivered||
|Uninstall-Script|delivered|delivered||
|Update-Script|delivered|delivered||
|New-ScriptFileInfo|delivered|delivered||
|Test-ScriptFileInfo|delivered|delivered||
|Update-ScriptFileInfo|delivered|delivered||
|ConvertFrom-SddlString||delivered||
|ConvertFrom-SecureString|delivered|delivered|yes|
|ConvertTo-SecureString|delivered|delivered|yes|
|Get-Service||delivered||
|New-Service||delivered||
|Restart-Service||delivered||
|Resume-Service||delivered||
|Set-Service||delivered||
|Start-Service||delivered||
|Stop-Service||delivered||
|Suspend-Service||delivered||
|Start-Sleep|delivered|delivered|yes|
|Set-StrictMode|delivered|delivered|yes|
|Out-String|delivered|delivered|yes|
|Select-String|delivered|delivered|yes|
|ConvertFrom-StringData|delivered|delivered|yes|
|Format-Table|delivered|delivered|yes|
|New-TemporaryFile|delivered|delivered|yes|
|New-TimeSpan|delivered|delivered|yes|
|Get-TimeZone||delivered|yes|
|Set-TimeZone||delivered|yes|
|Start-Trace||delivered||
|Stop-Trace||delivered||
|Start-Transcript|delivered|delivered|yes|
|Stop-Transcript|delivered|delivered|yes|
|Add-Type|delivered|delivered|yes|
|Get-TypeData|delivered|delivered|yes|
|Remove-TypeData|delivered|delivered|yes|
|Update-TypeData|delivered|delivered|yes|
|Get-UICulture|delivered|delivered|yes|
|Get-Unique|delivered|delivered|yes|
|Clear-Variable|delivered|delivered|yes|
|Get-Variable|delivered|delivered|yes|
|New-Variable|delivered|delivered|yes|
|Remove-Variable|delivered|delivered|yes|
|Set-Variable|delivered|delivered|yes|
|Write-Verbose|delivered|delivered|yes|
|Write-Warning|delivered|delivered|yes|
|Invoke-WebRequest|delivered|delivered|yes|
|Format-Wide|delivered|delivered|yes|
|Get-WinEvent||delivered|yes|
|New-WinEvent||delivered||
|Connect-WSMan||delivered||
|Disconnect-WSMan||delivered||
|Test-WSMan||delivered||
|Invoke-WSManAction||delivered||
|Disable-WSManCredSSP||delivered||
|Enable-WSManCredSSP||delivered||
|Get-WSManCredSSP||delivered||
|Get-WSManInstance||delivered||
|New-WSManInstance||delivered||
|Remove-WSManInstance||delivered||
|Set-WSManInstance||delivered||
|Set-WSManQuickConfig||delivered||
|New-WSManSessionOption||delivered||
|Disable-WSManTrace||delivered||
|Enable-WSManTrace||delivered||
|ConvertTo-Xml|delivered|delivered|yes|
|Select-xml|delivered|delivered|yes|

---

### Testing Guidelines TestRoadmap (`docs/testing-guidelines/TestRoadmap.md`)

# Overview
While we have done a fairly good job providing adequate coverage for the highest priority areas of PowerShell Core, we still have lots of gaps when we compare what is available in the OSS project vs what we have available as part of the Windows release test infrastructure.
This is to be expected as that infrastructure was built up over more than a decade.
It is not clear, however, how many of the current tests actually provide value, and how much duplication we have.
In any event, there is still a large difference in what we have in PowerShell Core and our older tests.

# Data Visibility
In both PowerShell Core or our proprietary tests we can't actually determine how and what cmdlets and engine functions (language/scripting/debugging/remoting) are being tested because we do not gather any usage telemetry on what our tests are doing during test execution.
We have no way via automation to determine how thoroughly we are testing our code except by inspecting the actual tests or looking at code coverage data (which isn't gathered often and only available on full PowerShell).
Further, this doesn't provide us data with regard to the test quality, only that we've covered a specific block of code.
The areas of greatest risk are those where we have no data at all, by collecting coverage data we can illuminate those code paths that are not being used and fill those gaps with new tests.

## Telemetry and Logging
While we have some telemetry feeds on Windows, we have _no_ telemetry capabilities on non-Windows platforms.
We should enable telemetry on PowerShell Core on all platforms and review the usage data as soon as possible.
This will provide us much needed visibility in how PowerShell Core is being used and can help us identify areas we should track more closely.
We already have infrastructure in place to allow us see how PowerShell Core is being used, by collecting telemetry from PowerShell Core, we can improve our confidence as we drive to production quality.

### Logging
The code which on Windows create ETW logging has been completely stubbed out on Linux/macOS.
We should take advantage of the native logging mechanisms on Linux/macOS and implement a logger similar to the ETW logger on Windows using Syslog (or equivalent).
We could use this data during test runs to identify test gaps.
Simply by capturing the cmdlets and their parameters which are invoked during test would illuminate the gaps we have in our current tests, and allow us to easily fill them.
It is not sufficient to support only one platform because we have many tests which determine at runtime whether or not it should run based on OS, so data from Windows will not be the same as that from Linux or MacOS.
We can also determine engine coverage gaps by measuring test of operators and other language elements.
Without that data, we are simply shooting in the dark.

## Code coverage
Even in our lab (STEX) environment we run tests to get code coverage data irregularly, and  PowerShell Core has _no_ tools to gather code coverage data.
We need to investigate possible solutions for code coverage on PowerShell Core.
There are a small number of solutions available:
* [OpenCover](https://github.com/OpenCover/opencover)
    * OpenCover is currently used by corefx to produce code coverage data, also visualization is available via [CoverAlls](https://coveralls.io/github/OpenCover/opencover).
    We should investigate `OpenCover` and determine it's feasibility for us.
    Unfortunately I haven't been able to find a solution for Linux
* DotCover
    * I have contacted `JetBrains` to see if they have any solutions which may be used with .NET Core.

If we can get code coverage on PowerShell Core on Windows, we would at least be able to have _some_ data to illuminate our test gaps.

Running code coverage more often on full PowerShell is something that we should consider, if it will help us close existing test coverage gaps, but the issue is _not_ test coverage for full PowerShell, but rather PowerShell Core where we have only a small percentage of tests in comparison.

## Daily Test Runs
We currently run only those tests which are tagged `CI` excluding the tag `SLOW` as part of our continuous integration systems.
This means roughly 1/3rd of our github tests are not being run on any regular schedule.
In order to provide us with higher confidence in our code, we should be running *ALL* of our tests on a regular basis.
However, running the tests is only the first step, we need an easy way to be notified of test failures, and to track progress of those runs over time.
Tracking this over time affords us the ability to see how our test count increases, implying an improvement in coverage.
It also provides us mechanism whereby we can see trends in instability.

### Pending and Skipped Tests
We currently have approximately 300 tests which are marked either as `skipped` or `pending`.
`Pending` tests represent those tests which should be run but are not currently being executed, usually because the underlying functionality is not present.
Over time, the number of `Pending` tests should drive to zero, and we should be tracking the list of tests which are marked `pending` and track those to be sure that they do not spend too long in this state.
`Skipped` tests due to platform applicability are certainly valid, and it is important that we track how many tests are skipped and for what reason.
A test which is skipped for all platforms should be considered carefully as to whether it should exist at all.
In either case, `pending` or `skipped` tests should be tracked over time so we can determine whether we are improving our ability to measure quality.

In the best case, the _total_ number of tests is the same across all platforms.
The count of Skipped/Pending tests would naturally be different as not all tests will be applicable to every platform, but if we can have consistency of test count across platforms, it will be easier to compare test results on one platform vs another.

## Remoting Considerations
Given that one of the targeted scenarios is to manage heterogeneous environments remotely, we need a test environment which encompasses the available platforms and protocols.
Our current test infrastructure does not have comprehensive support for remote testing except for loopback operations.
We need a matrix of protocols and platforms to ensure that we have adequate coverage to ensure quality.

In addition to loopback tests using both WSMan and SSH protocols, we should have the following _minimum_ matrix of client/server connections for both WSMan and SSH (where available) protocols.
* Windows Client->Nano Server
* Windows Client->Linux Server
* Linux Client -> Windows Server
* macOS Client -> Nano Client
* PowerShell Core Client -> Full PowerShell Server
* Full PowerShell Client -> PowerShell Core Server
* Downlevel Full PowerShell Client -> PowerShell Core Server

### Challenges
* On Windows, we have cmdlets to enable and disable remote access, those cmdlets do not exist on non-Windows platforms (they rely on configuration stored in the registry), nor do we support configuration for the SSH protocol.
We need to be sure that we can easily enable remoting for the non-Windows platforms and support both WSMan _and_ SSH configurations.
* Our current multi-machine tests do not test the connection code, they simply execute test code remotely and retrieve results and assume a good connection.
The infrastructure used for these tests is STEX which is not an open environment.
We will need to create automation to create and configure the test systems in the test matrix and then invoke tests on them.
It is not clear that our current CI systems can accommodate our needs here as Azure DevOps can supply us with all of the OS images needed.
We may need to create our own heterogeneous environment in Azure, or look to other teams (MS Build Lab/Jenkins) for assistance.

We need to investigate whether there are solutions available, and if not, design/implement an environment to meet our needs.

# Reporting
Currently, we report against the simplest of KPI:
* is the CI build error free (which is part of the PR/Merge process - and reported on our landing page)

There are a number of KPIs which we could report on:
* Code KPIs
    * What is the coverage (% blocks covered) of our `CI` tests
    * What is the coverage of all tests
    * How long is the CI system taking
        * build time
        * test time
    * What is the percentage of pull requests pass `CI` tests
    * What is the trend for `pending` tests
* Process KPIs
    * What is the time delta between a posted PR (with no test errors) and merge
    * How many revisions are needed before a PR is accepted
    * How many PRs are rejected
* Product KPIs
    * What is the usage of PowerShell Core on the various platforms
    * What are the common operations performed by PowerShell Core (cmdlet usage)
    * How many remote connections are created in a session

## Reporting Priorities
1. As a baseline, we should report code coverage on current Full PowerShell from the latest Windows release
2. We should report on code coverage as soon as possible.
This is the tool that will enable us to at least determine where we have _no_ data and illuminate test gaps.
3. We should track our CI execution time, which will allow us to keep an eye on our code submission workflow and how much our developers are waiting for builds

### Public Dashboard
Because we collect the test results as a build artifact, it is possible to collect and collate this data and provide a number of dash-board reports.
Since we are an OSS project, it makes sense that our reports should be also public.
A public dashboard provides evidence that we are not collecting PII, increasing trust in the project and shows that we are using data to drive product decisions.
We could easily create a web presence in Azure which would enable us to provide reporting on the current and historical state of our tests.
Now that we are running all of our tests on a nightly basis, we should be communicating the results of those test runs.
PowerBI could be used to create the visualizations, which would reduce the time and effort.

In order to achieve this we need to:
* Designate an Azure instance to run services and populate Azure tables:
    * Create tools to retrieve and transform git data
    * Create tools to retrieve and transform the test data
* Create PowerBI queries to visualize our KPIs

# Release Criteria
We must start defining the release criteria for a production ready release of PowerShell Core, as an initial proposal:
* No open issues for the release
* 80% code coverage of high use cmdlets (cmdlets used by 70% of users, as captured via telemetry)
* 90% code coverage of language elements (coverage error code paths may not be 100%)
* 60% code Coverage on Windows via Github tests
* 100% of our minimum remoting matrix tested
* Acceptance by 50% PowerShell MVPs (via Survey)
* Acceptance by Partners (via Survey)

A couple of assumptions have been made for this list:
1) we actually know the high use cmdlets - this implies we have telemetry to determine our cmdlet use
2) we have designated our Partners

# Microsoft Release Process
If PowerShell Core is targeted to be released as part of Windows Server or Nano, we will have additional requirements which must be met with regard to acceptance by the Windows org of the PowerShell Core package.
This represents additional work which needs planning and allocated resources.

## Replace STEX tests with PowerShell Core tests
Currently we have two distinct set of test artifacts, those used in PowerShell Core and our traditional lab (STEX) based tests.
We are creating new tests for PowerShell Core using the existing tests as guidance, but this is creating duplication between the two sets so we need to find ways to invoke our current PowerShell Core tests as part of our STEX based runs.
When we do this, we can start to delete our existing tests and reduce the maintenance burden due to duplicated tests.

**Proposal**

* Create a way to invoke our github based tests in lab runs

## Historical Tests
The PowerShell team created roughly 90,000 tests since the beginning of the project starting in 2003.
Initially tests were created in a C# framework which was used internally at Microsoft.
After that, a number of script based frameworks were created to run script based tests.
We have decided not to release those for a number of reasons:
* All the frameworks have a core assumption of running in the Microsoft Lab environment and rely on internal Microsoft tools
* All the frameworks rely on specific logging file formats used by internal Microsoft reporting tools
* Some of the frameworks have limitations which we can avoid by recasting/recreating them as `Pester` or `xUnit` tests

While, these reasons are not insurmountable, releasing these tests with their custom frameworks does not help us with our desire to promulgate open solutions.
Further, by creating/releasing `xUnit` and `Pester` tests we can take the opportunity to review existing tests and improve them, or eliminate them if they are poor, or duplicate tests.
It is obvious that the review of more than 90,000 tests is an enormous undertaking, and will take some time, and we are committed to creating a set of tests which can provide confidence that PowerShell Core has the same quality as earlier releases of PowerShell.

## Challenges ##
While there is a test gap between what is available on Github vs what is available via our internal proprietary tests, it may be possible to use our existing tests (and frameworks) against PowerShell Core.
This is an attractive potential because we have very high confidence of our current tests.
Moreover, we could also collect code coverage data during a test pass.
It would be expected to have a number of test failures because different functionality between PowerShell Core and Full PowerShell but collecting this data would enable us to enumerate those difference.
Unfortunately, the current logging mechanism used in our in-lab tests are not available in PowerShell Core, and a new logging mechanism would need to be created

**Proposal**

* Investigate the effort to run our historical tests in a PowerShell Core environment

# Action Plan
This document represents a number of initiatives, all of which will take resources.
Below is my suggestion for prioritization to reduce risk and improve confidence in our overall quality:

1. Implement telemetry feeds for PowerShell Core
2. Implement data collection feeds from our CI systems
3. Create a public dashboard to visualize our KPIs
    * including data from 1, 2 above
4. Implement Code Coverage on PowerShell Core
5. Design/Implement remoting test infrastructure
6. Replace in-lab tests with PowerShell Core tests
7. Investigate feasibility of running current in-lab tests on PowerShell Core

These are [tracked](https://github.com/PowerShell/PowerShell/issues?utf8=%E2%9C%93&q=is%3Aissue%20%23testability%20) as issues

---

### Testing Guidelines WritingPesterTests (`docs/testing-guidelines/WritingPesterTests.md`)

# Writing Pester Tests

Note that this document does not replace the documents found in the [Pester](https://github.com/pester/pester) project.
This is just some quick tips and suggestions for creating Pester tests for this project.
The Pester community is vibrant and active, if you have questions about Pester or creating tests, the [Pester Wiki](https://github.com/pester/pester/wiki) has a lot of great information.
As of January 2018, PowerShell Core is using Pester version 4 which has some changes from earlier versions.
See [Migrating from Pester 3 to Pester 4](https://github.com/pester/Pester/wiki/Migrating-from-Pester-3-to-Pester-4) for more information.

When creating tests, keep the following in mind:

- Tests should not be overly complicated and test too many things.
    - Boil down your tests to their essence, test only what you need.
- Tests should be as simple as they can.
- Tests should generally not rely on any other test.

## Examples

Here's the simplest of tests:

```powershell
Describe "A variable can be assigned and retrieved" {
    It "Creates a variable and makes sure its value is correct" {
       $a = 1
       $a | Should -Be 1
   }
}
```

If you need to do type checking, that can be done as well:

```powershell
Describe "One is really one" {
    It "Compare 1 to 1" {
       $a = 1
       $a | Should -Be 1
    }
    It "1 is really an int" {
       $i = 1
       $i | Should -BeOfType System.Int32
    }
}
```

If you are checking for proper errors, use the `Should -Throw -ErrorId` Pester syntax.
It checks against `FullyQualifiedErrorId` property, which is recommended because it does not change based on culture as an error message might.

```powershell
...
It "Get-Item on a nonexisting file should have error PathNotFound" {
    { Get-Item "ThisFileCannotPossiblyExist" -ErrorAction Stop } | Should -Throw -ErrorId "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
}
```

Note that if `Get-Item` were to succeed, the test will fail.

However, if you need to check the `InnerException` or other members of the ErrorRecord, you should use `-PassThru` parameter:

```powershell
It "InnerException sample" {
   $e = { Invoke-WebRequest https://expired.badssl.com/ } | Should -Throw -ErrorId "WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand" -PassThru
   $e.Exception.InnerException.NativeErrorCode | Should -Be 12175
}
```

## Describe/Context/It

For creation of PowerShell tests, the `Describe` block is the level of granularity suggested and one of three tags should be used: `CI`, `Feature`, or `Scenario`.

If the tag is not provided, the build process will fail.

### Describe

Creates a logical group of tests.
All `Mocks` and `TestDrive` contents defined within a `Describe` block are scoped to that `Describe`;
they will no longer be present when the `Describe` block exits.
A `Describe` block may contain any number of `Context` and `It` blocks.

### Context

Provides logical grouping of `It` blocks within a single `Describe` block. Any `Mocks` defined inside a `Context` are removed at the end of the `Context` scope, as are any files or folders added to the `TestDrive` during the `Context` block's execution. 

Any `BeforeEach` or `AfterEach` blocks defined inside a `Context` also only apply to tests within that `Context`.

### It

The `It` block is intended to be used inside of a `Describe` or `Context` block. If you are familiar with the AAA pattern (Arrange-Act-Assert), the body of the  `It` block is the appropriate location for an assert.

The convention is to assert a single expectation for each `It` block. The code inside of the `It` block should throw a terminating error if the expectation of the test is not met and thus cause the test to fail.

The name of the `It` block should expressively state the expectation of the test.

## Admin privileges in tests

Tests that require admin privileges **on Windows** must be additionally marked with `RequireAdminOnWindows` Pester tag.

In the Azure DevOps Windows CI, we run two different passes:

- The pass with exclusion of `RequireAdminOnWindows` tagged tests.
- The pass where only `RequireAdminOnWindows` tagged tests are being executed.

In each case, tests are executed with appropriate privileges.

Tests that need to be run with sudo **on Unix systems** must be additionally marked with `RequireSudoOnUnix` Pester tag.

`RequireSudoOnUnix` tag takes precedence over all other tags like `CI`, `Feature`, etc. (which are ignored when `RequireSudoOnUnix` is present).
Tests tagged with `RequireSudoOnUnix` will run as a separate pass for any Unix test.

## Selected Features

### Test Drive

A `PSDrive` is available for file activity during a test and this drive is limited to the scope of a single `Describe` block. The contents of the drive are cleared when a `Context` block is exited.

A test may need to work with file operations and validate certain types of file activities. It is usually desirable not to perform file activity tests that will produce side effects outside of an individual test.

Pester creates a `PSDrive` inside the user's temporary drive that is accessible via `TestDrive:` or `$TestDrive`. **Pester will remove** this drive after the test completes.
You may use this drive to isolate the file operations of your test to a temporary store.

The following example illustrates the feature:

```powershell
function Add-Footer($path, $footer) {
   Add-Content $path -Value $footer
}

Describe "Add-Footer" {
   $testPath="TestDrive:\test.txt"
   Set-Content $testPath -value "my test text."
   Add-Footer $testPath "-Footer"
   $result = Get-Content $testPath

   It "adds a footer" {
       (-join $result) | Should -BeExactly "my test text.-Footer"
   }
}
```

When this test completes, the contents of the `TestDrive:` will be removed.

### Parameter Generation

```powershell
$testCases = @(
    @{ a = 0; b = 1; ExpectedResult = 1 }
    @{ a = 1; b = 0; ExpectedResult = 1 }
    @{ a = 1; b = 1; ExpectedResult = 0 }
    @{ a = 0; b = 0; ExpectedResult = 0 }
    )

Describe "A test" {
    It "<a> -xor <b> should be <expectedresult>" -TestCases $testCases {
        param ($a, $b, $ExpectedResult)
        $a -xor $b | Should -Be $ExpectedResult
    }
}
```

### Mocking

Mocks the behavior of an existing command with an alternate implementation. This creates new behavior for any existing command within the scope of a `Describe` or `Context` block.
The function allows you to specify a script block that will become the command's new behavior.

The following example illustrates simple use:

```powershell
Context "Get-Random is not random" {
    Mock Get-Random { return 3 }

    It "Get-Random returns 3" {
        Get-Random | Should -Be 3
    }
}
```

More information may be found [here](https://github.com/pester/Pester/wiki/Mock).

### Free Code in a Describe block

Code execution in Pester can be very subtle and can cause issues when executing test code. The execution of code which lays outside of the usual code blocks may not happen as you expect. Consider the following:

```powershell
Describe it {
    Write-Host -For DarkRed "Before Context"
    Context "subsection" {
        Write-Host -for DarkRed "Before BeforeAll"
        BeforeAll { write-host -for Blue "In Context BeforeAll" }
        Write-Host -for DarkRed "After BeforeAll"

        Write-Host -for DarkRed "Before AfterAll"
        AfterAll { Write-Host -for Blue "In Context AfterAll" }
        Write-Host -for DarkRed "After AfterAll"

        BeforeEach { Write-Host -for Blue "In BeforeEach" }
        AfterEach { Write-Host -for Blue "In AfterEach" }

        Write-Host -for DarkRed "Before It"
        It "should not be a surprise" {
            1 | should -Be 1
        }
        Write-Host -for DarkRed "After It"
    }
    Write-Host -for DarkRed "After Context"
    Write-Host -for DarkGreen "Before Describe BeforeAll"
    BeforeAll { Write-Host -for DarkGreen "In Describe BeforeAll" }
    AfterAll { Write-Host -for DarkGreen "In Describe AfterAll" }
}
```

Now, when run, you can see the execution schedule:

```
PS# invoke-pester c:\temp\pester.demo.tests.ps1
Describing it
In Describe BeforeAll
Before Context
   Context subsection
In Context BeforeAll
Before BeforeAll
After BeforeAll
Before AfterAll
After AfterAll
Before It
In BeforeEach
    [+] should not be a surprise 79ms
In AfterEach
After It
In Context AfterAll
After Context
Before Describe BeforeAll
In Describe AfterAll
Tests completed in 79ms
Passed: 1 Failed: 0 Skipped: 0 Pending: 0
```

The `Describe` - `BeforeAll` block is executed before any other code even though it was at the bottom of the `Describe` block.
So if some state is set elsewhere in the `Describe` block, that state will not yet be visible (as the code will not yet been run).

Notice, too, that the `BeforeAll` block in `Context` is executed before any other code in that block.
Generally, you should have code reside in one of the code block elements of `BeforeAll`, `BeforeEach`, `AfterEach` and/or `AfterAll`, especially if those blocks rely on some state set by free code elsewhere in the block.

### Skipping Tests in Bulk

Sometimes it is beneficial to skip all the tests in a particular `Describe` block.
For example, tests which are not applicable to a platform could be skipped, and they would be reported as skipped.

The following is an example of how this may be done:

```powershell
Describe "Should not run these tests on non-Windows platforms" {
    BeforeAll {
        $originalDefaultParameterValues = $PSDefaultParameterValues.Clone()
        if ( ! $IsWindows ) {
            $PSDefaultParameterValues["it:skip"] = $true
        }
    }
    AfterAll {
        $global:PSDefaultParameterValues = $originalDefaultParameterValues
    }
    Context "Block 1" {
        It "This block 1 test 1" {
            1 | should -Be 1
        }
        It "This is block 1 test 2" {
            1 | should -Be 1
        }
    }
    Context "Block 2" {
        It "This block 2 test 1" {
            2 | should -Be 1
        }
        It "This is block 2 test 2" {
            2 | should -Be 1
        }
    }
}
```

Here is the output when run on a Linux distribution:

```
Describing Should not run these tests on non-Windows platforms
   Context Block 1
    [!] This block 1 test 1 691ms
    [!] This is block 1 test 2 114ms
   Context Block 2
    [!] This block 2 test 1 73ms
    [!] This is block 2 test 2 6ms
```

and here is the output when run on a Windows distribution:

```
Describing Should not run these tests on non-Windows platforms
   Context Block 1
    [+] This block 1 test 1 86ms
    [+] This is block 1 test 2 33ms
   Context Block 2
    [-] This block 2 test 1 52ms
      Expected: {1}
      But was:  {2}
      22:             2 | should -Be 1
      at <ScriptBlock>, <No file>: line 22
    [-] This is block 2 test 2 77ms
      Expected: {1}
      But was:  {2}
      25:             2 | should -Be 1
      at <ScriptBlock>, <No file>: line 25
```

This technique uses the `$PSDefaultParameterValues` feature of PowerShell to temporarily set the `It` block parameter `-skip` to true (or in the case of Windows, it is not set at all)

### Multi-line strings

You may want to have a test like:

```powershell
It 'tests multi-line string' {
    Get-MultiLineString | Should -Be @'
first line
second line
'@
}
```

There are problems with using multi-line strings with verifying the output results.
The reason for it are line-ends.

They cause problems for two reasons:

- They are different on different platforms (`\r\n` on Windows and `\n` on Unix).
- Even on the same system, they depend on the way how the repo was cloned (local git configuration).

Particularly, in the default Azure DevOps CI Windows image, you will get `\n` line ends in all your files.
That causes problems, because at runtime `Get-MultiLineString` would likely produce `\r\n` line ends on Windows.

Some workaround could be added, but they are sub-optimal and make reading test code harder.

```powershell
function normalizeEnds([string]$text)
{
    $text -replace "`r`n?|`n", "`r`n"
}

It 'tests multi-line string' {
    normalizeEnds (Get-MultiLineString) | Should -Be (normalizeEnds @'
first line
second line
'@)
}
```

When appropriate, you can avoid creating multi-line strings at the first place.
These commands create an array of strings:

- `Get-Content`
- `Out-String -Stream`

## Pester Do and Don't

### Do

1. Name your file `<descriptive_test_name>.tests.ps1`.
2. Keep tests simple:
    - Test only what you need.
    - Reduce dependencies.
3. Be sure to tag your `Describe` blocks based on their purpose:
    - Tag `CI` indicates that it will be run as part of the continuous integration process. These should be unit test like, and generally take less than a second.
    - Tag `Feature` indicates a higher level feature test (we will run these on a regular basis), for example, tests which go to remote resources, or test broader functionality.
    - Tag `Scenario` indicates tests of integration with other features (these will be run on a less regular basis and test even broader functionality than feature tests.
4. Make sure that `Describe`/`Context`/`It` descriptions are useful.
    - The error message should not be the place where you describe the test.
5. Use `Context` to group tests.
    - Multiple `Context` blocks can help you group your test suite into logical sections.
6. Use `BeforeAll`/`BeforeEach`/`AfterEach`/`AfterAll` instead of custom initiators.
7. Use `Should -Throw -ErrorId` to check for expected errors.
8. Use `-TestCases` when iterating over multiple `It` blocks.
9. Use code coverage functionality where appropriate.
10. Use `Mock` functionality when you don't have your entire environment.
11. Avoid free code in a `Describe` block.
    - Use `BeforeAll`/`BeforeEach`/`AfterEach`/`AfterAll`.
    - See [Free Code in a Describe block](WritingPesterTests.md#free-code-in-a-describe-block)
12. Avoid creating or using test files outside of `TESTDRIVE:`.
    - `TESTDRIVE:` has automatic clean-up.
13. Keep in mind that we are creating cross platform tests.
    - Avoid using the registry.
    - Avoid using COM.
14. Avoid being too specific about the _count_ of a resource as these can change platform to platform.
    - Example: Avoid checking for the count of loaded format files, but rather check for format data for a specific type.

### Don't

1. Don't have too many evaluations in a single `It` block.
   - The first `Should` failure will stop that block.
2. Don't use `Should` outside of an `It` Block.
3. Don't use the word "Error" or "Fail" to test a positive case.
   - Example: Rephrase the negative sentence `"Get-ChildItem TESTDRIVE: shouldn't fail"` to the following positive case `"Get-ChildItem should be able to retrieve file listing from TESTDRIVE"`.

---

### Testing Guidelines Getting Code Coverage (`docs/testing-guidelines/getting-code-coverage.md`)

# Getting Code Coverage Analysis for PowerShell

**Note: Code coverage is currently only supported on Windows, since we use OpenCover.**

The PowerShell code base is configured to build with code coverage support using [OpenCover].

You can see the testing coverage of the current [`master`] branch build at any time at [codecov.io].

To run test coverage analysis of PowerShell on your own branch/machine,
you will need to take the following steps
(and be aware that running the code coverage analysis can take as long as 8 hours).

## Running tests with code coverage analysis

**First**: Open PowerShell in an **elevated** session.
OpenCover needs elevated privileges to work.

Now, in PowerShell:

```powershell
# Go to your PowerShell build directory root
PS> Set-Location "C:\Path\to\powershell\build\dir"

# Import the PowerShell build module
PS> Import-Module .\build.psm1

# Build PowerShell. You may need to add other flags here like
# -ResGen or -Restore
PS> Start-PSBuild -Configuration CodeCoverage -Clean -PsModuleRestore

# Now ensure Pester is installed
PS> Restore-PSPester

# We also need to build the test executor
PS> Publish-PSTestTools

# Import the OpenCover module
PS> Import-Module $PWD\test\tools\OpenCover

# Install OpenCover to a temporary directory
PS> Install-OpenCover -TargetDirectory $env:TEMP -Force

# Finally, run the tests with code coverage analysis.
# If you want to run only the continuous integration tests,
# add -CIOnly, which will take less time
PS> Invoke-OpenCover -OutputLog coverage.xml -OpenCoverPath $env:TEMP\OpenCover
```

## Examining the code coverage data

Once the code coverage test run is done, you'll want to examine the data:

```powershell
# Collect the coverage data using Get-CodeCoverage from the OpenCover
# module that was imported above. This operation is generally expensive
# to compute, so worth storing in a variable
PS> $coverageData = Get-CodeCoverage .\coverage.xml

# Take a look at a summary of the results
PS> $coverageData.CoverageSummary

NumSequencePoints       : 298237
VisitedSequencePoints   : 125949
NumBranchPoints         : 101477
VisitedBranchPoints     : 39389
SequenceCoverage        : 42.23
BranchCoverage          : 38.82
MaxCyclomaticComplexity : 393
MinCyclomaticComplexity : 1
VisitedClasses          : 1990
NumClasses              : 3187
VisitedMethods          : 15115
NumMethods              : 32517

# You can also view results by assembly
PS> $coverageData.Assembly | Format-Table AssemblyName,Branch,Sequence

AssemblyName                              Branch Sequence
------------                              ------ --------
pwsh                                      100    100
Microsoft.PowerShell.ConsoleHost          21.58  23.32
System.Management.Automation              41.22  45.01
Microsoft.PowerShell.CoreCLR.Eventing     1.88   2.03
Microsoft.PowerShell.Security             17.32  20.09
Microsoft.PowerShell.Commands.Utility     20.14  21.39
Microsoft.PowerShell.Commands.Management  43.05  43.39
Microsoft.WSMan.Management                52.58  56.98
Microsoft.WSMan.Runtime                   80.95  80.33
Microsoft.PowerShell.Commands.Diagnostics 0      0
```

If you have made changes to tests or code
and run a second code coverage run,
you can also compare code coverage results:

```powershell
PS> $cov1 = Get-CodeCoverage ./coverage1.xml
PS> $cov2 = Get-CodeCoverage ./coverage2.xml
PS> Compare-CodeCoverage -Run1 $cov1 -Run2 $cov2

AssemblyName                              Sequence SequenceDelta Branch BranchDelta
------------                              -------- ------------- ------ -----------
Microsoft.PowerShell.Security                20.09        -30.12  17.32      -31.63
Microsoft.PowerShell.Commands.Management     43.39          9.10  43.05       11.59
System.Management.Automation                 45.04        -10.63  41.23      -11.07
Microsoft.PowerShell.Commands.Utility        21.39        -47.22  20.14      -46.47
Microsoft.PowerShell.Commands.Diagnostics        0        -51.91      0      -48.62
Microsoft.PowerShell.ConsoleHost             23.32        -22.28  21.58      -22.47
pwsh                                           100          0.00    100        0.00
Microsoft.WSMan.Management                   57.73         48.23  53.02       43.22
Microsoft.WSMan.Runtime                      80.33        -19.67  80.95      -19.05
Microsoft.PowerShell.CoreCLR.Eventing         2.03        -32.74   1.88      -26.01
```

To get file-specific coverage data,
you can use `Compare-FileCoverage`:

```powershell
PS> Compare-FileCoverage -ReferenceCoverage $cov2 -DifferenceCoverage $cov1 -FileName LanguagePrimitives.cs

FileName              ReferenceCoverage DifferenceCoverage CoverageDelta
--------              ----------------- ------------------ -------------
LanguagePrimitives.cs 53.68             69.03              15.34
```

You can see more ways to use `Compare-CodeCoverage` and `Compare-FileCoverage`
by running:

```powershell
PS> Get-Help Compare-CodeCoverage -Full
# Or
PS> Get-Help Compare-FileCoverage -Full
```

## Visualizing code coverage

For a more detailed, graphical representation of the code coverage results,
you can use the ReportGenerator package.
This generates an HTML report of the coverage from the XML file
and will provide much more detail about the coverage analysis.
The package is available on [NuGet],
and you can install and run it as follows:

```powershell
# Install ReportGenerator
PS> Find-Package ReportGenerator `
>> -ProviderName Nuget `
>> -Source "https://nuget.org/api/v2" `
>> | Install-Package -Scope CurrentUser

# Get the ReportGenerator executable path
# Make sure use the appropriate version number in the path
$ReportGenExe = "$HOME\AppData\Local\PackageManagement\NuGet\Packages\ReportGenerator.<version>\tools\ReportGenerator.exe"

# Run ReportGenerator
& $ReportGenExe -report:coverage.xml -targetdir:C:\temp\Coverage

# Finally, open the report in your browser
Invoke-Item C:\temp\Coverage\index.htm
```

This should open a screen in the browser like this:


The main report, which is below the summary and risk hot spots, has
a filter functionality as well (when "Enable Filtering" is clicked on):


[OpenCover]: https://github.com/OpenCover/opencover
[codecov.io]: https://codecov.io
[`master`]: https://github.com/PowerShell/PowerShell
[NuGet]: https://nuget.org/packages/ReportGenerator

---

### Testing Guidelines Testing Guidelines (`docs/testing-guidelines/testing-guidelines.md`)

# Testing Guidelines

Testing is a critical and required part of the PowerShell project.

The Microsoft PowerShell team created nearly 100,000 tests over the last 12 years which we run as part of the release process for Windows PowerShell.
Having all of those tests available for the initial release of PowerShell was not feasible,
and we have targeted those tests which we believe will provide us the ability to catch regressions in the areas which have had the largest changes for PowerShell.
It is our intent to continue to release more and more of our tests until we have the coverage we need.

For creating new tests, please review the [documents](https://github.com/PowerShell/PowerShell/tree/master/docs/testing-guidelines) on how to create tests for PowerShell.
There is a best practices document for [writing Pester tests](https://github.com/PowerShell/PowerShell/tree/master/docs/testing-guidelines/WritingPesterTests.md).
When adding new tests, place them in the directories as [outlined below](#test-layout).

## CI System

We use [Azure DevOps](https://azure.microsoft.com/en-us/solutions/devops) as a continuous integration (CI) system for Windows
and non-Windows platforms.

In the `README.md` at the top of the repository, you can see Azure CI badge.
It indicates the last build status of `master` branch.
Hopefully, it's green:



This badge is **clickable**; you can open corresponding build page with logs, artifacts, and tests results.
From there you can easily navigate to the build history.

### Getting CI Results

CI System builds and runs tests on every pull request and provides quick feedback about it.



These green check boxes and red crosses are **clickable** as well.
They will bring you to the corresponding page with details.

## Test Frameworks

### Pester

Our script-based test framework is [Pester](https://github.com/Pester/Pester).
This is the framework which we are using internally at Microsoft for new script-based tests,
and a large number of the tests which are part of the PowerShell project have been migrated from that test base.
Pester tests can be used to test most of PowerShell behavior (even some API operations can easily be tested in Pester).

Substantial changes were required, to get Pester executing on non-Windows systems.
These changes are not yet in the official Pester code base.
Some features of Pester may not be available or may have incorrect behavior.
Please make sure to create issues in [PowerShell/PowerShell](https://github.com/PowerShell/PowerShell/issues) (not Pester) for anything that you find.

#### Test Tags

The Pester framework allows `Describe` blocks to be tagged, and our CI system relies on those tags to invoke our tests.

One of the following tags must be used:

* `CI` - this tag indicates that the tests in the `Describe` block will be executed as part of the CI/PR process
* `Scenario` - this tag indicates a larger scale test interacting with multiple areas of functionality and/or remote resources, these tests are also run daily.
* `Feature` - tests with this tag will not be executed as part of the CI/PR process,
  but they will be executed on a daily basis as part of a `cron` driven build.
  They indicate that the test will be validating more behavior,
  or will be using remote network resources (ex: package management tests)

Additionally, the tag:

* `SLOW` indicates that the test takes a somewhat longer time to execute (97% of our `CI` tests take 100ms or less), a test which takes longer than 1 second should be considered as a candidate for being tagged `Slow`

#### Requesting additional tests for a PR

In our CI systems, we normally run only run tests tagged with `CI`.
If in the first line of the last (most recent) commit description you add `[Feature]`,
we will ensure that we will also run the tests tagged with `Feature`.
When you would want to do this:

- You have added or changed a `Feature` test.
- A maintainer asks you to run the `Feature` tests.
- Based on experience, you are confident that a maintainer will ask you to run the `Feature` tests.

#### Validating packaging changes for a PR

By default, our CI system does a build and run tests for a PR and does not exercise code to create a package.
If your PR includes changes to packaging, you can have the CI system exercise the packaging code by
using `[Package]` as the first line in the commit message.
When you would want to do this:

- You made change to PowerShell Core packaging
- A maintainer asks you to run as `[Package]`

### xUnit

For those tests which are not easily run via Pester, we have decided to use [xUnit](https://xunit.net/) as the test framework.
Currently, we have a minuscule number of tests which are run by using xUnit.

## Running tests outside of CI

When working on new features or fixes, it is natural to want to run those tests locally before making a PR.
These helper functions are part of the build.psm1 module to help with that:

* `Start-PSPester` will execute all Pester tests which are run by the CI system
* `Start-PSxUnit` will execute the available xUnit tests run by the CI system

Our CI system runs these as well; there should be no difference between running these on your dev system, versus in CI.

When running tests in this way, be sure that you have started PowerShell with `-noprofile` as some tests will fail if the
environment is not the default or has any customization.

For example, to run all the Pester tests for CI (assuming you are at the root of the PowerShell repo):

```PowerShell
Import-Module ./build.psm1
Start-PSPester
```

If you wish to run specific tests, that is possible as well:

```PowerShell
Start-PSPester -Path test/powershell/engine/Api
```

Or a specific Pester test file:

```PowerShell
Start-PSPester -Path test/powershell/engine/Api/XmlAdapter.Tests.ps1
```

### What happens after your PR?

When your PR has successfully passed the CI test gates, your changes will be used to create PowerShell binaries which can be run
in Microsoft's internal test frameworks.
The tests that you created for your change and the library of historical tests will be run to determine if any regressions are present.
If these tests find regressions, you'll be notified that your PR is not ready, and provided with enough information to investigate why the failure happened.

## Test Layout

We have taken a functional approach to the layout of our Pester tests and you should place new tests in their appropriate location.
If you are making a fix to a cmdlet in a module, the test belongs in the module directory.
If you are unsure, you can make it part of your PR, or create an issue.

The current layout of tests is:

* test/powershell/engine
* test/powershell/engine/Api
* test/powershell/engine/Basic
* test/powershell/engine/ETS
* test/powershell/engine/Help
* test/powershell/engine/Logging
* test/powershell/engine/Module
* test/powershell/engine/ParameterBinding
* test/powershell/engine/Remoting
* test/powershell/engine/Runspace
* test/powershell/engine/Logging/MessageAnalyzer
* test/powershell/Host
* test/powershell/Host/ConsoleHost
* test/powershell/Host/TabCompletion
* test/powershell/Language
* test/powershell/Modules
* test/powershell/Provider
* test/powershell/SDK
* test/powershell/Security
* test/powershell/Language/Classes
* test/powershell/Language/Interop
* test/powershell/Language/Operators
* test/powershell/Language/Parser
* test/powershell/Language/Interop/DotNet
* test/powershell/Language/Scripting
* test/powershell/Language/Scripting/Debugging
* test/powershell/Language/Scripting/NativeExecution
* test/powershell/Modules/Microsoft.PowerShell.Archive
* test/powershell/Modules/Microsoft.PowerShell.Core
* test/powershell/Modules/Microsoft.PowerShell.Diagnostics
* test/powershell/Modules/Microsoft.PowerShell.Management
* test/powershell/Modules/Microsoft.PowerShell.Security
* test/powershell/Modules/Microsoft.PowerShell.Utility
* test/powershell/Modules/PSReadLine

---

### Host Powershell Sample NuGet.Config (`docs/host-powershell/sample/NuGet.config.md`)

# Nuget.config creation

Create a filed called `nuget.config` at this location with this content:

```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> 
  </packageSources>
  <disabledPackageSources>
    <clear />
  </disabledPackageSources>
</configuration>
```

---

--- METRICS ---
- Files Extracted: 58
- Estimated Token Budget: ~67161 tokens
- Canonical Reference: https://codewiki.google/github.com/PowerShell/powershell
