Not sure if this is the right place or if my problem is an issue or by design. We are currently looking alternatives for a self developed scripting engine.
Our partners know Powershell, however one of our requirements is independence on any "installed" software, so Windows Powershell, even though it should be available on every Windows 7+, can not be considered.
We are looking at Powershell Core because as far as we understand we should be able to provide everything that is necessary to run a script by simple copy-deployement.
Furthermore, we want to have control over which Cmdlets can be executed ("sandboxing"), so we want to use runspaces and host the powershell scripts ourselves.
I was tryint to setup a simple powershell core host with a runspace using these two examples:
https://docs.microsoft.com/en-us/powershell/developer/hosting/creating-a-constrained-runspace
In the second link, a runspace is created and the "Get-Process" Cmdlet should be made available by using
SessionStateCmdletEntry ssce1 = new SessionStateCmdletEntry(
"get-process",
typeof(GetProcessCommand),
null);
However, when I use the first link as base, getting the powershell core sdk using nuget, GetProcessCommand is not known. The reasons seems to be that GetProcessCommand is available in Micrososft.Powershell.Commands.Management, however the nutget Package has a "ref" dll (System.Management.Automation) that does not expose GetProcessCommand.
Is this an oversight or by design, maybe because Get-Process is not available on all platforms? Can we work around this problem by refering to Microsoft.Powershell.Commands.Managment assembly directly or are we going down a dangerous path? If this behaviour is intentional, is there a list on which cmdlets implementatios are platform dependant or not immediately available in the Powershell Core SDK?
We are currently not intending to target anything else but Windows.
1) Use https://github.com/PowerShell/PowerShell/tree/master/docs/host-powershell/sample-dotnet2.0-powershell.beta.3 as base
2) Try to do
SessionStateCmdletEntry ssce1 = new SessionStateCmdletEntry(
"get-process",
typeof(GetProcessCommand),
null);
compiles
does not compile
```powershell
$PSVersionTable
Name Value
---- -----
PSVersion 6.1.0
PSEdition Core
GitCommitId 6.1.0
OS Microsoft Windows 10.0.16299
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0```
@adityapatwardhan Could you please answer or ping anybody?
@PaulHigin Can you help with creating the constrained runspace? Get-Process cmdlet should be available through the SDK.
I accidently closed the issue... sorry
For clarification @adityapatwardhan, @PaulHigin:
The cmdlet is available in pwsh.exe. I can host PSCore and run (Get-Command Get-Process).DLL and get Microsoft.Powershell.Commands.Managment.dll as output. So, thats working.
If I want to create a constrained runspace I need the cmdlets implementation GetCommandCommand which is implemented in \src\Microsoft.PowerShell.Commands.Management\commands\management\Process.cs and gets put in the assembly Microsoft.PowerShell.Commands.Management.dll. When I use and configure the project as suggested in https://github.com/PowerShell/PowerShell/tree/master/docs/host-powershell/sample-dotnet2.0-powershell.beta.3 you do not "link" (? sorry, I'm a C++ guy...) against Microsoft.PowerShell.Commands.Management.dll, but against System.Managment.Automation.dll, which is in the ref folder inside the nuget package. In that assembly, GetCommandCommand is not made available, so I would have to "link" against Microsoft.PowerShell.Commands.Management.dll manually.
Is this intentional and is it actually Ok to do that, as long as I know which OS I am targeting and take care to "link" the correct version. Or should I expect issues because stuff might get (re)moved and I therefore should I only use what is made available in the ref DLLs?
Can't edit my comment. This is how I run the above mentioned Get-Command-Thingy:
using (PowerShell ps = PowerShell.Create())
{
var results = ps.AddScript("(Get-Command Get-Process). DLL").Invoke();
foreach (dynamic result in results)
{
Console.WriteLine(result.ToString());
}
}
Can't edit my comment.
Old browser :-)
Found another example, maybe my selection of Cmdlets is just... "wrong"
Microsoft.PowerShell.Commands.Utility exposes the implementation of Write-Host as WriteHostCommand in the Microsoft.PowerShell.Commands namepsace. It is not available in via System.Management.Automation, which is again the DLL that is referenced when a dependency on Microsoft.PowerShell.Commands.Utility is added via nuget.
Am I doing something wrong? :(
... another one:
Out-File, available in Microsoft.PowerShell.Commands.Utility, not available via System.Management.Automation. Out-Host, on the other hand, is available via System.Management.Automation
Taking a look now ...
@bergersn The SDK has changed a lot from version beta3. Can you try it with Microsoft.PowerShell.SDK version 6.1.0?
Also you might need reference assemblies. Try using package: 'https://www.nuget.org/packages/PowerShellStandard.Library/5.1.0-RC1'
I haven't experimented with hosting PSCore6 and @daxian-dbw is your best source for that.
However, instead of using SessionStateCmdletEntry for creating a sand boxed runspace, I recommend using the PSSession configuration file instead. This is normally used for remote session configuration, but can be used for local runspaces as well.
The configuration file is used to determine how the runspace is configured what cmdlets, functions, aliases, provides, etc are visible.
You can start by looking at a configuration file that contains all configuration options:
New-PSSessionConfigurationFile -Full -Path .\full.pssc
notepad .\full.pssc
You have to ignore the remoting session configuration parts since they do not apply to a local runspace. Here is an example of a text file, TestGP.pssc
@{
# Version number of the schema used for this document
SchemaVersion = '2.0.0.0'
# ID used to uniquely identify this document
GUID = '498aab26-ac10-40fe-9493-380835fa1e43'
# Author of this document
Author = 'paul'
# Language mode to apply when applied to a session. Can be 'NoLanguage' (recommended), 'RestrictedLanguage', 'ConstrainedLanguage', or 'FullLanguage'
LanguageMode = 'FullLanguage'
# Session type defaults to apply for this session configuration. Can be 'RestrictedRemoteServer' (recommended), 'Empty', or 'Default'
SessionType = 'RestrictedRemoteServer'
# Cmdlets to make visible when applied to a session
# VisibleCmdlets = 'Invoke-Cmdlet1', @{ Name = 'Invoke-Cmdlet2'; Parameters = @{ Name = 'Parameter1'; ValidateSet = 'Item1', 'Item2' }, @{ Name = 'Parameter2'; ValidatePattern = 'L*' } }
VisibleCmdlets = 'Get-Process'
# Functions to make visible when applied to a session
# VisibleFunctions = 'Invoke-Function1', @{ Name = 'Invoke-Function2'; Parameters = @{ Name = 'Parameter1'; ValidateSet = 'Item1', 'Item2' }, @{ Name = 'Parameter2'; ValidatePattern = 'L*' } }
# External commands (scripts and applications) to make visible when applied to a session
# VisibleExternalCommands = 'Item1', 'Item2'
# Providers to make visible when applied to a session
VisibleProviders = '*'
}
The SessionType = 'RestrictedRemoteServer' creates a runspace with everything hidden except for 5 basic cmdlets such as Get-Command, Out-Default, Format-Table, etc. Then you have to selectively add what you want to expose in the runspace. I have added a single 'Get-Process' command, but also allow all providers (file, registry, etc.).
You can then create a PowerShell object to invoke commands on (the runspace is created implicitly) as follows (I am using PowerShell here in this example to call the APIs here):
$iss = [initialsessionstate]::CreateFromSessionConfigurationFile('C:\testGP.pssc')
$ps = [powershell]::Create($iss)
$ps.AddCommand('Get-Process').AddParameter('Name', @('pwsh','powershell'))
$ps.Invoke()
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
35 70.31 89.36 103.80 7124 1 powershell
27 74.00 85.36 80.77 14796 1 powershell
32 105.64 125.87 92.20 17320 1 powershell
108 146.61 184.38 15.75 20568 1 pwsh
$ps.Commands.Clear()
$ps.AddCommand('Get-Service').Invoke()
Exception calling "Invoke" with "0" argument(s): "The term 'Get-Service' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again."
At line:1 char:1
+ $ps.AddCommand('Get-Service').Invoke()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : CommandNotFoundException
To see what commands you have available in your sand boxed runspace/powershell you can run the Get-Command command:
$ps.Commands.Clear()
$ps.AddCommand('Get-Command').Invoke()
CommandType Name Version Source
----------- ---- ------- ------
Function Clear-Host
Function Exit-PSSession
Function Get-Command
Function Get-FormatData
Function Get-Help
Function Measure-Object
Function Out-Default
Function Select-Object
Cmdlet Get-Process 6.1.0.0 Microsoft.PowerShell.Management
Thank you @PaulHigin, it seems using a configuration file is a good workaround! I will try that.
I still feel that this is some oversight. Why is, from my point of view, a "basic" command like GetCommandCommand not made available through the System.Management.Automation ref-Assembly?
@adityapatwardhan I am using 6.1.0. The link I provided was just how I gut my initial project.
I will try using the PowerShell Standard package, but... why would I need to do that if I know I am using PowerShell Core and do not need some sort of compatibilty between Windows PowerShell and PowerShell Core
I think @daxian-dbw can help answer the type availability question. Unfortunately he is OOF this week but hopefully can contribute next week.
@bergersn The SDK package only has the reference assembly for System.Management.Automation.dll. By adding the PowerShellStandard.Library package, you should be able to get the type `GetProcessCommand' at compile time. This would prove my hypothesis about the compile time dependency.
If adding PowerShellStandard.Library package works for you, that can be used as a workaround. We might have to add reference assemblies of all DLLs to the SDK package as a real solution.
Thanks again to @PaulHigin @adityapatwardhan !
I wasn't able to try PowerShellStandard.Library. I am behind a very restrictive nuget proxy and I can't download the nuget package :( I'll try to get it some other way and report back :)
I'd be really interested in @daxian-dbw take on this :) I'd keep the issue open until then
@adityapatwardhan
System.Management.Automation.dll from PowerShellStandard.Library nuget package also does not expose GetProcessCommand, WriteHostCommand, OutFileCommand...
cc @JamesWTruher
Is the issue still actual in 7.0 milestone or we can close?