Cannot run remote Powershell command in .NET Core: no supported WSMan client library was found - c#

I am trying to execute a remote command in .NET Core using Powershell. This is how I am trying to connect to Powershell:
var username = "dwaldkjesfcdw";
SecureString password = new SecureString();
string pwd = "fsdfdsdsfvds"; /* Not Secure! */
pwd.ToCharArray().ToList().ForEach(password.AppendChar);
/* and now : seal the deal */
password.MakeReadOnly();
var credentials = new PSCredential(username, password);
var remoteComputer = new Uri(String.Format("{0}://{1}:3311/wsman", "HTTP", "11.11.111.111"));
var connection = new WSManConnectionInfo(remoteComputer, null, credentials);
var runspace = RunspaceFactory.CreateRunspace(connection);
runspace.Open();
var powershell = PowerShell.Create();
powershell.Runspace = runspace;
powershell.AddScript("$env:ComputerName");
var result = powershell.Invoke();
However, this line...
var runspace = RunspaceFactory.CreateRunspace(connection);
...throws this exception...
System.Management.Automation.Remoting.PSRemotingTransportException: This parameter set requires WSMan, and no supported WSMan client library was found. WSMan is either not installed or unavailable for this system. ---> System.DllNotFoundException: Unable to load shared library 'libpsrpclient' or one of its dependencies. In order to help diagnose loading problems, consider setting the DYLD_PRINT_LIBRARIES environment variable: dlopen(liblibpsrpclient, 1): image not found
at System.Management.Automation.Remoting.Client.WSManNativeApi.WSManInitialize(Int32 flags, IntPtr& wsManAPIHandle)
at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager.WSManAPIDataCommon..ctor()
--- End of inner exception stack trace ---
at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager.WSManAPIDataCommon..ctor()
at System.Management.Automation.Remoting.Client.WSManClientSessionTransportManager..ctor(Guid runspacePoolInstanceId, WSManConnectionInfo connectionInfo, PSRemotingCryptoHelper cryptoHelper, String sessionName)
at System.Management.Automation.Runspaces.WSManConnectionInfo.CreateClientSessionTransportManager(Guid instanceId, String sessionName, PSRemotingCryptoHelper cryptoHelper)
at System.Management.Automation.Remoting.ClientRemoteSessionDSHandlerImpl..ctor(ClientRemoteSession session, PSRemotingCryptoHelper cryptoHelper, RunspaceConnectionInfo connectionInfo, URIDirectionReported uriRedirectionHandler)
at System.Management.Automation.Remoting.ClientRemoteSessionImpl..ctor(RemoteRunspacePoolInternal rsPool, URIDirectionReported uriRedirectionHandler)
at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler.CreateClientRemoteSession(RemoteRunspacePoolInternal rsPoolInternal)
at System.Management.Automation.Internal.ClientRunspacePoolDataStructureHandler..ctor(RemoteRunspacePoolInternal clientRunspacePool, TypeTable typeTable)
at System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal.CreateDSHandler(TypeTable typeTable)
at System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo, String name)
at System.Management.Automation.Runspaces.RunspacePool..ctor(Int32 minRunspaces, Int32 maxRunspaces, TypeTable typeTable, PSHost host, PSPrimitiveDictionary applicationArguments, RunspaceConnectionInfo connectionInfo, String name)
at System.Management.Automation.RemoteRunspace..ctor(TypeTable typeTable, RunspaceConnectionInfo connectionInfo, PSHost host, PSPrimitiveDictionary applicationArguments, String name, Int32 id)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable, PSPrimitiveDictionary applicationArguments, String name)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo, PSHost host, TypeTable typeTable)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(PSHost host, RunspaceConnectionInfo connectionInfo)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(RunspaceConnectionInfo connectionInfo)
at Services.Services.CalculationService.ProcessCalculations(Int32 clientId, Int32 calculationId) in /Users/Services/CalculationService.cs:line 90
Here is my .csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.PowerShell.Commands.Diagnostics" Version="6.1.1" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="6.1.1" />
<PackageReference Include="Microsoft.WSMan.Management" Version="6.1.1" />
<PackageReference Include="System.Management.Automation" Version="6.1.1" />
<PackageReference Include="WindowsAzure.Storage" Version="8.1.4" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
</Project>
I am running on macOS but the app will run on Azure.
Is the problem with the version of nuget packages? I can't find what I am missing. Or is the problem on the remote computer?

