Import-Module won't work when launched from .net - c#

I'm trying to run a powershell script within my C# web application.
When i run the following in powershell, it works fine.
Import-Module 'C:\\Program Files\\Microsoft Dynamics NAV\\80\\Service\\NavAdminTool.ps1'
Get-NAVTenant -ServerInstance DynamicsHost
But when i'm running it using my web application, it tells me
The term 'Get-NAVTenant -ServerInstance DynamicsHost' 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.
Here is my c# code:
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { "C:\\Program Files\\Microsoft Dynamics NAV\\80\\Service\\NavAdminTool.ps1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.Commands.AddCommand("Get-NAVTenant -ServerInstance DynamicsHost");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(result.ToString());
}
Can someone point me in the right direction??
UPDATE:
Using runspace.SessionStateProxy.PSVariable.GetValue("Error") i could see the following error:
Cannot bind argument to parameter 'Name' because it is null.
Cannot bind argument to parameter 'Path' because it is null.
Cannot find path 'HKLM:\SOFTWARE\Microsoft\Microsoft Dynamics NAV\80\Service' because it does not exist.
A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.
A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.
A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.

The error message suggests that your entire command string is interpreted as the name of a (non-existent) cmdlet. According to the documentation the AddCommand() method expects the name of a cmdlet, while parameters should be added via AddParameter().
Try changing this:
ps.Commands.AddCommand("Get-NAVTenant -ServerInstance DynamicsHost");
into this:
ps.Commands.AddCommand("Get-NAVTenant");
ps.Commands.AddParameter("-ServerInstance", "DynamicsHost");
or this:
ps.AddCommand("Get-NAVTenant");
ps.AddParameter("-ServerInstance", "DynamicsHost");

I can verify the following code works, posted from above: the following code will return the DatabaseServer name of the specified Dynamics NAV service tier
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { "C:\\Program Files\\Microsoft Dynamics NAV\\80\\Service\\NavAdminTool.ps1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.Commands.AddCommand("Get-NAVTenant");
ps.Commands.AddParameter("-ServerInstance", "objectupgrade");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(result.Properties["DatabaseServer"].Value);
}
Console.Read();
Console.ReadKey();
A better and a much quicker method is to use the Microsoft.Dynamics.Nav.Management snap-in directly. Significant performance improvement can be seen by using this method. Please see following code found here: Why does PowerShell class not load a snapin
var config = RunspaceConfiguration.Create();
PSSnapInException warning;
config.AddPSSnapIn("Microsoft.Dynamics.Nav.Management", out warning);
using (Runspace runspace = RunspaceFactory.CreateRunspace(config))
{
runspace.Open();
using (var ps = PowerShell.Create())
{
ps.Runspace = runspace;
ps.AddCommand("Get-NAVTenant");
ps.AddParameter("ServerInstance", "ObjectUpgrade");
Collection<PSObject> results = ps.Invoke();
foreach (PSObject obj in results)
{
Console.WriteLine(obj.Properties["DatabaseServer"].Value);
}
Console.Read();
Console.ReadKey();
}
}

It turned out to be that the developer web server could't handle the request. Switching to IIS as developer server solved the problem. Now both of watto's examples works.

Related

Importing Az Powershell module in .NET

