I am trying to call the specific cmdlet "Get-VpnConnection" from a PowerShell instance in a Windows service (.NET Framework 4.7).
I have been able to call this cmdlet successfully in a command-line project (also .NET Framework 4.7) and have been able to call other cmdlets from within this service (e.g. "Get-Date"). I have selected the highest account permissions for the package installer (LocalSystem).
Here is an excerpt of what I've tried:
using (PowerShell ps = PowerShell.Create())
{
ps.AddCommand("Get-VpnConnection");
Collection<PSObject> results = ps.Invoke();
WriteToFile(results.Count.ToString());
}
When I run this from within the service, WriteToFile (a method I've created to write to a log text file in the program's base directory) will write "0" to the log whereas for "Get-Date" it would write "1". When I run this from within the main function of a command-line project, I get "1" as expected. No exceptions are thrown and no PowerShell Stream (Error or Verbose) contains anything. It's almost as if the cmdlet isn't being recognized as valid since providing a gibberish argument to AddCommand will produce an identical result.
Thank you for you time.
Related
I am trying to run one of the feature of Windows Subsystem for Linux (WSL) via PowerShell in C# code. Even though, there is no error, I cannot see the result. In order to fix it, I have read and implemented some suggestion in other stackoverflow questions but still i cannot see the result. Another question is that is it possible to pass argument for following code. In MS website, there is no example regarding passing argument. I hope there is a way to do it.
Code is here:
PowerShell ps = PowerShell.Create();
ps.AddScript(File.ReadAllText(#"C:\Users\username\Desktop\test.ps1"));
ps.Invoke();
The output of the Debug is :
The thread 0x4034 has exited with code 0 (0x0).
The thread 0x4b34 has exited with code 0 (0x0).
The thread 0x4f0 has exited with code 0 (0x0).
The program '[18876] WSL_CS.exe' has exited with code 0 (0x0).
But command prompt opened and closed very quickly.
In PowerShell, when I run the following code I can see the result.
powershell -ExecutionPolicy Bypass -File test.ps1 5
If you want to launch a visible console window that executes a script file and stays open (enters an interactive session after the script exits):
Do NOT use the PowerShell SDK and its PowerShell .NET class: Its purpose is programmatic control of PowerShell commands, not visible, interactive execution.
Instead, use the general-purpose Process class to create a child process that launches the PowerShell CLI in a visible console window (by default):
System.Diagnostics.Process.Start(
"powershell.exe", // The Windows PowerShell CLI
#"-ExecutionPolicy Bypass -NoExit -NoLogo -File C:\Users\username\Desktop\test.ps1 5"
).WaitForExit();
Note how the argument(s) to pass to the script file are specified after the script-file path (5 in this example) - be sure to double-quote them as needed, such as when they contain embedded spaces.
Since everything after a -File (-f) is interpreted as the script-file path and the arguments to pass to the script, be sure to place these arguments last on the command line.
Alternatively, if you're creating a .NET Core / .NET 5+ application, you may specify all arguments individually, in which case .NET takes care of any required double-quoting for you:
System.Diagnostics.Process.Start(
"powershell.exe", // The Windows PowerShell CLI
new string[] {
"-ExecutionPolicy",
"Bypass",
"-NoExit",
"-NoLogo",
"-File",
#"C:\Users\jdoe\Desktop\pg\pg.ps1",
"5" // Pass-through arguments.
}
).WaitForExit();
Pitfall:
-NoExit is not honored if the script file passed to -File cannot be found.
This contrasts with passing a piece of PowerShell source code to the -Command (-c) parameter, where -NoExit is honored, even if execution of the source code results in errors).
This discrepancy is arguably a bug and has been reported in GitHub issue #10471.
The upshot is that if you launch the process not from an existing console window, a console window is created on demand, which automatically closes shortly after, namely after PowerShell has reported the error due to not finding the specified script file, making it all but impossible to see what happened.
The workaround is to use the -Command parameter instead, which keeps the window open unconditionally:
// Again, passing arguments individually is an option in .NET Core / .NET 5+
System.Diagnostics.Process.Start(
"powershell.exe", // The Windows PowerShell CLI
#"-ExecutionPolicy Bypass -NoExit -NoLogo -Command & C:\Users\username\Desktop\test.ps1 5"
).WaitForExit();
Note the use of &, the call operator, to invoke the script (which isn't strictly necessary in this case, but generally is if the script-file path is quoted and/or contains variable references).
Also note that using -Command changes how the pass-through arguments are interpreted, which may or may not cause problems (not with a simple argument such as 5); in short: after command-line parsing, during which syntactic (unescaped) " chars. are stripped, PowerShell then interprets the resulting arguments as PowerShell source code, subjecting them to an additional layer of interpretation - see this answer for more information.
I'm trying to invoke a Powershell Command Get-DSCLocalConfigurationManager from a windows service project (.net framework 2.0). using System.Management.Automation
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
try
{
runspace.Open();
var ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddCommand("Get-DSCLocalConfigurationManager");
var results = ps.Invoke();
foreach (PSObject result in ps.Invoke())
{
_eventLog.WriteEntry(result.Members["AgentId"].Value.ToString());
}
}
catch (Exception e)
{
_eventLog.WriteEntry($"Powershell Command failed with: {e.Message}", EventLogEntryType.Error);
}
}
Invoking the command in a powershell window works as expected.
The problem is that pretty much every command i try to invoke this way returns an exception:
"The term 'Get-DSCLocalConfigurationManager' is not recognized as the name of a cmdlet,..."
I tried the commands Get-Module -ListAvailable $PSVersionTable.PSVersion with the same result. There are commands that work like Get-Process, so i assume there are missing modules.
Importing the module and invoking the command like this
ps.AddScript(#"Import -Module 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1'; Get-DSCLocalConfigurationManager");
also doesn't work as it returns the following error:
The 'C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1' module cannot be imported because its manifest contains one or more members that are not valid. The valid manifest members are ('ModuleToProcess', 'NestedModules', 'GUID', 'Author', 'CompanyName', 'Copyright', 'ModuleVersion', 'Description', 'PowerShellVersion', 'PowerShellHostName', 'PowerShellHostVersion', 'CLRVersion', 'DotNetFrameworkVersion', 'ProcessorArchitecture', 'RequiredModules', 'TypesToProcess', 'FormatsToProcess', 'ScriptsToProcess', 'PrivateData', 'RequiredAssemblies', 'ModuleList', 'FileList', 'FunctionsToExport', 'VariablesToExport', 'AliasesToExport', 'CmdletsToExport'). Remove the members that are not valid ('DscResourcesToExport', 'HelpInfoURI'), then try to import the module again.
What Powershell version is used when invoking commands like this? Is it tied to the .net framework version I'm using or is it the installed version of the system? What Modules are loaded? What can i do to invoke this command?
Edit: I created a simple console application and found out, that this is connected with the framework version. With .net framework 4.0 this works as expected, but as soon as i use 3.5 or lower the problem i describe arises.
I had same problem.
It comes from version of Powershell.
When you target project to .Net 2.0/3.5 you using System.Management.Automation.dll version 1.0.0.0, that runs Powershell 2.0, but when your project targets to .Net 4+, using dll version 3.0.0.0 and runs Powershell 3.0.
I pass to my runtime Powershell command to call shell Powershell and execute command, like this:
var results = powerShell.AddScript("powershell Get-AppxPackage -allusers -name 'Microsoft.WindowsStore'").Invoke();
if (powerShell.Streams.Error.Any())
{
foreach (var errorRecord in powerShell.Streams.Error)
throw new Exception();
}
Called Ppowershell redirects streams to runtime Powershell.
I'm calling a powershell script from my C# application using:
System.Diagnostics.Process.Start("powershell.exe", " -executionpolicy unrestricted -file myscript.ps1");
Within this script is a call to Java (which relies on the CLASSPATH & PATH system variables). This is where the script fails and reports that:
java is not recognized as an internal command or external command
I believe this is because the system variables for PATH are not being used when I'm executing Powershell from C#. Any help ?
FYI, if I open Powershell manually and run the command it works correctly.
I am using Microsoft PowerShell v4:
PS C:\> get-host
Name : ConsoleHost
Version : 4.0
InstanceId : 3b4b6b8d-70ec-46dd-942a-bfecf5fb6f31
UI : System.Management.Automation.Internal.Host.InternalHostUserInterface
CurrentCulture : de-CH
CurrentUICulture : en-US
PrivateData : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
IsRunspacePushed : False
Runspace : System.Management.Automation.Runspaces.LocalRunspace
I have developed a C# project in Visual Studio 2012 targeting .NET Framework 4 which contains some Cmdlet and the Snapin. I can debug them and everything works just fine.
I've created the path C:\PowerShell\Modules\ and added it to the PSModulePath environment variable.
I put the rMySnapIn.dll to the path C:\PowerShell\Modules\MySnapIn.
I would expect that the module is automatically loaded so I have my new cmdlets ready to use, but they're not: the module is not loaded. I have to write Import-Module MySnapin in order to get it loaded.
How can I get the module automatically loaded?
A checklist that may help you identify the issue:
According to What's New in Windows PowerShell, "Automatic importing of modules is triggered by (a) using the cmdlet in a command, (b) running Get-Command for a cmdlet without wildcards, or (C) running Get-Help for a cmdlet without wildcards." (That applies to V3 and V4.) How did you confirm the module was not loaded?
According to about_Modules, "Only modules that are stored in the location specified by the PSModulePath environment variable are automatically imported." You stated that you did add your path to PSModulePath. When I examine mine, I see that each path included is terminated with a backslash, so in your case you would need C:\PowerShell\Modules\ rather than just C:\PowerShell\Modules. What is the value of your $env:PsModulePath ?
According to this post from Thomas Lee as well as my own experience, autoloading does not work with script modules; however, you state you are using a compiled module, so this should not be your issue.
The $PSModuleAutoLoadingPreference preference variable can be used to turn off autoloading; however, unless you have explicitly changed it, it defaults to All so likely that is not the problem (about_Preference_Variables shows you the possible values). What is your value of $PSModuleAutoLoadingPreference ?
Last but not least--I am particularly suspicious over the fact that you seem to be mixing snapins and modules. They are distinct types of entities, and are not designed to be mixed. Snapins are loaded via Add-PSSnapin. Modules are loaded via Import-Module. And modules, as you know, are also loaded by auto-loading--I suspect that may not be true of code written as a snapin. Furthermore, snapins are deprecated; new code should be written using modules (that is, derive from Cmdlet or PSCmdlet, as detailed in Writing a Windows PowerShell Cmdlet).
If you want to load it automatically you can add the Import-Module MySnapin command line to your PowerShell profile.
To find out the location of your PowerShell profile just type $profile in a PowerShell and by default the profile path is:
C:\Documents and Settings\User\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
If the Microsoft.PowerShell_profile.ps1 file does not exist just create it.
I noticed that following structure is not supported by PowerShell 4:
Modules\MySnapIn\1.0.0\MySnapIn.psm1
Works fine after update to version 5.
Note: I'm authoring only script modules, so I may be wrong.
PowerShell module autoload depends on command discovery. I suspect that if you create manifest (New-ModuleManifest) and name commands that your binary module exposes, autoloading should kick-in and load module if someone will try to use one of these commands:
New-ModuleManifest -Path MySnappin.psd1 -RootModule MySnappin.dll -CmdletsToExport Get-Foo, Set-Bar
Can someone, please, help to understand why the following code inside a Csharp function
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipe = runspace.CreatePipeline();
Command connectToActDir = new Command("connect-QADService");
connectToActDir.Parameters.Add("Service", "'ip:port'");
connectToActDir.Parameters.Add("ConnectionAccount", "'user.local\administrator'");
connectToActDir.Parameters.Add("ConnectionPassword", "'password'");
pipe.Commands.Add(connectToActDir);
pipe.Invoke();
causes the following error
The term 'connect-QADService' 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.
while ActiveRoles cmdlets are installed and running the equivalent command in power shell succeeds. Do I miss some dll in project references?
Thanks
The Quest ActiveRoles cmdlets are not loaded into a PowerShell session by default, because they're not part of PowerShell.
PowerShell 3 will automatically load modules when needed. I don't know if this holds true when using a RunSpace as I've never used PowerShell this way.
Do you load the Quest snap-in or module in your PowerShell profile? You'll need to do the equivalent in your C# code.