This was occurring for me with .NET Core 3.1 on Fedora 33. Not sure if there is a package that provides this, and I'm not sure if it applies to macOS either, but I found that the exception is correct in my case. It cannot find some shared libraries related to the PowerShell Remoting Protocol (PSRP) client.
I had already installed PowerShell 7.0.3, and made sure that I could actually remote using WS Management. At first, it seemed that I needed to install the PSRP server and the Open Management Infrastructure (OMI) library. However, that didn't resolve the issue.
Poking around some old GitHub issues on the PowerShell repo, I got some clues that the runtime either couldn't find the libpsrpclient shared library object or one of its dependencies. I discovered that these shared libraries existed in the PowerShell installation location, which would explain why PowerShell itself had no problem remoting:
libpsrpclient.so - presumably the client library itself
libmi.so - a dependency library for omi
libssl.so.1.0.0 - a symlink to /lib64/libssl.so.10 (which is itself a symlink to /lib64/libssl.so.1.0.2o on Fedora 33)
libcrypto.so.1.0.0 - a symlink to /lib64/libcrypto.so.10 (which again is itself a symlink to /lib64/libcrypto.so.1.0.2o)
Anyway, here's the workaround on Linux:
Navigate to your PowerShell directory
cd /opt/microsoft/powershell/7
Copy (or symlink) the shared libraries to a location in your shared library path (like /usr/lib):
sudo cp libpsrpclient.so libmi.so libssl.so.1.0.0 libcrypto.so.1.0.0 /usr/lib
Relink/cache shared library:
sudo ldconfig -n -v /usr/lib
Edit: On Fedora Linux 36 with PowerShell 7.2.5, I had to use a forked version of Microsoft's OMI. For some reason, the libraries that came with it don't work anymore, perhaps because they depend upon OpenSSL 1.0, which doesn't ship with Fedora Linux anymore?
Initiate an elevated PowerShell session:
sudo pwsh
Install the PSWSMan module (this is a forked version of Microsoft OMI):
Install-Module PSWSMan
Let the module copy the correct libraries into your PowerShell directory:
Install-WSMan
Proceed with previous steps (except you won't copy the libssl and libcrypto libraries, because this forked version is compiled against OpenSSL 1.1 instead)

Related

How create Windows Service from VS 2022 created gRPC server?

I've created a gRPC server in Visual Studio 2022 Community Preview by selecting the "ASP NET Core gRPC Service" template and .Net 6 Core. I intend to replace four existing .Net Framework Windows services who are all using WCF. So, I'm not looking for an alternative on how to create a Windows service.
The code generated from VS 2022 creates a program.cs (sans comments) that looks like:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddGrpc();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
app.Run();
Every example I can find does not match this program.cs's contents. Additionally, all the examples include a generated startup.cs file. My project did not create a startup.cs file. All the examples show including the NuGet package Microsoft.Extensions.Hosting.WindowsServices and adding a UseWindowsServices parameter.
Host.CreateDefaultBuilder(args)
.UseWindowsService()
...
I don't have a Host or a CreateDefaultBuilder method. I tried adding the line:
builder.Host.UseWindowsService();
The program compiles and works perfectly when running in VS or the command line. I can see the ports with netstat:
netstat -an | find "6276"
C:\Users\Steve>netstat -an | find "6276"
TCP 127.0.0.1:6276 0.0.0.0:0 LISTENING
TCP [::1]:6276 [::]:0 LISTENING
But when I run it as a Windows Service, it is not listening on the identified port.
netstat -an | find "6276"
C:\Users\Steve>
I tried .Net 6.0 and .Net 7.0 preview 7, checking and unchecking "Do not use top level statements" on the later. No change in the behavior.
So, apparently Visual Studio changed the template output for gRPC and nobody has created a Windows Service with it yet... or at least has not shown how it was done.
Does anyone know how to take the latest gRPC template and create a Windows Service from it?
Here is an example of the minimal application created by the default template with a few modifications (see code comments)
The project file
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Protos\greet.proto" GrpcServices="Server" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Grpc.AspNetCore" Version="2.40.0" />
<!-- Install additional packages -->
<PackageReference Include="Grpc.AspNetCore.Server.Reflection" Version="2.40.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="6.0.0" />
</ItemGroup>
</Project>
The Program.cs
using GrpcService1.Services;
using Microsoft.Extensions.Hosting.WindowsServices;
// Use WebApplicationOptions to set the ContentRootPath
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
ContentRootPath = WindowsServiceHelpers.IsWindowsService()
? AppContext.BaseDirectory
: default
});
// Set WindowsServiceLifetime
builder.Host.UseWindowsService();
builder.Services.AddGrpc();
// Add reflection services
builder.Services.AddGrpcReflection();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
// Map reflection endpoint
app.MapGrpcReflectionService();
app.Run();
Now open cmd in the project folder and execute
dotnet publish
The publish command will produce the exe file (I assume you are working on a Windows machine, otherwise how would you test Windows Service? 😁). On my machine the path to exe is
"C:\github\junk\GrpcService1\bin\Debug\net6.0\publish\GrpcService1.exe"
Now open cmd as Administrator and run the following command
sc.exe create "GrpcService" binpath="C:\github\junk\GrpcService1\bin\Debug\net6.0\publish\GrpcService1.exe"
Open Services and start the GrpcService. Now install and run grpcui tool:
grpcui -plaintext localhost:5000
The grpcui tool will open the UI where you should be able to see the Greeter service
Notes:
I Used WebApplication.CreateBuilder(new WebApplicationOptions()) because without that the service won't start. The Windows Event Viewer shows the error:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.NotSupportedException: The content root changed
from "C:\Windows\system32" to
"C:\github\junk\GrpcService1\bin\Debug\net6.0\publish". Changing the
host configuration using WebApplicationBuilder.Host is not supported.
Use WebApplication.CreateBuilder(WebApplicationOptions) instead.
Found the solution here.
By default, the application will start on port 5000. If you wish to use another port add --urls argument when creating the service
sc.exe create "GrpcService" binpath="C:\github\junk\GrpcService1\bin\Debug\net6.0\publish\GrpcService1.exe --urls \"http://localhost:6276\""