I'm trying to use PowerShell from C#. I want to import the Az.Compute module to use cmdlets, but it's not working.
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Bypass;
Console.WriteLine(iss.ExecutionPolicy);
//iss.ImportPSModule(new string[] { "Az.Compute" });
iss.ImportPSModulesFromPath(#"C:\Program Files\WindowsPowerShell\Modules\Az.Compute");
Runspace runspace = RunspaceFactory.CreateRunspace(iss);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
Collection<PSObject> servers = ps
.AddCommand("Get-AzVM")
.Invoke();
First I needed to bypass the execution policy to be able to import module. I'm using ImportPSModule method from the InitialSessionSate class. When I'm running this code I get an exception at Get-AzVM: System.Management.Automation.CommandNotFoundException: 'The 'Get-AzVM' command was found in the module 'Az.Compute', but the module could not be loaded. For more information, run 'Import-Module Az.Compute'.'
If I run Get-InstalledModule in the developer powershell the module is there. I'v tried by importing the module from path, but still get the exception when trying to use cmdlets from the module.
The above error is due to the Az.Compute module was not loaded properly.
You can try the below workarounds to let the Get-AzVM cmdlet work and also the module to get loaded correctly:
Install-Module -Name Az -AllowClobber -Scope CurrentUser after running this cmdlet, restart the Powershell and then run again this import-module az.compute cmd.
Also you can check the logs of PowerShellCore/Operational from Event viewer, if any errors are found then update the packages to the latest versions.

Why does powershell not recognize cmdlets in a script called by a windows service?

We have a windows service which runs as the local system account. It calls a PowerShell script and retrieves the output for further processing. It works like a charm under windows server 2016 but now needs to be moved to a windows server 2012 R2. On this machine, it does not recognize the azure specific cmdlets.
I tried to install the specific cmdlets via -Scope AllUsers. We also logged into the PowerShell directly as local system-user; it does recognize the cmdlets (e.g. Add-AzureRMAccount) correctly.
C#:
PowerShell psInstance = PowerShell.Create();
psInstance.AddScript(scriptBase + "getVMs.ps1");
var azureVMList = psInstance.Invoke();
getVMs.ps1:
$finalPassword = ConvertTo-SecureString -String $password -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential -ArgumentList $accountName, $finalPassword
$trash = Add-AzureRmAccount -Credential $psCred -TenantId $tenantID -ServicePrincipal`
We don't understand why the cmdlets are working fine under the same circumstances on server 2016 and if we run them directly as the user.
Any hint is appreciated
I suggest a workaround here, in your c# code, directly import the module which contains the cmdlet.
1.you can use this command to get the module file(I'm using az module, feel free to change to azureRm module):
(Get-Module -Name az.accounts).Path
then you can see the module file path, in my side, it's "C:\Program Files\WindowsPowerShell\Modules\Az.Accounts\1.5.2\Az.Accounts".
2.in your c# code:
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] {"the full path of Az.Accounts.psd1, if it does not work, try full path of Az.Accounts.psm1"} );
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(scriptBase + "getVMs.ps1");
var azureVMList = psInstance.Invoke();

Set-Execution Policy from process

I'm doing a VSTO add in for Outlook in C# that calls PowerShell scripts to interact with the Exchange Online of Office 365.
It all works perfectly on my windows 10 machine with a machine level unrestricted PowerShell execution policy. However, I can't get this to run on the client's Windows 7 machine.
I think there are two issues. One that possibly his windows 7 PowerShell needs to be updated to work with my code, and second that I'm not properly setting the process execution policy. Here was my best effort to get the execution policy set to unrestricted (would bypass be better?).
using (PowerShell PowerShellInstance = PowerShell.Create())
{
StringBuilder OSScript = new StringBuilder("Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted;");
OSScript.Append(#"other really exciting stuff");
PowerShellInstance.AddScript(OSScript.ToString());
PowerShellInstance.Invoke();
}
Could someone point me the right direction? I know this doesn't work, as if I set the machine policy to restricted the other really exciting stuff doesn't happen, but if I set it to unrestricted then everything works.
I just created a new Console project and added this to Main:
using (PowerShell PowerShellInstance = PowerShell.Create())
{
string script = "Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted; Get-ExecutionPolicy"; // the second command to know the ExecutionPolicy level
PowerShellInstance.AddScript(script);
var someResult = PowerShellInstance.Invoke();
someResult.ToList().ForEach(c => Console.WriteLine(c.ToString()));
Console.ReadLine();
}
This works perfectly for me, even without running the code as administrator. I'm using Visual Studio 2015 in Windows 10 with Powershell 5.
Set-ExecutionPolicy works in the same way in Powershell 4 and 5, according to the Powershell 4.0 Set-ExecutionPolicy and the Powershell 5.0 Set-ExecutionPolicy.
Trying to do this using reflection.
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Reflection;
using Microsoft.PowerShell;
...
InitialSessionState iss = InitialSessionState.CreateDefault();
// Override ExecutionPolicy
PropertyInfo execPolProp = iss.GetType().GetProperty(#"ExecutionPolicy");
if (execPolProp != null && execPolProp.CanWrite)
{
execPolProp.SetValue(iss, ExecutionPolicy.Bypass, null);
}
Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();
Please note: There are 5 levels (scope) of ExecutionPolicy in PowerShell (see about_execution_policies). This will set Process's ExecutionPolicy. This means if that ExecutionPolicy was defined with Group policy or Local policy ( UserPolicy or MachinePolicy ), this will not override ExecutionPolicy.
Check Get-ExecutionPolicy -List to see list of ExecutionPolicies defined in different scopes for your current process.

C# cannot load powershell snapin despite being registered

I am trying to use a custom snapin for powershell in my C# program. (The C# program is a modified version this)
I'm using the standard approach to setup the runspace:
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
If I run this as is and scriptText contains the command "Get-PSSnapin" my snapin is missing. If I run "Get-PSSnapin -Registered" then I can see my snapin. If I use Add-PSSnapin, then it returns nothing and followup commands that I issue (which are implemented in the snapin will return):
...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
So, I amended my code to add the cmdlet to the runconfig:
RunspaceConfiguration runConfig = RunspaceConfiguration.Create();
PSSnapInException psEx = null;
runConfig.AddPSSnapIn("mySnapin", out psEx);
Runspace runspace = RunspaceFactory.CreateRunspace(runConfig);
Now, when I run it, I get:
error in script : Cannot invoke this function because the current host
does not implement it.
I tried both the x86 and 64 version. The snapin gets installed in the x86 programs so I did this by compiling for x86. If I do the 64 version, I get:
"Error in script : The Windows PowerShell snap-in 'mySnapin' is not
installed on this machine".
Confirming that this is specific to x86.
I also tried loading this as a module (desperation), but it doesn't work that way either. When I run:
get-command <command in mySnapin> | select Module, PsSnapin
The output doesn't have a module, just the snapin, hence it was silly to begin with.
I should note that this is installed by another program and I have no control over where it is install. I thought that might be a factor, but since it shows up with -Register I think it is finding without issue.
Edit:
I also tried import-module <path to dll>. This doesn't output anything and subsequent calls to functions in my snapin yield:
error in script : Cannot invoke this function because the current
host does not implement it.
Then again in C# since I wasn't clear on whether the import will be preserved across calls.
pipeline.Commands.Add("Import-Module");
var command = pipeline.Commands[0];
command.Parameters.Add("Name", #"<path to my snapin .dll>");
Any help getting this rolling would be greatly appreciated. Thank you!

The term 'Get-CsUser' is not recognized as the name of a cmdlet, function, script file, or operable program

I am getting below exception if run lync powershell command "Get-CsUser". I am running application with administrator and on machine which have lync powershell.
System.Management.Automation.CommandNotFoundException: The term
'Get-CsUser' 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
System.Management.Automation.CommandDiscovery.LookupCommandInfo(String
commandName, CommandOrigin commandOrigin) at
System.Management.Automation.CommandDiscovery.LookupCommandProcessor(String
commandName, CommandOrigin commandOrigin, Nullable`1 useLocalScope)
at
System.Management.Automation.Runspaces.Command.CreateCommandProcessor(ExecutionContext
executionContext, CommandFactory commandFactory, Boolean addToHistory)
at
System.Management.Automation.Runspaces.LocalPipeline.CreatePipelineProcessor()
at System.Management.Automation.Runspaces.LocalPipeline.InvokeHelper()
at
System.Management.Automation.Runspaces.LocalPipeline.InvokeThreadProc()
sample code:
using (Runspace runspace = RunspaceFactory.CreateRunspace(initial))
{
//// open it
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = runspace;
ps.AddScript("import-module 'C:\\Program Files\\Common Files\\Microsoft
ps.AddCommand("Get-CsUser");
Collection<PSObject> results = ps.Invoke();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
runspace.Close();
}
}
any suggestion to fix this ???
I don't have an answer, but there is a series of 4 articles that describe using Lync powershell cmdlets and C#. For example, here's a link to one of the articles:
PowerShell Scripting Lync 2010 SDK Using Lync Model API
The full set of four articles is published here:
Lync 2010 Technical Articles

Categories

Resources