Why does invoking PowerShell from C# throw a System.Management.Automation.CommandNotFoundException? - c#

I'm using this c#:
public bool RunPowershell(string script)
{
RunspaceConfiguration runspaceConfig = RunspaceConfiguration.Create();
using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfig))
{
runspace.Open();
using (RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace))
{
scriptInvoker.Invoke(script);
}
}
return true;
}
To run this script:
Add-PSSnapin -name Microsoft.SystemCenter.VirtualMachineManager
$vmm = Get-VMMServer -ComputerName "VmmComputerName"
It works ok on a Windows 2003 32bit OS, but on a Windows 2008R2 64bit, I get this error:
System.Management.Automation.CommandNotFoundException: The term 'Get-VMMServer' 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.CommandFactory._CreateCommand(String commandName, CommandOrigin commandOrigin, Nullable`1 useLocalScope)
at System.Management.Automation.ExecutionContext.CreateCommand(String command)
at System.Management.Automation.CommandNode.CreateCommandProcessor(Int32& index, ExecutionContext context)
at System.Management.Automation.CommandNode.AddToPipeline(PipelineProcessor pipeline, ExecutionContext context)
at System.Management.Automation.PipelineNode.Execute(Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext context)
at System.Management.Automation.ParseTreeNode.Execute(Array input, Pipe outputPipe, ExecutionContext context)
at System.Management.Automation.AssignmentStatementNode.Execute(Array input, Pipe outputPipe, ExecutionContext context)
at System.Management.Automation.StatementListNode.ExecuteStatement(ParseTreeNode statement, Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext context)
And, I have got Microsoft.SystemCenter.VirtualMachineManager installed. The script also works if I manually type it in to the power-shell console on the 2008R2 machine.
Can you please help on any ideas for what I might be missing?
Thanks very much.

This occurs because powershell snap-in metadata is recorded in the registry. In your case, this means that the snap-in info is only available in the 32 bit software hive in the registry. Normally the trick to make it available is to use the 64 bit version of the .NET framework's installutil.exe (in the framework64 directory) to register it, but sometimes it's 32 bit only for a reason. It may be depending on 32 bit COM objects that are not available in a 64 bit environment.
So you have two approaches:
1) register the snap-in for 64 bit by using installutil.exe /i (unlikely to work)
or
2) target your .NET exe for 32 bit only via VS project properties (anycpu -> x86)
or
3) wrap your work up in a script like this: http://www.nivot.org/blog/post/2012/12/18/Ensuring-a-PowerShell-script-will-always-run-in-a-64-bit-shell
-Oisin

Here's an example that handles named parameters and worked for my needs. Original was taken from the linked option in x0n's post. See the linked post for additional details. I'm executing this script from a C# console application that has 3rd party dependencies on x86.
param([string[]]$listOfVMNames, [string]$userName, [string]$resourceGroupName, [int]$waitForJob)
if ($pshome -like "*syswow64*") {
& (join-path ($pshome -replace "syswow64", "sysnative") powershell.exe) -file `
(join-path $psscriptroot $myinvocation.mycommand) -listOfVMNames (,$listOfVMNames) -userName $userName -resourceGroupName $resourceGroupName -waitForJob $waitForJob
exit
}

Related

powershell on linux docker image

I'm using a linux docker image with powershell and few modules installed on it.
Programmatically, my code do not see the modules.
For verification, if I start the image and instanciate powershell, I can run commands and confirm that the modules are installed:
kubectl run -i --tty test --image=urlofimage:20211008.8 --command pwsh
However, my code do not see the modules.
The extract of code below works in a windows machine, but returns the following error in the docker image:
This parameter set requires WSMan, and no supported WSMan client library was found. WSMan is either not installed or unavailable for this system.
internal const string NewSessionScript = "New-PSSession -ConfigurationName:Microsoft.Exchange -Authentication:Basic -ConnectionUri:{0} -Credential $cred -AllowRedirection";
this._runspace.SetCredential(userName, password);
var command = new PSCommand();
command.AddScript(string.Format(NewSessionScript, connectionUri));
var result = this._runspace.ExecuteCommand<PSSession>(command);
Question:
It looks like the code is instanciating powershell "in memory" but does not use the powershell that is installed on the machine.
How can I use it and leverage an image with all my powershell dependancies installed?

c# Visual Studio 2015 - how to create a Setup which uninstall other application

