From 8efab8297e3effeb5759a7b8193c178d28d5d2b5 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Mon, 8 Dec 2025 17:18:11 -0600 Subject: [PATCH] Freshness update - part2 --- .../Writing-Portable-Modules.md | 62 +-- .../choosing-the-right-nuget-package.md | 359 +++++++++--------- .../create-cmdline-predictor.md | 2 +- .../create-feedback-provider.md | 2 +- .../create-standard-library-binary-Module.md | 2 +- .../module-authoring-considerations.md | 2 +- .../resolving-dependency-conflicts.md | 153 ++++---- ...-Replicate-the-ISE-Experience-In-VSCode.md | 2 +- ...VSCode-for-Remote-Editing-and-Debugging.md | 2 +- .../vscode/understanding-file-encoding.md | 2 +- ...g-vscode-for-debugging-compiled-cmdlets.md | 2 +- .../dev-cross-plat/vscode/using-vscode.md | 2 +- 12 files changed, 289 insertions(+), 303 deletions(-) diff --git a/reference/docs-conceptual/dev-cross-plat/Writing-Portable-Modules.md b/reference/docs-conceptual/dev-cross-plat/Writing-Portable-Modules.md index b09a0643b3be..e47568f6ff68 100644 --- a/reference/docs-conceptual/dev-cross-plat/Writing-Portable-Modules.md +++ b/reference/docs-conceptual/dev-cross-plat/Writing-Portable-Modules.md @@ -1,13 +1,13 @@ --- description: This article explains how to create modules new modules or update existing modules so that they work across the platforms supported by PowerShell. -ms.date: 11/16/2022 +ms.date: 12/08/2025 title: Writing Portable Modules --- # Portable Modules -Windows PowerShell is written for [.NET Framework][06] while PowerShell Core is written for -[.NET Core][03]. Portable modules are modules that work in both Windows PowerShell and PowerShell +Windows PowerShell is written for [.NET Framework][03] while PowerShell Core is written for +[.NET Core][04]. Portable modules are modules that work in both Windows PowerShell and PowerShell Core. While .NET Framework and .NET Core are highly compatible, there are differences in the available APIs between the two. There are also differences in the APIs available in Windows PowerShell and PowerShell Core. Modules intended to be used in both environments need to be aware of @@ -17,12 +17,12 @@ these differences. ### Porting a PSSnapIn -PowerShell [SnapIns][09] aren't supported in PowerShell Core. However, it's trivial to convert a +PowerShell [SnapIns][07] aren't supported in PowerShell Core. However, it's trivial to convert a PSSnapIn to a PowerShell module. Typically, the PSSnapIn registration code is in a single source -file of a class that derives from [PSSnapIn][01]. Remove this source file from the build; it's no +file of a class that derives from [PSSnapIn][14]. Remove this source file from the build; it's no longer needed. -Use [New-ModuleManifest][08] to create a new module manifest that replaces the need for the PSSnapIn +Use [New-ModuleManifest][13] to create a new module manifest that replaces the need for the PSSnapIn registration code. Some values from the **PSSnapIn** (such as **Description**) can be reused within the module manifest. @@ -32,14 +32,14 @@ The **RootModule** property in the module manifest should be set to the name of ### The .NET Portability Analyzer (aka APIPort) To port modules written for Windows PowerShell to work with PowerShell Core, start with the -[.NET Portability Analyzer][11]. Run this tool against your compiled assembly to determine if the +[.NET Portability Analyzer][08]. Run this tool against your compiled assembly to determine if the .NET APIs used in the module are compatible with .NET Framework, .NET Core, and other .NET runtimes. -The tool suggests alternate APIs if they exist. Otherwise, you may need to add [runtime checks][02] +The tool suggests alternate APIs if they exist. Otherwise, you may need to add [runtime checks][15] and restrict capabilities not available in specific runtimes. ## Creating a new module -If creating a new module, the recommendation is to use the [.NET CLI][05]. +If creating a new module, the recommendation is to use the [.NET CLI][02]. ### Installing the PowerShell Standard module template @@ -143,7 +143,7 @@ FavoriteNumber FavoritePet ### Debugging the module For a guide on setting up Visual Studio Code to debug the module, see -[Using Visual Studio Code for debugging compiled cmdlets][15]. +[Using Visual Studio Code for debugging compiled cmdlets][12]. ## Supporting technologies @@ -151,7 +151,7 @@ The following sections describe in detail some of the technologies used by this ### .NET Standard Library -[.NET Standard][07] is a formal specification of .NET APIs that are available in all .NET +[.NET Standard][05] is a formal specification of .NET APIs that are available in all .NET implementations. Managed code targeting .NET Standard works with the .NET Framework and .NET Core versions that are compatible with that version of the .NET Standard. @@ -173,10 +173,10 @@ PowerShell Core 6 without recompilation. ### PowerShell Standard Library -The [PowerShell Standard][12] library is a formal specification of PowerShell APIs available in all +The [PowerShell Standard][09] library is a formal specification of PowerShell APIs available in all PowerShell versions greater than or equal to the version of that standard. -For example, [PowerShell Standard 5.1][13] is compatible with both Windows PowerShell 5.1 and +For example, [PowerShell Standard 5.1][10] is compatible with both Windows PowerShell 5.1 and PowerShell Core 6.0 or newer. We recommend you compile your module using PowerShell Standard Library. The library ensures the APIs @@ -189,7 +189,7 @@ will always be compatible with future versions of PowerShell. #### Indicating Compatibility With Windows PowerShell and PowerShell Core After validating that your module works with both Windows PowerShell and PowerShell Core, the module -manifest should explicitly indicate compatibility by using the [CompatiblePSEditions][10] property. +manifest should explicitly indicate compatibility by using the [CompatiblePSEditions][06] property. A value of `Desktop` means that the module is compatible with Windows PowerShell, while a value of `Core` means that the module is compatible with PowerShell Core. Including both `Desktop` and `Core` means that the module is compatible with both Windows PowerShell and PowerShell Core. @@ -203,7 +203,7 @@ means that the module is compatible with both Windows PowerShell and PowerShell First, validate that your module works on Linux and macOS. Next, indicate compatibility with those operating systems in the module manifest. This makes it easier for users to find your module for -their operating system when published to the [PowerShell Gallery][14]. +their operating system when published to the [PowerShell Gallery][11]. Within the module manifest, the `PrivateData` property has a `PSData` sub-property. The optional `Tags` property of `PSData` takes an array of values that show up in PowerShell Gallery. The @@ -272,7 +272,7 @@ Prior to PowerShell 7, one would have to have custom code to load the appropriat the managed library can find it correctly. With PowerShell 7, native binaries to load are searched in sub-folders within the managed library's -location following a subset of the [.NET RID Catalog][04] notation. +location following a subset of the [.NET RID Catalog][01] notation. ``` managed.dll folder @@ -306,18 +306,18 @@ managed.dll folder ``` -[01]: /dotnet/api/system.management.automation.pssnapin -[02]: /dotnet/api/system.runtime.interopservices.runtimeinformation.frameworkdescription#System_Runtime_InteropServices_RuntimeInformation_FrameworkDescription -[03]: /dotnet/core/ -[04]: /dotnet/core/rid-catalog -[05]: /dotnet/core/tools/?tabs=netcore2x -[06]: /dotnet/framework/ -[07]: /dotnet/standard/net-standard -[08]: /powershell/module/microsoft.powershell.core/new-modulemanifest -[09]: /powershell/scripting/developer/cmdlet/modules-and-snap-ins -[10]: /powershell/gallery/concepts/module-psedition-support -[11]: https://github.com/Microsoft/dotnet-apiport -[12]: https://github.com/PowerShell/PowerShellStandard -[13]: https://www.nuget.org/packages/PowerShellStandard.Library/5.1.0 -[14]: https://www.powershellgallery.com -[15]: vscode/using-vscode-for-debugging-compiled-cmdlets.md +[01]: /dotnet/core/rid-catalog +[02]: /dotnet/core/tools/ +[03]: /dotnet/framework/ +[04]: /dotnet/fundamentals/ +[05]: /dotnet/standard/net-standard +[06]: /powershell/gallery/concepts/module-psedition-support +[07]: /powershell/scripting/developer/cmdlet/modules-and-snap-ins +[08]: https://github.com/Microsoft/dotnet-apiport +[09]: https://github.com/PowerShell/PowerShellStandard +[10]: https://www.nuget.org/packages/PowerShellStandard.Library/5.1.0 +[11]: https://www.powershellgallery.com +[12]: vscode/using-vscode-for-debugging-compiled-cmdlets.md +[13]: xref:Microsoft.PowerShell.Core.New-ModuleManifest +[14]: xref:System.Management.Automation.PSSnapIn +[15]: xref:System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription%2A diff --git a/reference/docs-conceptual/dev-cross-plat/choosing-the-right-nuget-package.md b/reference/docs-conceptual/dev-cross-plat/choosing-the-right-nuget-package.md index 065511c722bf..ef349e6fc213 100644 --- a/reference/docs-conceptual/dev-cross-plat/choosing-the-right-nuget-package.md +++ b/reference/docs-conceptual/dev-cross-plat/choosing-the-right-nuget-package.md @@ -1,39 +1,39 @@ --- description: Alongside the executable packages published with each PowerShell release, the PowerShell team also maintains several packages available on NuGet. These packages allow targeting PowerShell as an API platform in .NET. ms.custom: rjmholt -ms.date: 11/16/2022 +ms.date: 12/08/2025 title: Choosing the right PowerShell NuGet package for your .NET project --- # Choosing the right PowerShell NuGet package for your .NET project Alongside the `pwsh` executable packages published with each PowerShell release, the PowerShell team -also maintains several packages available on [NuGet][25]. These packages allow targeting PowerShell +also maintains several packages available on [NuGet][18]. These packages allow targeting PowerShell as an API platform in .NET. As a .NET application that provides APIs and expects to load .NET libraries implementing its own (binary modules), it's essential that PowerShell be available in the form of a NuGet package. Currently there are several NuGet packages that provide some representation of the PowerShell API -surface area. Which package to use with a particular project hasn't always been made clear. This -article sheds some light on a few common scenarios for PowerShell-targeting .NET projects and how to -choose the right NuGet package to target for your PowerShell-oriented .NET project. +surface area. Which package to use with a particular project isn't always clear. This article sheds +some light on a few common scenarios for PowerShell-targeting .NET projects and how to choose the +right NuGet package to target for your PowerShell-oriented .NET project. ## Hosting vs referencing -Some .NET projects seek to write code to be loaded into a pre-existing PowerShell runtime (such as -`pwsh`, `powershell.exe`, the PowerShell Integrated Console or the ISE), while others want to run +Some .NET projects seek to write code to be loaded into a preexisting PowerShell runtime (such as +`pwsh`, `powershell.exe`, the PowerShell Integrated Console, or the ISE), while others want to run PowerShell in their own applications. - **Referencing** is for when a project, usually a module, is intended to be loaded into PowerShell. - It must be compiled against the APIs that PowerShell provides in order to interact with it, but - the PowerShell implementation is supplied by the PowerShell process loading it in. For - referencing, a project can use [reference assemblies][07] or the actual runtime assemblies as a - compilation target, but must ensure that it does not publish any of these with its build. -- **Hosting** is when a project needs its own implementation of PowerShell, usually because it is a + You must compile the module against the APIs that PowerShell provides in order to interact with + it. But PowerShell supplies the implementation by loading it in. A project can use + [reference assemblies][02] or the actual runtime assemblies as a compilation target, but must + ensure that it doesn't publish any of these assemblies with its build. +- **Hosting** is when a project needs its own implementation of PowerShell, usually because it's a standalone application that needs to run PowerShell. In this case, pure reference assemblies - cannot be used. Instead, a concrete PowerShell implementation must be depended upon. Because a + can't be used. Instead, a concrete PowerShell implementation must be depended upon. Because a concrete PowerShell implementation must be used, a specific version of PowerShell must be chosen - for hosting; a single host application cannot multi-target PowerShell versions. + for hosting; a single host application can't multi-target PowerShell versions. ### Publishing projects that target PowerShell as a reference @@ -42,17 +42,17 @@ PowerShell in their own applications. > .NET library into a directory with all of its dependencies, ready for deployment to a particular > runtime. -In order to prevent publishing project dependencies that are just being used as compilation -reference targets, it is recommended to set the [PrivateAssets][06] attribute: +Set the [PrivateAssets][01] attribute to prevent publishing project dependencies that are just being +used as compilation reference targets: ```xml ``` -If you forget to do this and use a reference assembly as your target, you may see issues related to -using the reference assembly's default implementation instead of the actual implementation. This may -take the form of a `NullReferenceException`, since reference assemblies often mock the -implementation API by simply returning `null`. +If you don't set this attribute and use a reference assembly as your target, you can see issues +related to using the reference assembly's default implementation instead of the actual +implementation. For example, you can receive a `NullReferenceException`, since reference assemblies +often mock the implementation API by returning `null`. ## Key kinds of PowerShell-targeting .NET projects @@ -62,16 +62,16 @@ PowerShell APIs: - **Implementing a PowerShell binary module** PowerShell binary modules are .NET libraries loaded by PowerShell that must implement PowerShell - APIs like the [PSCmdlet][04] or [CmdletProvider][03] types in order to expose cmdlets or providers - respectively. Because they are loaded in, modules seek to compile against references to PowerShell + APIs like the [PSCmdlet][31] or [CmdletProvider][30] types in order to expose cmdlets or providers + respectively. Because they're loaded in, modules seek to compile against references to PowerShell without publishing it in their build. It's also common for modules to want to support multiple PowerShell versions and platforms, ideally with a minimum of overhead of disk space, complexity, - or repeated implementation. See [about_Modules][09] for more information about modules. + or repeated implementation. For more information, see [about_Modules][04]. - **Implementing a PowerShell Host** - A PowerShell Host provides an interaction layer for the PowerShell runtime. It is a specific form - of _hosting_, where a [PSHost][01] is implemented as a new user interface to PowerShell. For + A PowerShell Host provides an interaction layer for the PowerShell runtime. It's a specific form + of _hosting_, where a [PSHost][28] is implemented as a new user interface to PowerShell. For example, the PowerShell ConsoleHost provides a terminal user interface for PowerShell executables, while the PowerShell Editor Services Host and the ISE Host both provide an editor-integrated partially graphical user interface around PowerShell. While it's possible to load a host onto an @@ -80,101 +80,101 @@ PowerShell APIs: - **Calling into PowerShell from another .NET application** - As with any application, PowerShell can be called as a subprocess to run workloads. However, as a + As with any application, you can call PowerShell as a subprocess to run workloads. However, as a .NET application, it's also possible to invoke PowerShell in-process to get back full .NET objects for use within the calling application. This is a more general form of _hosting_, where the - application holds its own PowerShell implementation for internal use. Examples of this might be a - service or daemon running PowerShell to manage machine state or a web application that runs - PowerShell on request to do something like manage cloud deployments. + application holds its own PowerShell implementation for internal use. For example, you could + create a service or daemon running PowerShell to manage machine state, or a web application that + runs PowerShell on request to do some work like managing cloud deployments. - **Unit testing PowerShell modules from .NET** - While modules and other libraries designed to expose functionality to PowerShell should be - primarily tested from PowerShell (we recommend [Pester][15]), sometimes it's necessary to unit - test APIs written for a PowerShell module from .NET. This situation involves the module code - trying to target a number of PowerShell versions, while testing should run it on specific, - concrete implementations. + Usually, modules and other libraries designed to expose functionality to PowerShell should be + tested from PowerShell. However, it's sometimes necessary to unit test APIs written for a + PowerShell module from .NET. ## PowerShell NuGet packages at a glance -In this article, we'll cover the following NuGet packages -that expose PowerShell APIs: +The following NuGet packages expose PowerShell APIs: -- [PowerShellStandard.Library][31], a reference assembly that enables building a single assembly - that can be loaded by multiple PowerShell runtimes. -- [Microsoft.PowerShell.SDK][12], the way to target and rehost the whole PowerShell SDK -- The [System.Management.Automation][32] package, the core PowerShell runtime and engine +- [PowerShellStandard.Library][24], a reference assembly that enables building a single assembly + that you can load in multiple PowerShell runtimes. +- [Microsoft.PowerShell.SDK][05], the way to target and rehost the whole PowerShell SDK +- The [System.Management.Automation][25] package, the core PowerShell runtime and engine implementation, that can be useful in minimal hosted implementations and for version-specific targeting scenarios. - The **Windows PowerShell reference assemblies**, the way to target and effectively rehost Windows PowerShell (PowerShell versions 5.1 and below). > [!NOTE] -> The [PowerShell NuGet][30] package is not a .NET library package at all, but instead provides the -> PowerShell dotnet global tool implementation. This should not be used by any projects, since it +> The [PowerShell NuGet][23] package isn't a .NET library package at all, but instead provides the +> PowerShell dotnet global tool implementation. Don't use this package in any projects, since it > only provides an executable. ## PowerShellStandard.Library The PowerShell Standard library is a reference assembly that captures the intersection of the APIs -of PowerShell versions 7, 6 and 5.1. This provides a compile-time-checked API surface to compile -.NET code against, allowing .NET projects to target PowerShell versions 7, 6 and 5.1 without risking -calling an API that won't be there. +of PowerShell v7 and v5.1. It provides a compile-time-checked API surface to compile .NET code +against, allowing .NET projects to target PowerShell v7 and v5.1 without risking calling an API that +that's not available. -PowerShell Standard is intended for writing PowerShell modules, or other code only intended to be -run after loading it into a PowerShell process. Because it is a reference assembly, PowerShell -Standard contains no implementation itself, so provides no functionality for standalone -applications. +Use PowerShell Standard to write PowerShell modules or other code only intended to be run after +loading it into a PowerShell process. Because it's a reference assembly, PowerShell Standard +contains no implementation itself, so it provides no functionality for standalone applications. ### Using PowerShell Standard with different .NET runtimes -PowerShell Standard targets the [.NET Standard 2.0][08] target runtime, which is a façade runtime -designed to provide a common surface area shared by .NET Framework and .NET Core. This allows -targeting a single runtime to produce a single assembly that will work with multiple PowerShell -versions, but has the following consequences: - -- The PowerShell loading the module or library must be running a minimum of .NET 4.6.1; .NET 4.6 and - .NET 4.5.2 do not support .NET Standard. Note that a newer Windows PowerShell version does not - mean a newer .NET Framework version; Windows PowerShell 5.1 may run on .NET 4.5.2. -- In order to work with a PowerShell running .NET Framework 4.7.1 or below, the .NET 4.6.1 - [NETStandard.Library][29] implementation is required to provide the netstandard.dll and other shim - assemblies in older .NET Framework versions. - -PowerShell 6+ provides its own shim assemblies for type forwarding from .NET Framework 4.6.1 (and -above) to .NET Core. This means that as long as a module uses only APIs that exist in .NET Core, -PowerShell 6+ can load and run it when it has been built for .NET Framework 4.6.1 (the `net461` +PowerShell Standard targets the [.NET Standard 2.0][03] target runtime, which is a façade runtime +designed to provide a common surface area shared by .NET Framework and .NET Core. It allows you to +target a single runtime to produce a single assembly that works with multiple PowerShell versions, +but has the following consequences: + +- The PowerShell instance loading the module or library must be running a minimum of .NET 4.6.1; .NET 4.6 and + .NET 4.5.2 don't support .NET Standard. + + > [!NOTE] + > A newer Windows PowerShell version doesn't mean a newer .NET Framework version. Windows + > PowerShell 5.1 can run on .NET 4.5.2. + +- To work with a PowerShell running .NET Framework 4.7.1 or below, the .NET 4.6.1 + [NETStandard.Library][22] implementation is required to provide the `netstandard.dll` and other + shim assemblies in older .NET Framework versions. + +PowerShell 6 (and higher) provides its own shim assemblies for type forwarding from .NET Framework +4.6.1 (and higher) to .NET Core. As long as a module uses only APIs that exist in .NET Core, +PowerShell 6 (and higher) can load and run it if it was built for .NET Framework 4.6.1 (the `net461` runtime target). -This means that binary modules using PowerShell Standard to target multiple PowerShell versions with -a single published DLL have two options: +Binary modules using PowerShell Standard to target multiple PowerShell versions with a single +published DLL have two options: -1. Publishing an assembly built for the `net461` target runtime. This involves: +1. Publishing an assembly built for the `net461` target runtime involves: - Publishing the project for the `net461` runtime - Also compiling against the `netstandard2.0` runtime (without using its build output) to ensure that all APIs used are also present in .NET Core. -1. Publishing an assembly build for the `netstandard2.0` target runtime. This requires: +1. Publishing an assembly build for the `netstandard2.0` target runtime requires: - Publishing the project for the `netstandard2.0` runtime - Taking the `net461` dependencies of NETStandard.Library and copying them into the project assembly's publish location so that the assembly is type-forwarded corrected in .NET Framework. -To build PowerShell modules or libraries targeting older .NET Framework versions, it may be -preferable to target multiple .NET runtimes. This will publish an assembly for each target runtime, -and the correct assembly will need to be loaded at module load time (for example with a small psm1 -as the root module). +To build PowerShell modules or libraries targeting older .NET Framework versions, you might find it +preferable to target multiple .NET runtimes. Doing so publishes an assembly for each target runtime. +The correct assembly must be loaded at module load time, for example with a small `.psm1` file as +the root module. ### Testing PowerShell Standard projects in .NET -When it comes to testing your module in .NET test runners like xUnit, remember that compile-time -checks can only go so far. You must test your module against the relevant PowerShell platforms. +When you test your module in .NET with test runners like xUnit, remember that compile-time checks +can only go so far. You must test your module against the relevant PowerShell platforms. To test APIs built against PowerShell Standard in .NET, you should add `Microsoft.PowerShell.SDK` as a testing dependency with .NET Core (with the version set to match the desired PowerShell version), and the appropriate Windows PowerShell reference assemblies with .NET Framework. For more information on PowerShell Standard and using it to write a binary module that works in -multiple PowerShell versions, see [this blog post][14]. Also see the -[PowerShell Standard repository][19] on GitHub. +multiple PowerShell versions, see [this blog post][07]. Also see the +[PowerShell Standard repository][12] on GitHub. ## Microsoft.PowerShell.SDK @@ -188,39 +188,37 @@ PowerShell installations or libraries. > can be used for .NET development with PowerShell. A given `Microsoft.PowerShell.SDK` version contains the concrete implementation of the same version -of the PowerShell application; version 7.0 contains the implementation of PowerShell 7.0 and running -commands or scripts with it will largely behave like running them in PowerShell 7.0. - -Running PowerShell commands from the SDK is mostly, but not totally, the same as running them from -`pwsh`. For example, [Start-Job][10] currently depends on the `pwsh` executable being available, and -so will not work with `Microsoft.PowerShell.SDK` by default. +of the PowerShell application. Version 7.0 contains the implementation of PowerShell 7.0. Commands +or scripts behave like running them in PowerShell 7.0. However, running PowerShell commands from the +SDK isn't the same as running them from `pwsh`. For example, [Start-Job][26] depends on the `pwsh` +executable being available, so it doesn't work with `Microsoft.PowerShell.SDK` by default. Targeting `Microsoft.PowerShell.SDK` from a .NET application allows you to integrate with all of PowerShell's implementation assemblies, such as `System.Management.Automation`, `Microsoft.PowerShell.Management`, and other module assemblies. -Publishing an application targeting `Microsoft.PowerShell.SDK` will include all these assemblies, -and any dependencies PowerShell requires. It will also include other assets that PowerShell required -in its build, such as the module manifests for `Microsoft.PowerShell.*` modules and the `ref` -directory required by [Add-Type][11]. +Publishing an application targeting `Microsoft.PowerShell.SDK` includes all these assemblies, and +any dependencies PowerShell requires. It also includes other assets that PowerShell required in its +build, such as the module manifests for `Microsoft.PowerShell.*` modules and the `ref` directory +required by [Add-Type][27]. -Given the completeness of `Microsoft.PowerShell.SDK`, it's best suited for: +`Microsoft.PowerShell.SDK` is best suited for: - Implementation of PowerShell hosts. - xUnit testing of libraries targeting PowerShell reference assemblies. - Invoking PowerShell in-process from a .NET application. -`Microsoft.PowerShell.SDK` may also be used as a reference target when a .NET project is intended to -be used as a module or otherwise loaded by PowerShell, but depends on APIs only present in a -particular version of PowerShell. Note that an assembly published against a specific version of -`Microsoft.PowerShell.SDK` will only be safe to load and use in that version of PowerShell. To -target multiple PowerShell versions with specific APIs, multiple builds are required, each targeting -their own version of `Microsoft.PowerShell.SDK`. +You can use `Microsoft.PowerShell.SDK` as a reference target for a .NET project to create a +PowerShell module or assembly loaded by PowerShell that depends on APIs only present in a particular +version of PowerShell. An assembly published for a specific version of `Microsoft.PowerShell.SDK` is +only safe to load and use in that version of PowerShell. To target multiple PowerShell versions with +specific APIs, multiple builds are required, each targeting their own version of +`Microsoft.PowerShell.SDK`. > [!NOTE] -> The PowerShell SDK is only available for PowerShell versions 6 and up. To provide equivalent +> The PowerShell SDK is only available for PowerShell v6 and higher. To provide equivalent > functionality with Windows PowerShell, use the Windows PowerShell reference assemblies described -> below. +> later in this article. ## System.Management.Automation @@ -228,38 +226,34 @@ The `System.Management.Automation` package is the heart of the PowerShell SDK. I primarily, as an asset for `Microsoft.PowerShell.SDK` to pull in. However, it can also be used directly as a package for smaller hosting scenarios and version-targeting modules. -Specifically, the `System.Management.Automation` package may be a preferable provider of PowerShell -functionality when: +Specifically, the `System.Management.Automation` package is the preferred when: -- You're only looking to use PowerShell language functionality (in the - `System.Management.Automation.Language` namespace) like the PowerShell parser, AST, and AST - visitor APIs (for example for static analysis of PowerShell). +- You're only looking to use PowerShell language functionality from the + `System.Management.Automation.Language` namespace, such as the PowerShell parser, AST, and AST + visitor APIs. - You only wish to execute specific commands from the `Microsoft.PowerShell.Core` module and can - execute them in a session state created with the [CreateDefault2][05] factory method. + execute them in a session state created with the [CreateDefault2][32] factory method. Additionally, `System.Management.Automation` is a useful reference assembly when: - You wish to target APIs that are only present within a specific PowerShell version -- You won't be depending on types occurring outside the `System.Management.Automation` assembly (for - example, types exported by cmdlets in `Microsoft.PowerShell.*` modules). +- You aren't depending on types occurring outside the `System.Management.Automation` assembly, such + as types exported by cmdlets in `Microsoft.PowerShell.*` modules. ## Windows PowerShell reference assemblies -For PowerShell versions 5.1 and older (Windows PowerShell), there is no SDK to provide an -implementation of PowerShell, since Windows PowerShell's implementation is a part of Windows. +For Windows PowerShell versions 5.1 and older, there's no SDK to provide an implementation of +PowerShell, since Windows PowerShell's implementation is a part of Windows. Instead, the Windows +PowerShell reference assemblies provide both reference targets and a way to rehost Windows +PowerShell, acting the same as the PowerShell SDK does for version 6 and higher. Windows PowerShell +reference assemblies have a different package for each version of Windows PowerShell: -Instead, the Windows PowerShell reference assemblies provide both reference targets and a way to -rehost Windows PowerShell, acting the same as the PowerShell SDK does for versions 6 and up. +- [PowerShell 5.1][21] +- [PowerShell 4][20] +- [PowerShell 3][19] -Rather than being differentiated by version, Windows PowerShell reference assemblies have a -different package for each version of Windows PowerShell: - -- [PowerShell 5.1][28] -- [PowerShell 4][27] -- [PowerShell 3][26] - -Information on how to use the Windows PowerShell reference assemblies can be found in the -[Windows PowerShell SDK][12]. +You can find information about how to use the Windows PowerShell reference assemblies in the +[Windows PowerShell SDK][05]. ## Real-world examples using these NuGet packages @@ -268,102 +262,97 @@ needs. Listed here are some notable examples. ### PSReadLine -[PSReadLine][20], the PowerShell module that provides much of PowerShell's rich console experience, +[PSReadLine][13], the PowerShell module that provides much of PowerShell's rich console experience, targets PowerShell Standard as a dependency rather than a specific PowerShell version, and targets -the `net461` .NET runtime in its [csproj][21]. +the `net461` .NET runtime in its [csproj][14]. -PowerShell 6+ supplies its own shim assemblies that allow a DLL targeting the `net461` runtime to -"just work" when loaded in (by redirecting binding to .NET Framework's `mscorlib.dll` to the -relevant .NET Core assembly). +PowerShell v6 (and higher) supplies its own shim assemblies that allow a DLL targeting the `net461` +runtime to _just work_ when loaded. The shim simplifies the delivery and module layout of +PSReadLine. PowerShell Standard ensures that the module only uses APIs that are available in both +Windows PowerShell 5.1 and PowerShell 6 (and higher), which allows the module to ship with only a +single assembly. -This simplifies PSReadLine's module layout and delivery significantly, since PowerShell Standard -ensures the only APIs used will be present in both PowerShell 5.1 and PowerShell 6+, while also -allowing the module to ship with only a single assembly. - -The .NET 4.6.1 target does mean that Windows PowerShell running on -.NET 4.5.2 and .NET 4.6 is not supported though. +The .NET 4.6.1 target does mean that Windows PowerShell running on .NET 4.5.2 and .NET 4.6 isn't +supported though. ### PowerShell Editor Services -[PowerShell Editor Services][16] (PSES) is the backend for the [PowerShell extension][24] for -[Visual Studio Code][13], and is actually a form of PowerShell module that gets loaded by a -PowerShell executable and then takes over that process to rehost PowerShell within itself while also -providing Language Service Protocol and Debug Adapter features. +[PowerShell Editor Services][09] (PSES) is the backend for the [PowerShell extension][17] for +[Visual Studio Code][06]. This PowerShell module gets loaded by a PowerShell and then takes over +that process to rehost PowerShell within itself, while also providing Language Service Protocol and +Debug Adapter features. PSES provides concrete implementation targets for `netcoreapp2.1` to target PowerShell 6+ (since PowerShell 7's `netcoreapp3.1` runtime is backwards compatible) and `net461` to target Windows PowerShell 5.1, but contains most of its logic in a second assembly that targets `netstandard2.0` -and PowerShell Standard. This allows it to pull in dependencies required for .NET Core and .NET -Framework platforms, while still simplifying most of the codebase behind a uniform abstraction. +and PowerShell Standard. This design allows it to pull in dependencies required for .NET Core and +.NET Framework platforms, while still simplifying most of the codebase behind a uniform abstraction. -Because it is built against PowerShell Standard, PSES requires a runtime implementation of -PowerShell in order to be tested correctly. To do this, [PSES's xUnit][18] tests pull in -`Microsoft.PowerShell.SDK` and `Microsoft.PowerShell.5.ReferenceAssemblies` in order to provide a -PowerShell implementation in the test environment. +Because PSES targets PowerShell Standard, it requires a runtime implementation to be tested +correctly. To do this, [PSES's xUnit][11] tests pull in `Microsoft.PowerShell.SDK` and +`Microsoft.PowerShell.5.ReferenceAssemblies` to provide a PowerShell implementation in the test +environment. -As with PSReadLine, PSES cannot support .NET 4.6 and below, but it [performs a check][17] at runtime -before calling any of the APIs that could cause a crash on the lower .NET Framework runtimes. +Since PSES can't support .NET 4.6 and older, it [performs a check][10] at runtime before calling any +of the APIs that could cause a crash on the lower .NET Framework runtimes. ### PSScriptAnalyzer -[PSScriptAnalyzer][22], the linter for PowerShell, must target syntactic elements only introduced in +[PSScriptAnalyzer][15], the linter for PowerShell, must target syntactic elements only introduced in certain versions of PowerShell. Because recognition of these syntactic elements is accomplished by -implementing an [AstVisitor2][02], it's not possible to use PowerShellStandard and also implement +implementing an [AstVisitor2][29], it's not possible to use PowerShellStandard and also implement AST visitor methods for newer PowerShell syntaxes. -Instead, PSScriptAnalyzer [targets each PowerShell version][23] as a build configuration, and -produces a separate DLL for each of them. This increases build size and complexity, but allows: +Instead, PSScriptAnalyzer targets each [PowerShell version][16] as a build configuration and +produces a separate DLL for each version. This increases build size and complexity, but allows: - Version-specific API targeting - Version-specific functionality to be implemented with essentially no runtime cost -- Total support for Windows PowerShell all the way down to .NET Framework 4.5.2 +- Total support for Windows PowerShell running on .NET Framework 4.5.2 and higher ## Summary -In this article, we've listed and discussed the NuGet packages available to target when implementing -a .NET project that uses PowerShell, and the reasons you might have for using one over another. - -If you've skipped to the summary, some broad recommendations are: +This article listed and discussed the NuGet packages you can target and the reasons for using each +one. The general recommendations are: - PowerShell **modules** should compile against PowerShell Standard if they only require APIs common to different PowerShell versions. -- PowerShell **hosts and applications** that need to run PowerShell internally should target the - PowerShell SDK for PowerShell 6+ or the relevant Windows PowerShell reference assemblies for - Windows PowerShell. +- PowerShell **hosts and applications** that need to run PowerShell internally should target: + - The PowerShell SDK for PowerShell v6 and higher + - Or the relevant Windows PowerShell reference assemblies for Windows PowerShell - PowerShell modules that need **version-specific APIs** should target the PowerShell SDK or Windows - PowerShell reference assemblies for the required PowerShell versions, using them as reference - assemblies (that is, not publishing the PowerShell dependencies). + PowerShell reference assemblies for the required PowerShell versions. Use them as reference + assemblies so you don't publish the PowerShell dependencies. -[01]: /dotnet/api/system.management.automation.host.pshost -[02]: /dotnet/api/system.management.automation.language.astvisitor2 -[03]: /dotnet/api/system.management.automation.provider.cmdletprovider -[04]: /dotnet/api/system.management.automation.pscmdlet -[05]: /dotnet/api/system.management.automation.runspaces.initialsessionstate.createdefault2 -[06]: /dotnet/core/tools/csproj#packagereference -[07]: /dotnet/standard/assembly/reference-assemblies -[08]: /dotnet/standard/net-standard -[09]: /powershell/module/microsoft.powershell.core/about/about_modules -[10]: /powershell/module/microsoft.powershell.core/start-job -[11]: /powershell/module/microsoft.powershell.utility/add-type -[12]: /powershell/scripting/developer/windows-powershell -[13]: https://code.visualstudio.com/ -[14]: https://devblogs.microsoft.com/powershell/powershell-standard-library-build-single-module-that-works-across-windows-powershell-and-powershell-core/ -[15]: https://github.com/Pester/Pester -[16]: https://github.com/PowerShell/PowerShellEditorServices/ -[17]: https://github.com/PowerShell/PowerShellEditorServices/blob/8c500ee1752201d3c1cc2e5d90f1a2af3b1eb15d/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs#L231-L251 -[18]: https://github.com/PowerShell/PowerShellEditorServices/blob/8c500ee1752201d3c1cc2e5d90f1a2af3b1eb15d/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj#L15-L20 -[19]: https://github.com/PowerShell/PowerShellStandard -[20]: https://github.com/PowerShell/PSReadLine -[21]: https://github.com/PowerShell/PSReadLine/blob/master/PSReadLine/PSReadLine.csproj -[22]: https://github.com/powershell/psscriptanalyzer -[23]: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Engine/Engine.csproj -[24]: https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell -[25]: https://www.nuget.org/ -[26]: https://www.nuget.org/packages/Microsoft.PowerShell.3.ReferenceAssemblies/ -[27]: https://www.nuget.org/packages/Microsoft.PowerShell.4.ReferenceAssemblies/ -[28]: https://www.nuget.org/packages/Microsoft.PowerShell.5.ReferenceAssemblies/ -[29]: https://www.nuget.org/packages/NETStandard.Library/ -[30]: https://www.nuget.org/packages/PowerShell/ -[31]: https://www.nuget.org/packages/PowerShellStandard.Library/ -[32]: https://www.nuget.org/packages/System.Management.Automation/ +[01]: /dotnet/core/tools/csproj#packagereference +[02]: /dotnet/standard/assembly/reference-assemblies +[03]: /dotnet/standard/net-standard +[04]: /powershell/module/microsoft.powershell.core/about/about_modules +[05]: /powershell/scripting/developer/windows-powershell +[06]: https://code.visualstudio.com/ +[07]: https://devblogs.microsoft.com/powershell/powershell-standard-library-build-single-module-that-works-across-windows-powershell-and-powershell-core/ +[09]: https://github.com/PowerShell/PowerShellEditorServices/ +[10]: https://github.com/PowerShell/PowerShellEditorServices/blob/8c500ee1752201d3c1cc2e5d90f1a2af3b1eb15d/src/PowerShellEditorServices.Hosting/EditorServicesLoader.cs#L231-L251 +[11]: https://github.com/PowerShell/PowerShellEditorServices/blob/8c500ee1752201d3c1cc2e5d90f1a2af3b1eb15d/test/PowerShellEditorServices.Test/PowerShellEditorServices.Test.csproj#L15-L20 +[12]: https://github.com/PowerShell/PowerShellStandard +[13]: https://github.com/PowerShell/PSReadLine +[14]: https://github.com/PowerShell/PSReadLine/blob/master/PSReadLine/PSReadLine.csproj +[15]: https://github.com/powershell/psscriptanalyzer +[16]: https://github.com/PowerShell/PSScriptAnalyzer/blob/master/Engine/Engine.csproj +[17]: https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell +[18]: https://www.nuget.org/ +[19]: https://www.nuget.org/packages/Microsoft.PowerShell.3.ReferenceAssemblies/ +[20]: https://www.nuget.org/packages/Microsoft.PowerShell.4.ReferenceAssemblies/ +[21]: https://www.nuget.org/packages/Microsoft.PowerShell.5.ReferenceAssemblies/ +[22]: https://www.nuget.org/packages/NETStandard.Library/ +[23]: https://www.nuget.org/packages/PowerShell/ +[24]: https://www.nuget.org/packages/PowerShellStandard.Library/ +[25]: https://www.nuget.org/packages/System.Management.Automation/ +[26]: xref:Microsoft.PowerShell.Core.Start-Job +[27]: xref:Microsoft.PowerShell.Utility.Add-Type +[28]: xref:System.Management.Automation.Host.PSHost +[29]: xref:System.Management.Automation.Language.AstVisitor2 +[30]: xref:System.Management.Automation.Provider.CmdletProvider +[31]: xref:System.Management.Automation.PSCmdlet +[32]: xref:System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2%2A diff --git a/reference/docs-conceptual/dev-cross-plat/create-cmdline-predictor.md b/reference/docs-conceptual/dev-cross-plat/create-cmdline-predictor.md index e5ff3bde7913..0a84205fc296 100644 --- a/reference/docs-conceptual/dev-cross-plat/create-cmdline-predictor.md +++ b/reference/docs-conceptual/dev-cross-plat/create-cmdline-predictor.md @@ -1,6 +1,6 @@ --- description: This article describes how to create a command-line predictor to help with command completion in PowerShell. -ms.date: 12/01/2022 +ms.date: 12/08/2025 title: How to create a command-line predictor --- # How to create a command-line predictor diff --git a/reference/docs-conceptual/dev-cross-plat/create-feedback-provider.md b/reference/docs-conceptual/dev-cross-plat/create-feedback-provider.md index a25b7365b55d..c23b1abfd7ac 100644 --- a/reference/docs-conceptual/dev-cross-plat/create-feedback-provider.md +++ b/reference/docs-conceptual/dev-cross-plat/create-feedback-provider.md @@ -1,6 +1,6 @@ --- description: This article describes how to create a feedback provider. -ms.date: 11/14/2023 +ms.date: 12/08/2025 title: How to create a feedback provider --- # How to create a feedback provider diff --git a/reference/docs-conceptual/dev-cross-plat/create-standard-library-binary-Module.md b/reference/docs-conceptual/dev-cross-plat/create-standard-library-binary-Module.md index f822223ce28d..6c78e965edd2 100644 --- a/reference/docs-conceptual/dev-cross-plat/create-standard-library-binary-Module.md +++ b/reference/docs-conceptual/dev-cross-plat/create-standard-library-binary-Module.md @@ -1,7 +1,7 @@ --- description: The PowerShell Standard Library allows us to create cross platform modules that work in both PowerShell and with Windows PowerShell 5.1. ms.custom: contributor-KevinMarquette -ms.date: 02/02/2023 +ms.date: 12/08/2025 title: How to create a Standard Library Binary Module --- # How to create a Standard Library binary module diff --git a/reference/docs-conceptual/dev-cross-plat/performance/module-authoring-considerations.md b/reference/docs-conceptual/dev-cross-plat/performance/module-authoring-considerations.md index b94ded572ffa..1fad6f39283a 100644 --- a/reference/docs-conceptual/dev-cross-plat/performance/module-authoring-considerations.md +++ b/reference/docs-conceptual/dev-cross-plat/performance/module-authoring-considerations.md @@ -1,6 +1,6 @@ --- description: PowerShell module authoring considerations -ms.date: 11/16/2022 +ms.date: 12/08/2025 title: PowerShell module authoring considerations --- diff --git a/reference/docs-conceptual/dev-cross-plat/resolving-dependency-conflicts.md b/reference/docs-conceptual/dev-cross-plat/resolving-dependency-conflicts.md index 9299814608f8..7bb34542ffb3 100644 --- a/reference/docs-conceptual/dev-cross-plat/resolving-dependency-conflicts.md +++ b/reference/docs-conceptual/dev-cross-plat/resolving-dependency-conflicts.md @@ -1,6 +1,5 @@ --- description: When writing a binary PowerShell module in C#, it's natural to take dependencies on other packages or libraries to provide functionality. -ms.custom: rjmholt ms.date: 08/08/2022 title: Resolving PowerShell module assembly dependency conflicts --- @@ -14,7 +13,7 @@ unrelated modules in the same PowerShell session. If you've had this problem, you've seen an error message like this: -![Assembly load conflict error message][1] +![Assembly load conflict error message][06] This article looks at some ways dependency conflicts occur in PowerShell and ways to mitigate dependency conflict issues. Even if you're not a module author, there are some tricks in here that @@ -24,7 +23,7 @@ might help you with dependency conflicts occurring in modules that you use. In .NET, dependency conflicts occur when two versions of the same assembly are loaded into the same _Assembly Load Context_. This term means slightly different things on different .NET platforms, -which is covered [later][2] in this article. This conflict is a common problem that occurs in any +which is covered [later][17] in this article. This conflict is a common problem that occurs in any software where versioned dependencies are used. Conflict issues are compounded by the fact that a project almost never deliberately or directly @@ -34,7 +33,7 @@ that each require a different version of the same dependency. For example, say your .NET application, `DuckBuilder`, brings in two dependencies, to perform parts of its functionality and looks like this: -![Two dependencies of DuckBuilder rely on different versions of Newtonsoft.Json][3] +![Two dependencies of DuckBuilder rely on different versions of Newtonsoft.Json][03] Because `Contoso.ZipTools` and `Fabrikam.FileHelpers` both depend on different versions of **Newtonsoft.Json**, there may be a dependency conflict depending on how each dependency is loaded. @@ -45,7 +44,7 @@ In PowerShell, the dependency conflict issue is magnified because PowerShell's o loaded into the same shared context. This means the PowerShell engine and all loaded PowerShell modules must not have conflicting dependencies. A classic example of this is **Newtonsoft.Json**: -![FictionalTools module depends on newer version of Newtonsoft.Json than PowerShell][4] +![FictionalTools module depends on newer version of Newtonsoft.Json than PowerShell][04] In this example, the module `FictionalTools` depends on **Newtonsoft.Json** version `12.0.3`, which is a newer version of **Newtonsoft.Json** than `11.0.2` that ships in the example PowerShell. @@ -66,7 +65,7 @@ assembly. This often looks like the following: -![Two PowerShell modules require different versions of the Microsoft.Extensions.Logging dependency][5] +![Two PowerShell modules require different versions of the Microsoft.Extensions.Logging dependency][05] In this case, the `FictionalTools` module requires a newer version of `Microsoft.Extensions.Logging` than the `FilesystemManager` module. @@ -100,7 +99,7 @@ in each ALC. The semantics of assembly loading depend on both the .NET implementation (.NET Core vs .NET Framework) and the .NET API used to load a particular assembly. Rather than go into detail here, -there are links in the [Further reading][6] section that go into great detail on how .NET assembly +there are links in the [Further reading][16] section that go into great detail on how .NET assembly loading works in each .NET implementation. In this article we'll refer to the following mechanisms: @@ -115,7 +114,7 @@ In this article we'll refer to the following mechanisms: ### Differences in .NET Framework vs .NET Core The way these APIs work has changed in subtle ways between .NET Core and .NET Framework, so it's -worth reading through the included [links][7]. Importantly, Assembly Load Contexts and other +worth reading through the included [links][16]. Importantly, Assembly Load Contexts and other assembly resolution mechanisms have changed between .NET Framework and .NET Core. In particular, .NET Framework has the following features: @@ -132,7 +131,7 @@ In particular, .NET Framework has the following features: - The mysterious void that assemblies loaded with `Assembly.LoadFile(string path)` and `Assembly.Load(byte[] asmBytes)` live in -For more information, see [Best Practices for Assembly Loading][8]. +For more information, see [Best Practices for Assembly Loading][12]. .NET Core (and .NET 5+) has replaced this complexity with a simpler model: @@ -338,7 +337,7 @@ In PowerShell, there are several ways to achieve this: Be aware that modules may not be compatible with or may work differently with Windows PowerShell. -#### When out-of-process invocation should not be used +#### When out-of-process invocation shouldn't be used As a module author, out-of-process command invocation is difficult to bake into a module and may have edge cases that cause issues. In particular, remoting and jobs may not be available in all @@ -349,7 +348,7 @@ be applicable. As a module user, there are cases where out-of-process invocation won't work: - When PowerShell remoting is unavailable because you don't have privileges to use it or it - is not enabled. + isn't enabled. - When a particular .NET type is needed from output as input to a method or another command. Commands running over PowerShell remoting emit deserialized objects rather than strongly-typed .NET objects. This means that method calls and strongly typed APIs don't work with the output of @@ -364,20 +363,20 @@ carefully. ### Loading through .NET Core Assembly Load Contexts -[Assembly Load Contexts][9] (ALCs) were introduced in .NET Core 1.0 to specifically address the need +[Assembly Load Contexts][31] (ALCs) were introduced in .NET Core 1.0 to specifically address the need to load multiple versions of the same assembly into the same runtime. Within .NET, they offer the most robust solution to the problem of loading conflicting versions of -an assembly. However, custom ALCs are not available in .NET Framework. This means that this solution +an assembly. However, custom ALCs aren't available in .NET Framework. This means that this solution only works in PowerShell 6 and above. Currently, the best example of using an ALC for dependency isolation in PowerShell is in PowerShell Editor Services, the language server for the PowerShell extension for Visual Studio Code. An -[ALC is used][10] to prevent PowerShell Editor Services' own dependencies from clashing with those +[ALC is used][24] to prevent PowerShell Editor Services' own dependencies from clashing with those in PowerShell modules. Implementing module dependency isolation with an ALC is conceptually difficult, but we will work -through a minimal example. Imagine we have a simple module that is only intended to work in +through a minimal example. Imagine we've a simple module that's only intended to work in PowerShell 7. The source code is organized as follows: ``` @@ -473,7 +472,7 @@ To mediate these two requirements, we must break up our module into two assembli Using this bridge concept, our new assembly situation looks like this: -![Diagram representing AlcModule.Engine.dll bridging the two ALCs][11] +![Diagram representing AlcModule.Engine.dll bridging the two ALCs][01] To make sure the default ALC's dependency probing logic doesn't resolve the dependencies to be loaded into the custom ALC, we need to separate these two parts of the module in different @@ -610,7 +609,7 @@ namespace AlcModule.Cmdlets // all of *its* dependencies will be resolved // by the logic we defined for that ALC's implementation. // - // Note that we are safe in our assumption that the name is enough + // Note that we're safe in our assumption that the name is enough // to distinguish our assembly here, // since it's unique to our module. // There should be no other AlcModule.Engine.dll on the system. @@ -633,7 +632,7 @@ namespace AlcModule.Cmdlets With the new implementation, take a look at the sequence of calls that occurs when the module is loaded and `Test-AlcModule` is run: -![Sequence diagram of calls using the custom ALC to load dependencies][12] +![Sequence diagram of calls using the custom ALC to load dependencies][02] Some points of interest are: @@ -757,15 +756,15 @@ Get-ChildItem -Path "$cmdletsSrc/bin/$Configuration/$netcore/publish/" | ForEach-Object { Copy-Item -Path $_.FullName -Destination $outDir } ``` -Finally, we have a general way to isolate our module's dependencies in an Assembly Load Context that +Finally, we've a general way to isolate our module's dependencies in an Assembly Load Context that remains robust over time as more dependencies are added. -For a more detailed example, go to this [GitHub repository][13]. This example demonstrates how to +For a more detailed example, go to this [GitHub repository][26]. This example demonstrates how to migrate a module to use an ALC, while keeping that module working in .NET Framework. It also shows how to use .NET Standard and PowerShell Standard to simplify the core implementation. -This solution is also used by the [Bicep PowerShell module][14], and the blog post -[Resolving PowerShell Module Conflicts][15] is another good read about this solution. +This solution is also used by the [Bicep PowerShell module][25], and the blog post +[Resolving PowerShell Module Conflicts][28] is another good read about this solution. ### Assembly resolving handler for side-by-side loading @@ -780,21 +779,21 @@ this solution: There is a simplified solution to achieve side-by-side assembly loading, by hooking up a `Resolving` event with a custom `AssemblyLoadContext` instance. Using this method is easier for the module -author but has two limitations. Check out the [PowerShell-ALC-Samples][16] repository for sample +author but has two limitations. Check out the [PowerShell-ALC-Samples][19] repository for sample code and documentation that describes these limitations and detailed scenarios for this solution. > [!IMPORTANT] -> Do not use `Assembly.LoadFile` for the dependency isolation purpose. Using `Assembly.LoadFile` +> Don't use `Assembly.LoadFile` for the dependency isolation purpose. Using `Assembly.LoadFile` > creates a _Type Identity_ issue when another module loads a different version of the same assembly > into the default `AssemblyLoadContext`. While this API loads an assembly to a separate > `AssemblyLoadContext` instance, the assemblies loaded are discoverable by PowerShell's -> [type resolution code][33]. Therefore, there could be duplicate types with the same fully qualifed +> [type resolution code][21]. Therefore, there could be duplicate types with the same fully qualifed > type name available from two different ALCs. ### Custom Application Domains The final and most extreme option for assembly isolation is to use custom **Application Domains**. -**Application Domains** are only available in .NET Framework. They are used to provide in-process +**Application Domains** are only available in .NET Framework. They're used to provide in-process isolation between parts of a .NET application. One of the uses is to isolate assembly loads from each other within the same process. @@ -811,15 +810,15 @@ mentioning as a possibility, they're not recommended. If you're interested in trying to use a custom application domain, the following links might help: -- [Conceptual documentation on Application Domains][17] -- [Examples for using Application Domains][18] +- [Conceptual documentation on Application Domains][09] +- [Examples for using Application Domains][10] ## Solutions for dependency conflicts that don't work for PowerShell Finally, we'll address some possibilities that come up when researching .NET dependency conflicts in .NET that can look promising, but generally won't work for PowerShell. -These solutions have the common theme that they are changes to deployment configurations for an +These solutions have the common theme that they're changes to deployment configurations for an environment where you control the application and possibly the entire machine. These solutions are oriented toward scenarios like web servers and other applications deployed to server environments, where the environment is intended to host the application and is free to be configured by the @@ -841,12 +840,12 @@ Two issues with this for PowerShell are: - .NET Core doesn't support `app.config`, so this solution only applies to `powershell.exe`. - `powershell.exe` is a shared application that lives in the `System32` directory. It's likely that - your module won't be able to modify its contents on many systems. Even if it can, modifying - the `app.config` could break an existing configuration or affect the loading of other modules. + your module won't be able to modify its contents on many systems. Even if it can, modifying the + `app.config` could break an existing configuration or affect the loading of other modules. ### Setting `codebase` with app.config -For the same reasons, trying to configure the `codebase` setting in `app.config` is not going to +For the same reasons, trying to configure the `codebase` setting in `app.config` isn't going to work in PowerShell modules. ### Installing dependencies to the Global Assembly Cache (GAC) @@ -856,7 +855,7 @@ the GAC, so that different versions can be loaded side-by-side from the GAC. Again, for PowerShell modules, the chief issues here are: -- The GAC only applies to .NET Framework, so this does not help in PowerShell 6 and above. +- The GAC only applies to .NET Framework, so this doesn't help in PowerShell 6 and above. - Installing assemblies to the GAC is a modification of global machine state and may cause side-effects in other applications or to other modules. It may also be difficult to do correctly, even when your module has the required access privileges. Getting it wrong could cause serious, @@ -867,52 +866,50 @@ Again, for PowerShell modules, the chief issues here are: There's plenty more to read on .NET assembly version dependency conflicts. Here are some nice jumping off points: -- [.NET: Assemblies in .NET][19] -- [.NET Core: The managed assembly loading algorithm][20] -- [.NET Core: Understanding System.Runtime.Loader.AssemblyLoadContext][21] -- [.NET Core: Discussion about side-by-side assembly loading solutions][22] -- [.NET Framework: Redirecting assembly versions][23] -- [.NET Framework: Best practices for assembly loading][24] -- [.NET Framework: How the runtime locates assemblies][25] -- [.NET Framework: Resolve assembly loads][26] -- [Stack Overflow: Assembly binding redirect, how and why?][27] -- [PowerShell: Discussion about implementing AssemblyLoadContexts][28] -- [PowerShell: `Assembly.LoadFile()` doesn't load into default AssemblyLoadContext][29] +- [.NET: Assemblies in .NET][14] +- [.NET Core: The managed assembly loading algorithm][07] +- [.NET Core: Understanding System.Runtime.Loader.AssemblyLoadContext][08] +- [.NET Core: Discussion about side-by-side assembly loading solutions][13471] +- [.NET Framework: Redirecting assembly versions][11] +- [.NET Framework: Best practices for assembly loading][12] +- [.NET Framework: How the runtime locates assemblies][13] +- [.NET Framework: Resolve assembly loads][15] +- [Stack Overflow: Assembly binding redirect, how and why?][29] +- [PowerShell: Discussion about implementing AssemblyLoadContexts][11571] +- [PowerShell: `Assembly.LoadFile()` doesn't load into default AssemblyLoadContext][12052] - [Rick Strahl: When does a .NET assembly dependency get loaded?][30] -- [Jon Skeet: Summary of versioning in .NET][31] -- [Nate McMaster: Deep dive into .NET Core primitives][32] +- [Jon Skeet: Summary of versioning in .NET][18] +- [Nate McMaster: Deep dive into .NET Core primitives][27] -[1]: ./media/resolving-dependency-conflicts/moduleconflict.png -[2]: #powershell-and-net -[3]: ./media/resolving-dependency-conflicts/dep-conflict.jpg -[4]: ./media/resolving-dependency-conflicts/engine-conflict.jpg -[5]: ./media/resolving-dependency-conflicts/mod-conflict.jpg -[6]: #further-reading -[7]: #further-reading -[8]: /dotnet/framework/deployment/best-practices-for-assembly-loading -[9]: /dotnet/api/system.runtime.loader.assemblyloadcontext -[10]: https://github.com/PowerShell/PowerShellEditorServices/blob/master/src/PowerShellEditorServices.Hosting/Internal/PsesLoadContext.cs -[11]: ./media/resolving-dependency-conflicts/alc-diagram.jpg -[12]: ./media/resolving-dependency-conflicts/alc-sequence.png -[13]: https://github.com/rjmholt/ModuleDependencyIsolationExample -[14]: https://github.com/PSBicep/PSBicep -[15]: https://pipe.how/get-assemblyloadcontext/ -[16]: https://github.com/daxian-dbw/PowerShell-ALC-Samples -[17]: /dotnet/framework/app-domains/application-domains -[18]: /dotnet/framework/app-domains/use -[19]: /dotnet/standard/assembly/ -[20]: /dotnet/core/dependency-loading/loading-managed -[21]: /dotnet/core/dependency-loading/understanding-assemblyloadcontext -[22]: https://github.com/dotnet/runtime/issues/13471 -[23]: /dotnet/framework/configure-apps/redirect-assembly-versions -[24]: /dotnet/framework/deployment/best-practices-for-assembly-loading -[25]: /dotnet/framework/deployment/how-the-runtime-locates-assemblies -[26]: /dotnet/standard/assembly/resolve-loads -[27]: https://stackoverflow.com/questions/43365736/assembly-binding-redirect-how-and-why -[28]: https://github.com/PowerShell/PowerShell/issues/11571 -[29]: https://github.com/PowerShell/PowerShell/issues/12052 +[01]: ./media/resolving-dependency-conflicts/alc-diagram.jpg +[02]: ./media/resolving-dependency-conflicts/alc-sequence.png +[03]: ./media/resolving-dependency-conflicts/dep-conflict.jpg +[04]: ./media/resolving-dependency-conflicts/engine-conflict.jpg +[05]: ./media/resolving-dependency-conflicts/mod-conflict.jpg +[06]: ./media/resolving-dependency-conflicts/moduleconflict.png +[07]: /dotnet/core/dependency-loading/loading-managed +[08]: /dotnet/core/dependency-loading/understanding-assemblyloadcontext +[09]: /dotnet/framework/app-domains/application-domains +[10]: /dotnet/framework/app-domains/use +[11]: /dotnet/framework/configure-apps/redirect-assembly-versions +[12]: /dotnet/framework/deployment/best-practices-for-assembly-loading +[13]: /dotnet/framework/deployment/how-the-runtime-locates-assemblies +[14]: /dotnet/standard/assembly/ +[15]: /dotnet/standard/assembly/resolve-loads +[16]: #further-reading +[17]: #powershell-and-net +[18]: https://codeblog.jonskeet.uk/2019/06/30/versioning-limitations-in-net/ +[19]: https://github.com/daxian-dbw/PowerShell-ALC-Samples +[21]: https://github.com/PowerShell/PowerShell/blob/918bb8c952af1d461abfc98bc709a1d359168a1c/src/System.Management.Automation/utils/ClrFacade.cs#L56-L61 +[24]: https://github.com/PowerShell/PowerShellEditorServices/blob/master/src/PowerShellEditorServices.Hosting/Internal/PsesLoadContext.cs +[25]: https://github.com/PSBicep/PSBicep +[26]: https://github.com/rjmholt/ModuleDependencyIsolationExample +[27]: https://natemcmaster.com/blog/2017/12/21/netcore-primitives/ +[28]: https://pipe.how/get-assemblyloadcontext/ +[29]: https://stackoverflow.com/questions/43365736/assembly-binding-redirect-how-and-why [30]: https://weblog.west-wind.com/posts/2012/Nov/03/Back-to-Basics-When-does-a-NET-Assembly-Dependency-get-loaded -[31]: https://codeblog.jonskeet.uk/2019/06/30/versioning-limitations-in-net/ -[32]: https://natemcmaster.com/blog/2017/12/21/netcore-primitives/ -[33]: https://github.com/PowerShell/PowerShell/blob/918bb8c952af1d461abfc98bc709a1d359168a1c/src/System.Management.Automation/utils/ClrFacade.cs#L56-L61 +[31]: xref:System.Runtime.Loader.AssemblyLoadContext +[11571]: https://github.com/PowerShell/PowerShell/issues/11571 +[12052]: https://github.com/PowerShell/PowerShell/issues/12052 +[13471]: https://github.com/dotnet/runtime/issues/13471 diff --git a/reference/docs-conceptual/dev-cross-plat/vscode/How-To-Replicate-the-ISE-Experience-In-VSCode.md b/reference/docs-conceptual/dev-cross-plat/vscode/How-To-Replicate-the-ISE-Experience-In-VSCode.md index f8a89a84a7e2..c66a8597df3b 100644 --- a/reference/docs-conceptual/dev-cross-plat/vscode/How-To-Replicate-the-ISE-Experience-In-VSCode.md +++ b/reference/docs-conceptual/dev-cross-plat/vscode/How-To-Replicate-the-ISE-Experience-In-VSCode.md @@ -1,6 +1,6 @@ --- description: How to replicate the ISE experience in Visual Studio Code -ms.date: 11/16/2022 +ms.date: 12/08/2025 title: How to replicate the ISE experience in Visual Studio Code --- diff --git a/reference/docs-conceptual/dev-cross-plat/vscode/Using-VSCode-for-Remote-Editing-and-Debugging.md b/reference/docs-conceptual/dev-cross-plat/vscode/Using-VSCode-for-Remote-Editing-and-Debugging.md index 6e705073fbd4..d14269ec4693 100644 --- a/reference/docs-conceptual/dev-cross-plat/vscode/Using-VSCode-for-Remote-Editing-and-Debugging.md +++ b/reference/docs-conceptual/dev-cross-plat/vscode/Using-VSCode-for-Remote-Editing-and-Debugging.md @@ -1,6 +1,6 @@ --- description: Using Visual Studio Code for remote editing and debugging -ms.date: 11/16/2022 +ms.date: 12/08/2025 title: Using Visual Studio Code for remote editing and debugging --- # Using Visual Studio Code for remote editing and debugging diff --git a/reference/docs-conceptual/dev-cross-plat/vscode/understanding-file-encoding.md b/reference/docs-conceptual/dev-cross-plat/vscode/understanding-file-encoding.md index d700afb5dd72..498c288c6851 100644 --- a/reference/docs-conceptual/dev-cross-plat/vscode/understanding-file-encoding.md +++ b/reference/docs-conceptual/dev-cross-plat/vscode/understanding-file-encoding.md @@ -1,6 +1,6 @@ --- description: Configure file encoding in VS Code and PowerShell -ms.date: 11/29/2023 +ms.date: 12/08/2025 title: Understanding file encoding in VS Code and PowerShell --- # Understanding file encoding in VS Code and PowerShell diff --git a/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode-for-debugging-compiled-cmdlets.md b/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode-for-debugging-compiled-cmdlets.md index 368ae4e6af0c..965f77be5d1e 100644 --- a/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode-for-debugging-compiled-cmdlets.md +++ b/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode-for-debugging-compiled-cmdlets.md @@ -1,6 +1,6 @@ --- description: How to set a build task and launch configuration for a PSModule project in .NET Core -ms.date: 11/16/2022 +ms.date: 12/08/2025 title: Using Visual Studio Code to debug compiled cmdlets --- # Using Visual Studio Code to debug compiled cmdlets diff --git a/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode.md b/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode.md index 3a278f4ccb4f..40412aa85589 100644 --- a/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode.md +++ b/reference/docs-conceptual/dev-cross-plat/vscode/using-vscode.md @@ -1,6 +1,6 @@ --- description: Using Visual Studio Code for PowerShell Development -ms.date: 09/09/2022 +ms.date: 12/08/2025 title: Using Visual Studio Code for PowerShell Development ---