Build visual studio solution using msbuild from c# code - c#

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.

Related

C# ProcessStartInfo: Second process receives no arguments

I'm trying to make a call from one process to start another, supplying starting arguments as separate parameters in a ProcessStartInfo. The starting call uses a URL registered in Windows to find the second program, entered into FileName. I then add a string containing 4 parameters to Arguments. As I have understood it, the spaces in the string indicate the separation of the arguments.
Program 1
//Create starting information
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo() {
FileName = "urlHandle:",
Arguments = "/argA valueA /argB valueB"
};
//Start second program
System.Diagnostics.Process.Start(startInfo);
Program 2
//Print received arguments to a file
Environment.GetCommandLineArgs().ToList().ForEach(a => writer.WriteLine(a + ",\t"));
The second program starts as intended (meaning the URL is working), but the output is incomplete.
[path to .exe of second program],
urlHandle:,
It contains the path to the program, the string set as FileName , but everything put into Arguments is missing.
Does anybody have any ideas why the arguments disappear?
Note 1: If I would add the arguments into the FileName, I would receive them as one string. In order to trigger the behaviour I want in the second program, I must supply it with several parameters instead of one. I know this is possible from testing it manually from the terminal.
Note 2: I'm using .Net Framework, so trying ArgumentList from .Net Core is not an option.
After some more tests I have found the issue. The error does not lie in how I set up and use ProcessStartInfo, but rather in that I am using a custom URL protocol.
In the Windows registry one defines the number of parameters that can be sent via the URL call ("C:\[path to my .exe]" "%1"). The first argument is the Filename, and is as such the only thing sent via the protocol. In order to send more, one is required to add "%2", "%3", etc.
Note: The path itself becomes argument 0 in the receiving program, while the actual sent parameters start at argument 1 and beyond.

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)

Open and Receive values from a bat to exe with C#

I'm trying to create a C# console app to do some proccess. I want to open my demo.exe and send some parameters from a .BAT file to that cosole.
I know the .bat should be something like:
demo.exe -a cclock -cc 1306 -mc 1750
But, I don't have any idea to make my .exe to get the parameters I'm sending.
This is where the arguments to Main method helps.
In an standard C# program entry method is like,
static int Main(string[] args)
Here args[] is the array of arguments passed to your executable via command line.
So in your example,
demo.exe -a cclock -cc 1306 -mc 1750
args is a string array containing following,
{"-a", "cclock", "-cc", "1306", "-mc", "1750"}
You can retrieve these value in this manner,
args[0] = "-a"
args[1] = "cclock"
args[2]= "-cc" ...... and so on
You can use these value for the rest of your code.
Remember that whatever values you pass are broken into separate string values on each occurrence of white-space. Also whatever value you pass will be taken as string. So you have to do your own validation and parsing.
Your application's Main method (typically in Program.cs) can accept a parameter string[] args, which you can access to get the command line parameters used to launch your app. Alternatively, you can also use Environment.GetCommandLineArgs() anywhere in the application to do the same thing.

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

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

Debugging C# on the command line: ">"-character

I'm creating a small commandline tool for a customer and trying to verify its output. The output is been written to the commandline itself. Since its rather a huge file that's been used as an input file and thus a huge out to write to the commandline, I wanted the output to redirect to a file.
Usually I use use commandline arguments like so to redirect the output to a file:
a.exe ./input.txt > ./ouput.txt
However, in my program, I try to verify the input:
static void Main(string[] args)
{
if (args.Length != 1)
throw new ArgumentException();
...
And args now is:
args[0] = ./input.txt
args[1] = >
args[2] = ./ouput.txt
Honestly I personally still expect only one argument, since the file is been created and thus the shell does understand what I mean. So... what am I doing wrong? Should I use args or something else?
Thank you in advance!
Are you passing the arguments through Visual Studio? It will only work if you untick Enable the Visual Studio hosting process.
Image and explanation from here.

Categories

Resources