Initially I created an application that I completely rewrite in a second version. It is a complete different Visual studio solution.
Now I would like that its Setup installer uninstall the previous version but because it was not created using the same solution, the automatic uninstallation of previous version does not work.
Is there any way to force the installer to uninstall certain application based on product name or product code?
I found a WMIC command that works when run from command line
wmic product where name="XXXX" call uninstall /nointeractive
So I created a VBS script which execute a bat file containing the WMIC code and I added it to the Setup project
dim shell
set shell=createobject("wscript.shell")
shell.run "uninstallAll.bat",0,true
set shell=nothing
but when I run the result MSI, it fires an error 1001, meaning that a service already exists. , in other words the uninstallation didn't work.
The old program is still present and they create a service with the same name. :/
any suggestion?
There are 2 options:
You can increase the version of MSI project so it will treat as upgrade and it will not throw any error while installing.
another way out is the write some in the installer project as follows:
protected override void OnBeforeInstall(IDictionary savedState)
{
//Write uninstall powershell script
//installutil /u <yourproject>.exe
using (PowerShell PowerShellInstance = PowerShell.Create())
{
PowerShellInstance.AddScript("");
PowerShellInstance.AddParameter("");
}
PowerShellInstance.Invoke();
}
Note: This InstallUtil is available with the .NET Framework, and its path is %WINDIR%\Microsoft.NET\Framework[64]\<framework_version>.
For example, for the 32-bit version of the .NET Framework 4 or 4.5.*, if your Windows installation directory is C:\Windows, the path is C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe.
For the 64-bit version of the .NET Framework 4 or 4.5.*, the default path is C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe
I decided to go for the option of introducing c# code in the project installer. Firstly I added the reference for System.Management.Automation via nuget
https://www.nuget.org/packages/System.Management.Automation
After this, I just created a string variable containing the PS code I need to uninstall several programs with a similar name.
string unInstallKiosk = #"$app = get-WMIObject win32_Product -Filter ""name like 'KIOSK'""
foreach ($program in $app){
$app2 = Get-WmiObject -Class Win32_Product | Where -Object { $_.IdentifyingNumber -match ""$($program.identifyingNumber)""
}
$app2.Uninstall()}";
and passed this variable to the method PowerShellInstance.AddScript()
PowerShellInstance.AddScript(unInstallKiosk);
The installation ends but the uninstallation simply dont happens.
anyone has an idea how to solve this?

PowerShell script run from C# is lacking several modules

var runspace = RunspaceFactory.CreateRunspace()
runspace.Open();
var ps = PowerShell.Create()
ps.Runspace = runspace;
ps.AddCommand(...);
ps.Invoke()
Some cmdlets that exist in a regular shell are missing from the runtime started by C#, e.g. all the commands from the Microsoft.PowerShell.LocalAccounts module :
Error: System.Management.Automation.CommandNotFoundException: The term 'New-LocalUser' 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.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
By comparing the Get-Module -ListAvailable output from a regular shell and a C# started one I noticed multiple modules are missing :
AppBackgroundTask
AssignedAccess
BitLocker
ConfigCI
Defender
Microsoft.PowerShell.LocalAccounts
MMAgent
NetworkSwitchManager
PcsvDevice
PSWorkflow, PSWorkflowUtility
SmbShare, SmbWitness
StartLayout
WindowsSearch
The version ($PSVersionTable) is reported as the same in both shells : 5.1.14393.693
Edit
Seems to be the same issue & solution : Why do powershell modules not import when running powershell via start process in c#?
You can import modules directly on your script instead of trying to do that from C#.
Import-module bitlocker
For example.

Error while Trying to load Powershell Module "MSOnline" in ASP.NET web app

