From 1334b4cbf265690aa245f470f846693f073756a6 Mon Sep 17 00:00:00 2001 From: "Christoph Bergmeister [MVP]" Date: Fri, 11 Jan 2019 22:06:22 +0000 Subject: [PATCH] Update examples for hosting PSCore and remove old outdated examples (#8472) --- .spelling | 1 + docs/host-powershell/README.md | 167 +++--------------- .../sample-dotnet1.1/Logic/Logic.csproj | 16 -- .../sample-dotnet1.1/Logic/UseRunspace.cs | 36 ---- .../sample-dotnet1.1/MyApp/MyApp.csproj | 17 -- .../sample-dotnet1.1/MyApp/Program.cs | 31 ---- .../MyApp/MyApp.csproj | 13 -- .../MyApp/Program.cs | 26 --- .../NuGet.config | 8 - .../Logic/Logic.csproj | 15 -- .../Logic/UseRunspace.cs | 36 ---- .../MyApp/MyApp.csproj | 15 -- .../MyApp/Program.cs | 31 ---- .../NuGet.config | 8 - .../NuGet.config | 8 - .../MyApp/MyApp.csproj | 10 +- .../MyApp/Program.cs | 0 .../{sample-dotnet1.1 => sample}/NuGet.config | 0 18 files changed, 26 insertions(+), 412 deletions(-) delete mode 100644 docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj delete mode 100644 docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs delete mode 100644 docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj delete mode 100644 docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell.beta.1/NuGet.config delete mode 100644 docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config rename docs/host-powershell/{sample-dotnet2.0-powershell.beta.3 => sample}/MyApp/MyApp.csproj (67%) rename docs/host-powershell/{sample-dotnet2.0-powershell.beta.3 => sample}/MyApp/Program.cs (100%) rename docs/host-powershell/{sample-dotnet1.1 => sample}/NuGet.config (100%) diff --git a/.spelling b/.spelling index e55fca3653..573f28d302 100644 --- a/.spelling +++ b/.spelling @@ -139,6 +139,7 @@ cron crontab crossgen crossgen'ing +crossplatform csharp csmacnz csphysicallyinstalledmemory diff --git a/docs/host-powershell/README.md b/docs/host-powershell/README.md index 506d5b71d8..1f14267b2f 100644 --- a/docs/host-powershell/README.md +++ b/docs/host-powershell/README.md @@ -2,162 +2,25 @@ ## PowerShell Core v6.0.1 and Later -The runtime assemblies for Windows, Linux and OSX are now published in NuGet package version 6.0.1.1 and above. +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 `6.0.1.1` NuGet packages. - -## PowerShell Core v6.0.0-beta.3 and Later - -PowerShell Core is refactored in v6.0.0-beta.3 to remove the dependency on a customized `AssemblyLoadContext`. -With this change, hosting PowerShell Core in .NET Core will be the same as hosting Windows PowerShell in .NET. - -Please see the [.NET Core Sample Application](#net-core-sample-application) section for an example that uses PowerShell Core `beta.3` NuGet packages. - -## PowerShell Core v6.0.0-beta.2 and Prior - -### Overview - -Due to the lack of necessary APIs for manipulating assemblies in .NET Core 1.1 and prior, -PowerShell Core needs to control assembly loading via our customized `AssemblyLoadContext` ([CorePsAssemblyLoadContext.cs][]) in order to do tasks like type resolution. -So applications that want to host PowerShell Core (using PowerShell APIs) need to be bootstrapped from `PowerShellAssemblyLoadContextInitializer`. - -`PowerShellAssemblyLoadContextInitializer` exposes 2 APIs for this purpose: -`SetPowerShellAssemblyLoadContext` and `InitializeAndCallEntryMethod`. -They are for different scenarios: - -- `SetPowerShellAssemblyLoadContext` - It's designed to be used by a native host - whose Trusted Platform Assemblies (TPA) do not include PowerShell assemblies, - such as the in-box `powershell.exe` and other native CoreCLR host in Nano Server. - When using this API, instead of setting up a new load context, - `PowerShellAssemblyLoadContextInitializer` will register a handler to the [Resolving][] event of the default load context. - Then PowerShell Core will depend on the default load context to handle TPA and the `Resolving` event to handle other assemblies. - -- `InitializeAndCallEntryMethod` - It's designed to be used with `dotnet.exe` - where the TPA list includes PowerShell assemblies. - When using this API, `PowerShellAssemblyLoadContextInitializer` will set up a new load context to handle all assemblies. - PowerShell Core itself also uses this API for [bootstrapping][]. - -This documentation only covers the `InitializeAndCallEntryMethod` API, -as it's what you need when building a .NET Core application with .NET CLI. - -### Comparison - Hosting Windows PowerShell vs. Hosting PowerShell Core - -The following code demonstrates how to host Windows PowerShell in an application. -As shown below, you can insert your business logic code directly in the `Main` method. - -```CSharp -// MyApp.exe -using System; -using System.Management.Automation; - -public class Program -{ - static void Main(string[] args) - { - // My business logic code - using (PowerShell ps = PowerShell.Create()) - { - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - } - } -} -``` - -However, when it comes to hosting PowerShell Core, there will be a layer of redirection for the PowerShell load context to take effect. -In a .NET Core application, the entry point assembly that contains the `Main` method is loaded in the default load context, -and thus all assemblies referenced by the entry point assembly, implicitly or explicitly, will also be loaded into the default load context. - -In order to have the PowerShell load context to control assembly loading for the execution of an application, -the business logic code needs to be extracted out of the entry point assembly and put into a different assembly, say `Logic.dll`. -The entry point `Main` method shall do one thing only -- let the PowerShell load context load `Logic.dll` and start the execution of the business logic. -Once the execution starts this way, all further assembly loading requests will be handled by the PowerShell load context. - -So the above example needs to be altered as follows in a .NET Core application: - -```CSharp -// MyApp.exe -using System.Management.Automation; -using System.Reflection; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program - /// - public static int Main(string[] args) - { - // Application needs to use PowerShell AssemblyLoadContext if it needs to create PowerShell runspace - // PowerShell engine depends on PS ALC to provide the necessary assembly loading/searching support that is missing from .NET Core - string appBase = System.IO.Path.GetDirectoryName(typeof(Program).GetTypeInfo().Assembly.Location); - System.Console.WriteLine("\nappBase: {0}", appBase); - - // Initialize the PS ALC and let it load 'Logic.dll' and start the execution - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), - "Application.Test.Logic", - "Start", - new object[] { args }); - } - } -} - -// Logic.dll -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; - -namespace Application.Test -{ - public sealed class Logic - { - /// - /// Start the actual logic - /// - public static int Start(string[] args) - { - // My business logic code - using (PowerShell ps = PowerShell.Create()) - { - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - } - return 0; - } - } -} -``` - -[CorePsAssemblyLoadContext.cs]: https://github.com/PowerShell/PowerShell/blob/v6.0.0-beta.2/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs -[Resolving]: https://github.com/dotnet/corefx/blob/ec2a6190efa743ab600317f44d757433e44e859b/src/System.Runtime.Loader/ref/System.Runtime.Loader.cs#L35 -[bootstrapping]: https://github.com/PowerShell/PowerShell/blob/v6.0.0-beta.2/src/powershell/Program.cs#L27 +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 -- [sample-dotnet1.1](./sample-dotnet1.1) - .NET Core `1.1` + PowerShell Core `alpha.17` NuGet packages. - [.NET Core SDK 1.0.1](https://github.com/dotnet/cli/releases/tag/v1.0.1) is required. -- [sample-dotnet2.0-powershell.beta.1](./sample-dotnet2.0-powershell.beta.1) - .NET Core `2.0.0` + PowerShell Core `beta.1` NuGet packages. - .NET Core SDK `2.0.0-preview1-005952` or higher is required. -- [sample-dotnet2.0-powershell.beta.3](./sample-dotnet2.0-powershell.beta.3) - .NET Core `2.0.0` + PowerShell Core `beta.3` NuGet packages. - .NET Core SDK `2.0.0-preview1-005952` or higher is required. -- [sample-dotnet2.0-powershell-crossplatform](./sample-dotnet2.0-powershell-crossplatform) - .Net Core `2.0.0` + PowerShell Core `6.0.1.1` NuGet packages. +Note: The .NET Core `2.1` runtime and .NET Core SDK `2.1` or higher is required for the examples below: -You can find the sample application project `"MyApp"` in each of the above 3 sample folders. -To build the sample project, run the following commands (make sure the required .NET Core SDK is in use): +- [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 restore .\MyApp\MyApp.csproj -dotnet publish .\MyApp -c release -r win10-x64 +dotnet publish .\MyApp --configuration release ``` -For cross platform project there is no need to specify `-r win10-x64`. -The runtime for the build machine's platform will automatically be selected. - -Then you can run `MyApp.exe` from the publish folder and see the results: +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 @@ -171,3 +34,13 @@ Evaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS C 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://docs.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. diff --git a/docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj b/docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj deleted file mode 100644 index dc8816bca5..0000000000 --- a/docs/host-powershell/sample-dotnet1.1/Logic/Logic.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - netstandard1.6 - Logic - win10-x64 - $(PackageTargetFallback);dnxcore50;portable-net45+win8 - - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs b/docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs deleted file mode 100644 index 57264108a7..0000000000 --- a/docs/host-powershell/sample-dotnet1.1/Logic/UseRunspace.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; - -namespace Application.Test -{ - public sealed class Logic - { - /// - /// Start the actual logic. - /// - public static int Start(string[] args) - { - using (PowerShell ps = PowerShell.Create()) - { - Console.WriteLine("\nEvaluating 'Get-Command Write-Output' in PS Core Runspace\n"); - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - - ps.Commands.Clear(); - - Console.WriteLine("\nEvaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS Core Runspace\n"); - results = ps.AddScript("([System.Management.Automation.ActionPreference], [System.Management.Automation.AliasAttribute]).FullName").Invoke(); - foreach (dynamic result in results) - { - Console.WriteLine(result.ToString()); - } - } - - return 0; - } - } -} diff --git a/docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj b/docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj deleted file mode 100644 index 012db33cc6..0000000000 --- a/docs/host-powershell/sample-dotnet1.1/MyApp/MyApp.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - netcoreapp1.1 - MyApp - Exe - win10-x64 - $(PackageTargetFallback);dnxcore50;portable-net45+win8 - 1.1.1 - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs b/docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs deleted file mode 100644 index 232f41db82..0000000000 --- a/docs/host-powershell/sample-dotnet1.1/MyApp/Program.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Management.Automation; -using System.Reflection; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program. - /// - public static int Main(string[] args) - { - // Application needs to use PowerShell AssemblyLoadContext if it needs to create powershell runspace - // PowerShell engine depends on PS ALC to provide the necessary assembly loading/searching support that is missing from .NET Core - string appBase = System.IO.Path.GetDirectoryName(typeof(Program).GetTypeInfo().Assembly.Location); - System.Console.WriteLine("\nappBase: {0}", appBase); - - // Initialize the PS ALC and let it load 'Logic.dll' and start the execution - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), - "Application.Test.Logic", - "Start", - new object[] { args }); - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj deleted file mode 100644 index 57db49f147..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/MyApp.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netcoreapp2.0 - MyApp - Exe - win10-x64;linux-x64;osx-x64 - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs deleted file mode 100644 index ea25f0b631..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/MyApp/Program.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Management.Automation; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program. - /// - public static int Main(string[] args) - { - using (PowerShell ps = PowerShell.Create()) - { - Console.WriteLine("\nEvaluating 'Get-Command Write-Output' in PS Core Runspace\n"); - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - } - - return 0; - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config b/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config deleted file mode 100644 index 58f8d2c9b6..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell-crossplatform/NuGet.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj deleted file mode 100644 index 0d32ce0bbf..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/Logic.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - Logic - win10-x64 - - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs deleted file mode 100644 index 57264108a7..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/Logic/UseRunspace.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; - -namespace Application.Test -{ - public sealed class Logic - { - /// - /// Start the actual logic. - /// - public static int Start(string[] args) - { - using (PowerShell ps = PowerShell.Create()) - { - Console.WriteLine("\nEvaluating 'Get-Command Write-Output' in PS Core Runspace\n"); - var results = ps.AddScript("Get-Command Write-Output").Invoke(); - Console.WriteLine(results[0].ToString()); - - ps.Commands.Clear(); - - Console.WriteLine("\nEvaluating '([S.M.A.ActionPreference], [S.M.A.AliasAttribute]).FullName' in PS Core Runspace\n"); - results = ps.AddScript("([System.Management.Automation.ActionPreference], [System.Management.Automation.AliasAttribute]).FullName").Invoke(); - foreach (dynamic result in results) - { - Console.WriteLine(result.ToString()); - } - } - - return 0; - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj deleted file mode 100644 index 6bdba82519..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/MyApp.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - - netcoreapp2.0 - MyApp - Exe - win10-x64 - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs deleted file mode 100644 index 232f41db82..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/MyApp/Program.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Management.Automation; -using System.Reflection; - -namespace Application.Test -{ - public class Program - { - /// - /// Managed entry point shim, which starts the actual program. - /// - public static int Main(string[] args) - { - // Application needs to use PowerShell AssemblyLoadContext if it needs to create powershell runspace - // PowerShell engine depends on PS ALC to provide the necessary assembly loading/searching support that is missing from .NET Core - string appBase = System.IO.Path.GetDirectoryName(typeof(Program).GetTypeInfo().Assembly.Location); - System.Console.WriteLine("\nappBase: {0}", appBase); - - // Initialize the PS ALC and let it load 'Logic.dll' and start the execution - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Logic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"), - "Application.Test.Logic", - "Start", - new object[] { args }); - } - } -} diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/NuGet.config b/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/NuGet.config deleted file mode 100644 index 58f8d2c9b6..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.1/NuGet.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config b/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config deleted file mode 100644 index 58f8d2c9b6..0000000000 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/NuGet.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/MyApp.csproj b/docs/host-powershell/sample/MyApp/MyApp.csproj similarity index 67% rename from docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/MyApp.csproj rename to docs/host-powershell/sample/MyApp/MyApp.csproj index 6901e37dda..b03d053c16 100644 --- a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/MyApp.csproj +++ b/docs/host-powershell/sample/MyApp/MyApp.csproj @@ -1,16 +1,16 @@  - netcoreapp2.0 + netcoreapp2.1 MyApp Exe - win10-x64 + win10-x64;linux-x64;osx-x64 - - - + + + diff --git a/docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/Program.cs b/docs/host-powershell/sample/MyApp/Program.cs similarity index 100% rename from docs/host-powershell/sample-dotnet2.0-powershell.beta.3/MyApp/Program.cs rename to docs/host-powershell/sample/MyApp/Program.cs diff --git a/docs/host-powershell/sample-dotnet1.1/NuGet.config b/docs/host-powershell/sample/NuGet.config similarity index 100% rename from docs/host-powershell/sample-dotnet1.1/NuGet.config rename to docs/host-powershell/sample/NuGet.config