C#: ArgumentException when calling System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace() - c#

I am in a bit of a strange situation. I have been given a fairly large suite of PowerShell modules and functions, and it is my job to tie these together into an executable. The requirements state that this must be a single, standalone executable with no installer and .net 3.5 may be the only dependency. The Windows Management Framework is not an exception and cannot be assumed to exist on the machine. To get around this, I have added System.Management.Automation as a reference and made it an embedded resource, along with all of the PowerShell module files, and load them from reflection at runtime. This seems to work OK, but I have some errors that I cannot seem to figure out and think it might have something to do with this system.
So Here is the issue: When I start to initialize things to run the PowerShell command, I get a strange error that I can't seem to control.
Here is the code:
public static void RunCommand(object objcommand)
{
//create a script block for toolbox once, get the embeded resource, convert from byte array to string, make scriptblock from string
ScriptBlock toolbox = System.Management.Automation.ScriptBlock.Create(System.Text.Encoding.Default.GetString(Properties.Resources.toolbox));
string command = (string)objcommand;
//get the module name
string modname = options.Commands[command]["module"];
//get the module from the embeded resources, convert to string, convert to scriptblock
var module = System.Management.Automation.ScriptBlock.Create(new System.IO.StreamReader(myasm.GetManifestResourceStream("piramids.Resources." + modname + ".psm1")).ReadToEnd());
using (var powerShell = PowerShell.Create())
{
System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(); //i think this line triggers the exception
rs.Open();
powerShell.Runspace = rs;
//make the necesary powershell modules of the command availible
powerShell.AddCommand("new-module").AddParameter("ScriptBlock", toolbox).Invoke();
powerShell.AddCommand("new-module").AddParameter("ScriptBlock", module).Invoke();
//if inethistory, make dlls availible
if (modname.Equals("inethistory"))
{
powerShell.AddCommand("add-type").AddParameter("Path", sqldll).Invoke();
powerShell.AddCommand("add-type").AddParameter("Path", esentdll).Invoke();
}
ICollection<PSObject> output = new List<PSObject>(0);
try {
output = powerShell.AddCommand("get-" + command).AddCommand(format).AddCommand("out-string").Invoke();//pipeline.Invoke();
} catch (System.Management.Automation.RuntimeException e)
{
Console.Error.WriteLine("An Error occured while executing '" + command + "'");
Console.Error.WriteLine(e.Message);
}
//do stuff with the results
and here is the stack trace:
Unhandled Exception: System.ArgumentException: The path is not of a legal form.
at System.IO.Path.NormalizePathFast(String path, Boolean fullCheck)
at System.IO.Path.NormalizePath(String path, Boolean fullCheck)
at System.IO.Path.GetFullPathInternal(String path)
at System.IO.Path.GetFullPath(String path)
at System.Diagnostics.FileVersionInfo.GetFullPathWithAssert(String fileName)
at System.Diagnostics.FileVersionInfo.GetVersionInfo(String fileName)
at System.Management.Automation.PSVersionInfo.GetPSVersionTable()
at System.Management.Automation.PSVersionInfo.get_PSVersion()
at Microsoft.PowerShell.DefaultHost..ctor(CultureInfo currentCulture, CultureInfo currentUICulture)
at System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace()
at piramids.Program.RunCommand(Object objcommand)
at piramids.Program.Main(String[] args)
I believe this line is where the exception occurs:
System.Management.Automation.Runspaces.Runspace rs = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
The CreateRunspace method is not documented to throw any exceptions, and this exception comes from so many levels down that I have no idea what kind of path this thing is checking, as I never called a function that asked for a path.
I am stumped. Does anyone have any idea what may be causing this?
EDIT: After some digging, here is what I found. PSVersionTable is a static field of VersionInfo, so the static constructor is called the first time get called for this field. The static constructor calls an internal method called GetBuildVersion, which tries to get the assembly location of PSVersionInfo. According to This documentation page:
If the assembly is loaded from a byte array, such as when using the Load(Byte[]) method overload, the value returned is an empty string ("").
I am loading from a byte array, so this will be an empty string. But then GetBuildVersion uses this location to do FileVersionInfo.GetVersionInfo which verifies the path with Path.GetFullPath. According to This documentation page:
ArgumentException:
the path is a zero-length string
So there is the problem. Now the question is, How do I assign a location to an assembly loaded from a byte array? May God have mercy on me.

I'm not at all convinced this is even remotely reasonable to expect PowerShell code to work without installing WMF. If I were approached with that request I would respond that all code must be rebuilt in another .NET language (that is, C#).
Still, perhaps you can see if it's this static method. You'll have to de-PowerShell the code I'm afraid. The PowerShell accelerator is just a simple way for me to get at the System.Management.Automation assembly. The class is not public and the method on the class is not public either.
$verInfo = [PowerShell].Assembly.GetTypes() | Where-Object Name -eq 'PSVersionInfo'
$verInfo.GetMethod('get_PSVersion', [System.Reflection.BindingFlags]'NonPublic,Static').Invoke($null, [System.Reflection.BindingFlags]'NonPublic,Static', $null, #(), $null)
Chris

Related

ArgumentException : "the path is not of a legal form" when using the CallerFilePath attribute in a script

Context
I am trying to run a C# script (.csx file) programmatically from a program I will call ScriptRunner.exe here and that I wrote myself (because csi.exe doesn't output what I want).ScriptRunner.exe is a simple console application and its most interesting feature is to have the following line :
var state = await CSharpScript.RunAsync<int>(script, referencesAndUsings, globalArgs);
ScriptRunner.exe works great ! However...
Problem
The moment my script contains the following line :
static string GetCurrentFileName([System.Runtime.CompilerServices.CallerFilePath] string fileName = null) { return fileName; }
and in particular [System.Runtime.CompilerServices.CallerFilePath], I get an ArgumentException : "the path is not of a legal form" ; note that the latter doesn't appear if I use the same line from a C# Interactive through a #load command - which correctly shows the path of my .csx file.
Investigated elements until now
The stacktrace shows at System.IO.Path.LegacyNormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
I checked what seems to be the implementation
I checked by hand the path of my csx file ; there's no invalid path characters in the path to my csx, and no wildcards in it either.
I checked there was no reference issue with mscorlib
Maybe something is missing in the ScriptOptions (referencesAndUsings in my first sample code), I looked at it but... I don't seem to understand everything well enough
The way I created my ScriptOptions ("referencesAndUsings") looks like the following:
var myOptions = ScriptOptions.Default;
myOptions.AddReferences(new List<string>() { ... });
myOptions.AddImports(new List<string>() { ... });
This is the documentation for the CallerFilePath attribute
This is the documentaiont for the concept of Caller Information
What really saddens me is that it works in C# Interactive.
Question
Does anyone know why it wouldn't want to work when interpreted by my ScriptRunner.exe ; and how to make it work ?
In
var state = await CSharpScript.RunAsync<int>(script, referencesAndUsings, globalArgs);
script is the script itself (the contents of the csx file). As such it has no path. CSharpScript knows nothing about the path of your csx file. When you call GetCurrentFileName from within the script, there is no path information.
You need to specify a FilePath in ScriptOptions using WithFilePath(csxFilePath)

Passing bytes as parameter to c#?

I am currently stuck while trying to call a c# methods from python. I am using python 3.2 and not IronPython. I used pip to install the latest version of python.net
Problem occurs (as often discussed) while using ref or out parameters.
Here is my code so far:
import clr
path = clr.FindAssembly("USB_Adapter_Driver")
clr.AddReference(path)
from USB_Adapter_Driver import USB_Adapter
gpio = USB_Adapter()
version2 = ''
status, version = gpio.version(version2)
print ('status: ' + str(status))
print ('Version: ' + str(version))
readMask = bytearray([1])
writeData = bytearray([0])
print (readMask)
print (writeData)
status, readData = gpio.gpioReadWrite(b'\x01',b'\x00',b'\x00')
status, readData = gpio.gpioReadWrite(readMask[0],writeData[0],b'\x00')
status, readData = gpio.gpioReadWrite(readMask[0],writeData[0],)
I have had some major issues getting clr. running at all. But in this exact config it seems to work (I need to save the path to a variable, otherwise it wont work, I also cant type the path the dll in clr.AddReference(path) because this wont work as well)
The c# version method looks like this:
public USB_Adapter_Driver.USB_Adapter.Status version(ref string ver)
My status variable gets a value which works perfectly with the status enum for the c# class.
Problem is: after the call my variable "version" is empty. Why? According to: How to use a .NET method which modifies in place in Python? this should be a legal way to do things. I also tried to use the explicit version but my namespace clr does not contain clr.Reference().
The next (and more severe) problem is pio.gpioReadWrite().Here the info about this one:
public USB_Adapter_Driver.USB_Adapter.Status gpioReadWrite(byte readMask, byte writeData, ref byte readData)
Here I get the error message:
TypeError: No method matches given arguments
It doesn't matter which of the calls I use from above. All of them fail.
Here is the full output of a debugging run:
d:\[project path]\tests.py(6)<module>()
status: 6
Version:
bytearray(b'\x01')
bytearray(b'\x00')
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
d:\[project path]\tests.py(28)<module>()
status, readData = gpio.gpioReadWrite(readMask[0],writeData[0],)
(Pdb) Traceback (most recent call last):
File "D:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\pdb.py", line 1661, in main
pdb._runscript(mainpyfile)
File "D:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\pdb.py", line 1542, in _runscript
self.run(statement)
File "D:\WinPython-64bit-3.4.4.2Qt5\python-3.4.4.amd64\lib\bdb.py", line 431, in run
exec(cmd, globals, locals)
File "<string>", line 1, in <module>
File "d:\[project path]\tests.py", line 28, in <module>
status, readData = gpio.gpioReadWrite(readMask[0],writeData[0],)
TypeError: No method matches given arguments
Hope one of you has an idea on how to fix this.
Thanks,
Kevin
Python.Net doesn't handle ref/out parameters like IronPython.
status, readData = gpio.gpioReadWrite(b'\x01',b'\x00',b'\x00') call is not quite correct since Python.Net will not return an updated readData as second result.
You can handle ref parameters using reflection. Check out my answer to similar question here
there is a rough code template for your case:
import clr
clr.AddReference("USB_Adapter_Driver")
import System
import USB_Adapter_Driver
myClassType = System.Type.GetType("USB_Adapter_Driver.USB_Adapter, USB_Adapter_Driver")
method = myClassType.GetMethod("gpioReadWrite")
parameters = System.Array[System.Object]([System.Byte(1),System.Byte(0),System.Byte(0)])
gpio = USB_Adapter_Driver.USB_Adapter()
status = method.Invoke(gpio,parameters)
readData = parameters[2]

Given path format not supported c#

I get this exception when trying to perform an XSLT transformation with C#:
Exception: System.NotSupportedException: The given path's format is not supported.
at System.Security.Permissions.FileIOPermission.QuickDemand(FileIOPermissionAccess access, String fullPath, Boolean checkForDuplicates, Boolean needFullPath)
at System.Xml.XmlResolver.ResolveUri(Uri baseUri, String relativeUri)
at System.Xml.XmlUrlResolver.ResolveUri(Uri baseUri, String relativeUri)
at System.Xml.XmlTextReaderImpl..ctor(String url, XmlNameTable nt)
at System.Xml.XPath.XPathDocument..ctor(String uri, XmlSpace space)
at System.Xml.XPath.XPathDocument..ctor(String uri)
at ConsoleApplication8.Program.TransformXML(String sXmlPath, String sXslPath)
when i try to run this code
void test()
{
var myXslTrans = new XslCompiledTransform();
myXslTrans.Load(#"‪C:\Users\ahmed\Desktop\fewf\visio.xsl");
myXslTrans.Transform(#"‪C:\Users\ahmed\Desktop\fewf\page1.xml", #"‪C:\Users\ahmed\Desktop\fewf\page.html");
}
i try to use Path.Combine(); but give me the same case
How can i solve this ?
Unfortunately, it was not clear from your question that you are using Silverlight (or at least some platform that somehow triggers this method)). When I started searching for QuickDemand, it turned out that this is only called in SilverLight (or similar?) environments, so I am rewriting my answer with that in mind.
at System.Security.Permissions.FileIOPermission.QuickDemand
This error is caused by this block of code in the reference source. As can be seen there, if the path contains a colon above second position, it is considered invalid.
In your code above this isn't shown, but since this is the only place in the reference source where this specific error is thrown, I am going to assume that the real code you have (possibly any of the xsl:includes in the XSLT) is containing a colon at some position other than the second position.
Either way, if this doesn't help, go to the Exceptions screen and check the NotSupportedException and in the Debug window uncheck the "Just my code" and check the "Enable .NET framework source stepping". That way, you can break at the position where the error is thrown and use IntelliSense and the debug windows to find out the context (i.e. the actual path) that is causing this error.
Also, from my previous post, if this doesn't help:
Try your code with a minimal XSLT (this is vital!)
Once you have that running, add an xsl:include
Once you have that running, add a document (if you use that, in addition, enable it in the settings)
Once you have that running... well, you get the drift

Build visual studio solution using msbuild from c# code

I want to build my solution file from other c# code using msbuid I have tried
var msbuild_path = #"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe";
var solution_path = #"D:\Sumit\WorkingCopy\Final\Final.sln";
Process.Start(msbuild_path + " " + solution_path);
but this one throws an error Please help me out!!
According to https://msdn.microsoft.com/en-us/library/h6ak8zt5(v=vs.110).aspx , the Process.Start method takes two arguments:
public static Process Start(string fileName, string arguments)
So you should change your code to
Process.Start(msbuild_path, solution_path);
What you were doing before was actually trying to run a file named "C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe(space)D:\Sumit\WorkingCopy\Final\Final.sln", but no such file exists with that name. The msbuild.exe may exist, but "msbuild.exe D:\Sumit...\Final.sln" is not the filename you meant to pass as the command filename. Also, the argument string was empty, so the system assumed you did not want to pass any arguments to "msbuild.exe D:\Sumit...\Final.sln". But the error message was because the two filenames were mashed into one filename.
Windows allows filenames to contain embedded spaces, which frequently causes problems in dealing with command-line arguments.

Does LibGit2Sharp support cloning a repository from the local file system?

I am trying to clone a git repository from the local file system:
using System;
using LibGit2Sharp;
class Program
{
static void Main()
{
var sourceUrl = #"file:///c:/work/libgit2sharp";
using (Repository.Clone(sourceUrl, "targetDir", bare: true))
{
Console.WriteLine("repository successfully cloned");
}
}
}
and I get an exception:
Unhandled Exception: LibGit2Sharp.LibGit2SharpException: An error was raised by libgit2. Category = Odb (Error).
Failed to find the memory window file to deregister
at LibGit2Sharp.Core.Ensure.Success(Int32 result, Boolean allowPositiveResult) in c:\work\libgit2sharp\LibGit2Sharp\Core\Ensure.cs:line 85
at LibGit2Sharp.Core.Proxy.git_clone_bare(String url, String workdir, git_transfer_progress_callback transfer_cb) in c:\work\libgit2sharp\LibGit2Sharp\Core\Proxy.cs:line 219
at LibGit2Sharp.Repository.Clone(String sourceUrl, String workdirPath, Boolean bare, Boolean checkout, TransferProgressHandler onTransferProgress, CheckoutProgressHandler onCheckoutProgress) in c:\work\libgit2sharp\LibGit2Sharp\Repository.cs:line 431
at Program.Main() in c:\work\ConsoleApplication1\Program.cs:line 10
I've also tried the following source url:
var sourceUrl = #"c:\work\libgit2sharp\.git\";
and got another exception:
Unhandled Exception: LibGit2Sharp.LibGit2SharpException: An error was raised by libgit2. Category = Config (Error).
Failed to parse config file: Unexpected end of file while parsing multine var (in c:/work/ConsoleApplication1/bin/Debug/targetDir/config:23, column 0)
at LibGit2Sharp.Core.Ensure.Success(Int32 result, Boolean allowPositiveResult) in c:\work\libgit2sharp\LibGit2Sharp\Core\Ensure.cs:line 85
at LibGit2Sharp.Core.Proxy.git_clone_bare(String url, String workdir, git_transfer_progress_callback transfer_cb) in c:\work\libgit2sharp\LibGit2Sharp\Core\Proxy.cs:line 219
at LibGit2Sharp.Repository.Clone(String sourceUrl, String workdirPath, Boolean bare, Boolean checkout, TransferProgressHandler onTransferProgress, CheckoutProgressHandler onCheckoutProgress) in c:\work\libgit2sharp\LibGit2Sharp\Repository.cs:line 431
at Program.Main() in c:\work\ConsoleApplication1\Program.cs:line 12
targetDir is never created.
If on the other hand I use HTTP transport, the Repository.Clone method works fine:
var sourceUrl = "https://github.com/libgit2/libgit2sharp";
So my question is if I am doing something wrong or if this is unsupported feature or a bug in the native git2.dll?
So my question is if I am doing something wrong or if this is unsupported feature or a bug in the native git2.dll?
A bit a both, actually.
The first exception is clearly a bug. This should not happen and will be troubleshot.
The second one requires a deeper analysis. Would you be so kind as to open a issue in the LibGit2Sharp project?
Good news are that a pull request from BenStraub was recently merged. This pull request implements the local fetch transport which should pretty solve the issue.
LibGit2Sharp will be updated in the following days with a new a new version of libgit2 binaries which should allow you perform a local clone/fetch. I'll update this answer as soon as it's been done.
Update
This test shows how do to a Clone and a Push over against a local repository.

Categories

Resources