Good morning I have one problem trying o load a Powershell Module called MSOnline in a ASP.NET
After following this links:
http://www.msdigest.net/2012/03/how-to-connect-to-office-365-with-powershell/
http://blogs.technet.com/b/educloud/archive/2013/01/23/managing-office-365-for-education-using-powershell.aspx
This is a Button that run a script via Code Behind in C#. When I was trying to load the module it threw an exception.
protected void Bexecute_Click(object sender, EventArgs e)
{
// Import-Module MSOnline
try
{
//Loading MSOnline using a InitialSessionState
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new string[] { "MSOnline" });
//Before the solution iss has an exception of "not found" the MSOnline Module
//Create a runspace
Runspace test = RunspaceFactory.CreateRunspace(iss);
//Open a Runspace
test.Open();
//Create a Pipeline
Pipeline pipeLine = test.CreatePipeline();
//Create the StringBuilder to get append the script
StringBuilder script = new StringBuilder();
//Take the script from Tscript (TextBoxt with ID="Tscript" in default.aspx
script.AppendLine(#"Get-Module -ListAvailable");
//Add the script and commands to the pipeline;
pipeLine.Commands.AddScript(script.ToString());
//Execute script and get the PSObject Results collection
Collection<PSObject> resultObjects = pipeLine.Invoke();
//Close the Runspace
test.Close();
if (resultObjects.Count > 0)
{
/*** DO SOMETHING WITH THE PSObjects ***/
}
}
catch (System.Management.Automation.RuntimeException ex)
{
status.AppendLine(ex.Message);
}
}
What I need is what could be wrong. I referenced the system.management.automation (dll). But I don't have a clue why is not listed if it's installed it. Thank you for the help.
I have found MSOnline .dll files in : C:\windows\system32\WindowsPowerShell\v1.0\Modules\MSOnline
But If I tried to add manually from visual studio it says "that MSOnline doesn't exist".
This is quite weird, because all have same permissions to folder. What's going on! :S This is so frustrating...
To get ASP.NET web app run under x64 bit architecture you should do this:
1, MS Online Services Assistant needs to be downloaded and installed
Microsoft Online Services Sign-In Assistant – 64 bit version http://go.microsoft.com/fwlink/?linkid=236300
2.MS Online Module for PowerShell needs to be downloaded and installed
Microsoft Online Services Module for Windows PowerShell (64-bit version) http://go.microsoft.com/fwlink/?linkid=236297
After this step you can run: get-module -ListAvailable and the Module MSOnline will be listed.
But it is still not working on 64 bits SOs. the original poster used win8 64bits and I am using win 8.1 64 bits and it works as well.
Copy the MSOnline module folder from (Path1) to (Path2) where
(Path1) -> "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\MSOnline" and
(Path2) -> "C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules\MSOnline"
Considering I'm running this on VS2013 under Windows 8.1 and 64 bits arquitecture.
After doing this the MSOnline Module is listed in the Get-Module -ListAvailable (from webapp, not just for powershell)), so I could import it and use it.

.ps1 cannot be loaded because the execution of scripts is disabled on this system

I run this code to execute PowerShell code from an ASP.NET application:
System.Management.Automation.Runspaces.Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
runspace.Open();
System.Management.Automation.Runspaces.Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(#"\\servername\path");
pipeline.Commands.Add("Out-String");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
But I am getting an error:
.ps1 cannot be loaded because the execution of scripts is disabled on
this system. Please see "get-help about_signing" for more details.
The same code runs fine from a command prompt or a windows (Windows Forms) application.
Your script is blocked from executing due to the execution policy.
You need to run PowerShell as administrator and set it on the client PC to Unrestricted. You can do that by calling Invoke with:
Set-ExecutionPolicy Unrestricted
There are certain scenarios in which you can follow the steps suggested in the other answers, verify that Execution Policy is set correctly, and still have your scripts fail. If this happens to you, you are probably on a 64-bit machine with both 32-bit and 64-bit versions of PowerShell, and the failure is happening on the version that doesn't have Execution Policy set. The setting does not apply to both versions, so you have to explicitly set it twice.
Look in your Windows directory for System32 and SysWOW64.
Repeat these steps for each directory:
Navigate to WindowsPowerShell\v1.0 and launch powershell.exe
Check the current setting for ExecutionPolicy:
Get-ExecutionPolicy -List
Set the ExecutionPolicy for the level and scope you want, for example:
Set-ExecutionPolicy -Scope LocalMachine Unrestricted
Note that you may need to run PowerShell as administrator depending on the scope you are trying to set the policy for.
The problem is that the execution policy is set on a per user basis. You'll need to run the following command in your application every time you run it to enable it to work:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned
There probably is a way to set this for the ASP.NET user as well, but this way means that you're not opening up your whole system, just your application.
(Source)
You need to run Set-ExecutionPolicy:
Set-ExecutionPolicy Unrestricted <-- Will allow unsigned PowerShell scripts to run.
Set-ExecutionPolicy Restricted <-- Will not allow unsigned PowerShell scripts to run.
Set-ExecutionPolicy RemoteSigned <-- Will allow only remotely signed PowerShell scripts to run.
I had a similar issue and noted that the default cmd on Windows Server 2012 was running the x64 one.
For Windows 7, Windows 8, Windows Server 2008 R2 or Windows Server 2012, run the following commands as Administrator:
x86
Open C:\Windows\SysWOW64\cmd.exe
Run the command: powershell Set-ExecutionPolicy RemoteSigned
x64
Open C:\Windows\system32\cmd.exe
Run the command powershell Set-ExecutionPolicy RemoteSigned
You can check mode using
In CMD: echo %PROCESSOR_ARCHITECTURE%
In Powershell: [Environment]::Is64BitProcess
I hope this helps you.
Try This:
Set-ExecutionPolicy -scope CurrentUser Unrestricted
If you faced this error while running json-server and landed here on this page.
one alternate solution is to run it using npx directly without installing it.
npx json-server --watch db.json

Categories