Issue accessing GCP secrets manager using dotnet 5

I am using Google.Cloud.SecretManager.V1 in my .NET 5 aspnet core application. I am containerizing application to run as linux container on GCP Cloud run. I get following exception while creating SecretManagerServiceClient
//call SDK
SecretManagerServiceClient client = SecretManagerServiceClient.Create();
System.DllNotFoundException: Unable to load shared library 'libdl.so' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibdl.so: cannot open shared object file: No such file or directory
at Grpc.Core.Internal.UnmanagedLibrary.Linux.dlopen(String filename, Int32 flags)
at Grpc.Core.Internal.UnmanagedLibrary.LoadLibraryPosix(Func`3 dlopenFunc, Func`1 dlerrorFunc, String libraryPath, String& errorMsg)
at Grpc.Core.Internal.UnmanagedLibrary.PlatformSpecificLoadLibrary(String libraryPath, String& errorMsg)
at Grpc.Core.Internal.UnmanagedLibrary..ctor(String[] libraryPathAlternatives)
at Grpc.Core.Internal.NativeExtension.LoadUnmanagedLibrary()
at Grpc.Core.Internal.NativeExtension.LoadNativeMethods()
at Grpc.Core.Internal.NativeExtension..ctor()
at Grpc.Core.Internal.NativeExtension.Get()
at Grpc.Core.Internal.NativeMethods.Get()
at Grpc.Core.GrpcEnvironment.GrpcNativeInit()
at Grpc.Core.GrpcEnvironment..ctor()
at Grpc.Core.GrpcEnvironment.AddRef()
at Grpc.Core.Channel..ctor(String target, ChannelCredentials credentials, IEnumerable`1 options)
at Google.Api.Gax.Grpc.GrpcCore.GrpcCoreAdapter.CreateChannelImpl(String endpoint, ChannelCredentials credentials, GrpcChannelOptions options)
at Google.Api.Gax.Grpc.GrpcAdapter.CreateChannel(String endpoint, ChannelCredentials credentials, GrpcChannelOptions options)
at Google.Api.Gax.Grpc.ChannelPool.GetChannel(GrpcAdapter grpcAdapter, String endpoint, GrpcChannelOptions channelOptions, ChannelCredentials credentials)
at Google.Api.Gax.Grpc.ChannelPool.GetChannel(GrpcAdapter grpcAdapter, String endpoint, GrpcChannelOptions channelOptions)
at Google.Api.Gax.Grpc.ClientBuilderBase`1.CreateCallInvoker()
at Google.Cloud.SecretManager.V1.SecretManagerServiceClientBuilder.BuildImpl()
at Google.Cloud.SecretManager.V1.SecretManagerServiceClientBuilder.Build()
at Google.Cloud.SecretManager.V1.SecretManagerServiceClient.Create()
Same code works fine if I use aspnetcore 3.1 image. NET 5 is supposed to be upgrade of .NET core 3.1 and backward compatible. So, I am curious and what could be done to make this code work on .NET 5
I posted this answer to make a solution from the comment section more visible.
As it was suggested by #John Hanley and confirmed by #SmartCoder this issue was solved by adding to the Docker file lines below:
RUN apt-get update -y
RUN apt-get install -y libc6-dev

Unable to load the specified metadata resource Release vs Debug build

I've been scratching my head for hours with a peculiar issue in Entity Framework.
The following questions are not duplicates since their answers do not help me:
MetadataException: Unable to load the specified metadata resource
Entity Framework - Unable to load the specified metadata resource
Unable to load the specified metadata resource
I have an aspnet core mvc app (v1.1) that references a .NET Framework 4.7 project (the Data Access Layer) with Entity Framework 6.1.3 installed as a NuGet package.
I'm using the designer so I have an .edmx file.
I'm getting the following exception thrown at my face in runtime:
System.Data.Entity.Core.MetadataException: Unable to load the specified metadata resource.
at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoaderCompositeResource.LoadResources(String assemblyName, String resourceName, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoaderCompositeResource.CreateResourceLoader(String path, ExtensionCheck extensionCheck, String validExtension, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
at System.Data.Entity.Core.Metadata.Edm.MetadataArtifactLoader.Create(String path, ExtensionCheck extensionCheck, String validExtension, ICollection`1 uriRegistry, MetadataArtifactAssemblyResolver resolver)
at System.Data.Entity.Core.Metadata.Edm.MetadataCache.SplitPaths(String paths)
at System.Data.Entity.Core.Common.Utils.Memoizer`2.<>c__DisplayClass2.<Evaluate>b__0()
at System.Data.Entity.Core.Common.Utils.Memoizer`2.Result.GetValue()
at System.Data.Entity.Core.Common.Utils.Memoizer`2.Evaluate(TArg arg)
at System.Data.Entity.Core.Metadata.Edm.MetadataCache.GetArtifactLoader(DbConnectionOptions effectiveConnectionOptions)
at System.Data.Entity.Core.Metadata.Edm.MetadataCache.GetMetadataWorkspace(DbConnectionOptions effectiveConnectionOptions)
at System.Data.Entity.Core.EntityClient.EntityConnection.GetMetadataWorkspace()
at System.Data.Entity.Core.Objects.ObjectContext.RetrieveMetadataWorkspaceFromConnection()
at System.Data.Entity.Core.Objects.ObjectContext..ctor(EntityConnection connection, Boolean isConnectionConstructor, ObjectQueryExecutionPlanFactory objectQueryExecutionPlanFactory, Translator translator, ColumnMapFactory columnMapFactory)
at System.Data.Entity.Internal.InternalConnection.CreateObjectContextFromConnectionModel()
at System.Data.Entity.Internal.LazyInternalConnection.CreateObjectContextFromConnectionModel()
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
And I have the following connectionstring:
metadata=res://*/MyContext.csdl|res://*/MyContext.ssdl|res://*/MyContext.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=MyDatabase;integrated security=True;multipleactiveresultsets=True;App=EntityFramework"
The thing is, when running in a Debug build, the application runs without any problems. However when running in a Release build, the exception gets thrown. But if I disable optimize code on the project with the .edmx file, the exception is not thrown anymore.
I've even looked in the Entity Framework source code. You can see from the Stacktrace, that this exception gets thrown at line 170, because loaders.Count == 0. I don't understand why the resources can't be loaded from the assembly in a Release build, while it works in a Debug build.
EDIT I just installed a trial version of Reflector to inspect the assembly. So when looking into the .dll file that has been built with the Debug configuration, I can clearly see the 3 resource files embedded. However, in the assembly that has been built with a Release configuration, oddly the resource files are missing!
I've found a workaround for this problem.
I'm targeting a .net core 3.1 linux container with a legacy project using an EDMX.
Migration of the whole EDMX in code first will take a lot of time so I had to find a solution to make it work in Azure.
Problem is that a dotnet cli command like dotnet publish does not embed csdl, msl, or ssdl files see issues #8932.
So do not embed it in the output assembly. This is partially explained in this thread.
First change the "Metadata artifact processing" property in the "Conceptual Entity Model" of the EDMX from "Embeded in Output Assembly" to "Copy to output directory" this picture show you how.
Note that you need to open the EDMX file (double click), since a single click will show you the property of the file.
copy the csdl, msl, and ssdl files for publishing. I do that with a PostBuild event in the csproj file. Like this :
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Condition="'$(OS)' == 'Unix'" Command="echo *** cp -a $(ProjectDir)$(OutDir)* $(TargetDir)" />
<Exec Condition="'$(OS)' == 'Unix'" Command="cp -a $(ProjectDir)$(OutDir)* $(TargetDir)" />
<Exec Condition="'$(OS)' != 'Unix'" Command="echo *** copy /Y $(ProjectDir)$(OutDir)* $(TargetDir)" />
<Exec Condition="'$(OS)' != 'Unix'" Command="copy /Y $(ProjectDir)$(OutDir)* $(TargetDir)" />
</Target>
Note that you'll have to adapt the copy command paths to match your solution (for example if your EDMX project is located in a sub-project).
Finally change your connection string to a non embeded metadata (see doc here).
From
connectionString="metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string=[...]"
To
connectionString="metadata=/app;provider=System.Data.SqlClient;provider connection string=[...]"
Since the folder change upon release/debug/publish I've created this small function in my application to change the connection string :
private string EntityConnectionString(string connectionString)
{
EntityConnectionStringBuilder csb = new EntityConnectionStringBuilder
{
ProviderConnectionString = connectionString,
Metadata = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
};
csb.Provider = "System.Data.SqlClient";
return csb.ConnectionString;
}
Just provide the connection string in the classical non EDMX format to the connectionString parameter of the function. ie :
data source=[...];initial catalog=EntityframeworkTest;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework

Local repository for Nuget causing error

I have come from the Maven world where for every project/solution you can read from a local repository (which could be updated from the public repository) and publish private code projects to the repository as well.
So, for example:
I can get log4xxx from the public repository, but have only one local
copy (per version) for all my projects.
I could create, mycommoncode-1.1.0, from my
project and it would land in the same directory
(${user.home}/.m2/repository)
So in the same vein, I am trying to keep a local repository for my .NET projects by using:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
<!-- My specific and common packages can be sourced from this folder -->
<add key="My Package Source" value="C:\sourcecode\CommonDLLs" />
    <add key="NuGet official package source" value="https://nuget.org/api/v2/" />
  </packageSources>
 ...
  <config>
    <!-- Install packages in this folder instead of default $(Solutiondir)\Packages -->
    <add key="repositorypath" value="C:\sourcecode\CommonDLLs" />
  </config>
</configuration>
To test this I packaged up an assembly, creating MyProject.dll.1.0.0.nupkg file for my project.
Then in Visual Studio, I selected another project and selected Manage NuGet Packages... I see MyProject.dll and an Install button.
But then I get errors:
'MyProject.dll 1.0.0' already installed.
Adding 'MyProject.dll 1.0.0' to MyTestProject.
Uninstalling 'MyProject.dll 1.0.0'.
Successfully uninstalled 'MyProject.dll 1.0.0'.
**Failed to add reference to 'MyProject'.**
I think it has to do with the path for both package source and respositoryPath, but wanted to confirm. True? Why does this not work? In theory, then I would have a single local repository.
Update:
I tried making the config point to different directories. I still get the same errors.
So it must be how I build the local repository files and/or where they are located:
I have a dll, MyProject.dll:
Step 1: Run nuget command
nuget spec MyProject.dll (which is in a folder 'lib')
Step 2: Edit nuget spec file
edit .nuspec file created
Step 3: Run nuget command
nuget pack MyProject.nuspec
This leaves me with 3 items in my folder:
MyProject.dll.nuspec
lib/MyProject.dll
MyProject.dll.1.0.0.nupkg
I tried just placing the .nupkg alone to the path pointed to by packageSources. Still same error.
Thanks a million!
Update #2:
Here is stack trace from running install in PM console:
PM> install-package -source c:\sourcecode\createcommon MyProject.dll
'MyProject.dll 1.0.0' already installed.
Adding 'MyProject.dll 1.0.0' to MyTestProject.
Uninstalling 'MyProject.dll 1.0.0'.
Successfully uninstalled 'MyProject.dll 1.0.0'.
Install-Package : Failed to add reference to 'MyProject'.
At line:1 char:16
+ install-package <<<< -source c:\sourcecode\createcommon MyProject.dll
+ CategoryInfo : NotSpecified: (:) [Install-Package], InvalidOperationException
+ FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand
PM> $error[0].Exception.StackTrace
at NuGet.VisualStudio.VsProjectSystem.AddReference(String referencePath, Stream stream)
at NuGet.ProjectManager.ExtractPackageFilesToProject(IPackage package)
at NuGet.ProjectManager.AddPackageReferenceToProject(IPackage package)
at NuGet.ProjectManager.Execute(PackageOperation operation)
at NuGet.ProjectManager.Execute(IPackage package, IPackageOperationResolver resolver)
at NuGet.ProjectManager.AddPackageReference(IPackage package, Boolean ignoreDependencies, Boolean allowPrereleaseVersions)
at NuGet.VisualStudio.VsPackageManager.<>c__DisplayClass60.<AddPackageReference>b__5f()
at NuGet.VisualStudio.VsPackageManager.RunProjectAction(IProjectManager projectManager, Action action)
at NuGet.VisualStudio.VsPackageManager.AddPackageReference(IProjectManager projectManager, IPackage package, Boolean ignoreDependencies, Boolean allowPrereleaseVersions)
at NuGet.VisualStudio.VsPackageManager.<>c__DisplayClass8.<InstallPackage>b__4()
at NuGet.VisualStudio.VsPackageManager.RunSolutionAction(Action action)
at NuGet.VisualStudio.VsPackageManager.InstallPackage(IProjectManager projectManager, String packageId, SemanticVersion version, Boolean ignoreDependencies, Boolean allowPrereleaseVersions, Boolean skipAssemblyReferences, ILogger logger)
at NuGet.VisualStudio.VsPackageManager.InstallPackage(IProjectManager projectManager, String packageId, SemanticVersion version, Boolean ignoreDependencies, Boolean allowPrereleaseVersions, ILogger logger)
at NuGet.PowerShell.Commands.InstallPackageCommand.InstallPackage(IVsPackageManager packageManager)
at NuGet.PowerShell.Commands.InstallPackageCommand.ProcessRecordCore()
at NuGet.PowerShell.Commands.NuGetBaseCommand.ProcessRecord()
PM>
Inner exception:
System.InvalidOperationException: Failed to add reference to 'Utility'. --->
System.Runtime.InteropServices.COMException:
Error HRESULT E_FAIL has been returned from a call to a COM component.
at VSLangProj.References.Add(String bstrPath)
at NuGet.VisualStudio.VsProjectSystem.AddReference(String referencePath, Stream stream)
--- End of inner exception stack trace ---

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

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
}

Categories