Summary: Learn how to execute C# programs from source without a compiled binary by using Windows PowerShell.
Microsoft Scripting Guy, Ed Wilson, is here. Today guest blogger, Ingo Karstein, is back with us to share his knowledge. You can also read previous guest blogs by Ingo. Take it away Ingo…
Some time ago, I created a script called PS2EXE that creates EXE files out of Windows PowerShell script files. It is posted on the Hey, Scripting Guy! Blog: Learn About Two CodePlex Projects: PS2EXE and RoboPowerCopy.
Now I have created another script, rather the opposite of PS2EXE: C#Script. This script is able to execute C# programs from source code without a compiled binary.
I’ve done this because I have several C# tools that I always use for my daily business. Some of them are not easily convertible to Windows PowerShell. But I like the fact that script files are always readable because you only need the source code, no compiler. There is no need for binaries with separate source projects somewhere on the hard disk, so I decided to create a script with the purpose of running C# code inside Windows PowerShell.
The idea is simple:
- Take a C# program file and compile it into the memory.
- Search for the Main method and call them using .NET reflection.
- Add some basic .NET console support to write output from the C# program to the Windows PowerShell environment.
The C# program will be executed in a real .NET thread that is created in the Windows PowerShell script by using a helper class that is compiled in memory at runtime too. This helper class provides some synchronous .NET events that can be subscribed in Windows PowerShell to handle the console output.
Note You can download C#Script from the Microsoft TechNet Gallery: C#Script: Execute source code C# programs from PowerShell. You should be aware of the following limitations:
- This project is in the alpha state! There will be errors in it. So please be careful, especially in a production environment.
- Console input not implemented. Therefore, we need a custom class derived from System.IO.TextReader.
- There is no resource file support! It is just plain C#.
To demonstrate the script, I created two C# demo projects: “Test” and “TestWin.” The first one is a console application, the second is a Windows Forms application.
The following screenshot shows my “TestWin” demo project. My csscript.ps1 file is in the folder “C:\source2\csscript,” and “testwin” is in the subfolder. (The Windows 8 operating system is in German, but you get the point, I’m sure.)
Let’s have a look into “TestWin.” The following screenshot is from the Visual Studio 2012 project.
Of course it can be run in Visual Studio 2012 or as standalone .NET assembly (EXE file). The list box is empty. It would show the program's arguments if there were any.
At the beginning of the Program.cs file, there is an XML configuration section for C#Script:
//<csscript>
// <nodebug/>
// <references>
// <reference>System</reference>
// <reference>System.Core</reference>
// <reference>System.Data</reference>
// <reference>System.Data.DataSetExtensions</reference>
// <reference>System.Xml</reference>
// <reference>System.Xml.Linq</reference>
// <reference>System.Windows.Forms</reference>
// <reference>System.Drawing</reference>
// </references>
// <mode>winexe</mode>
// <files>
// <file>Form1.cs</file>
// <file>Form1.Designer.cs</file>
//// <file>Test</file>
// </files>
//</csscript>
This rules the compilation of the program when using C#Script. Here, you specify the .NET assembly references, the execution mode, and the source files. By using four slash characters, the line will be ignored. In the “files” section, you specify all necessary C# files if there are more than one. The additional files do not need XML configuration.
In my demo, the project needs three C# files to run: Program.cs, Form1.cs, and Form1.Designer.cs. The configuration XML is stored only at the beginning of Program.cs.” By using <debug/>, it’s possible to debug the C# program file. I will show that later.
Now let’s go to the Windows PowerShell command line and use C#Script:
At the command line, I type:
.\csscript.ps1 .\testwin\testwin\Program.cs "Greetings" "from" "germany" "!"
That’s it.
Let’s have a look at the console application demo.
At the Windows PowerShell command line, I type:
.\csscript.ps1 .\test\test\Program.cs "Greetings" "from" "germany" "!"
Here I use the <debug/> configuration to be able to debug the program. This gives me the Debugger Attach dialog from Visual Studio 2012 when I run the previous command-line statement:
You will automatically get the source file of the C#Script internal helper class with hard coded breakpoints:
Here you can see how it works inside: Internally it creates a thread and executes the original program by reflection. The Main method of the C# program is given in Method parameter, and the command-line arguments are in the prms parameter.
The next hard coded breakpoint is specified in the Program.cs file. The file will have a new name. (Here the name is n_dspgoj.0.cs.)
This is the output in the console:
In the C#Script package, I’ve included a file named “csscript.bat” that helps you execute csscript from the traditional Windows shell:
You can use it like this:
I’ve tested this C#Script with one of my favorite tools: the SharePoint Feature Administration and Clean Up Tool (it’s a Windows Forms application).
1. I downloaded the code from CodePlex: SharePoint Feature Administration and Clean Up Tool
2. Unzip to a folder.
3. Create a batch file “run.bat.”
@echo off
call csscript.bat "FeatureAdmin2013-VisualStudio2012\Program.cs"
4. Copy “csscript.ps1” and “csscript.bat” into the folder.
5. Modify the file “Program.cs” to contain the config XML structure.
Note “requiredframework” and “requiredplatform” are set because SharePoint 2013 needs .NET Framework 4.0 and 64-bit processes.
6. Execute the program with “run.bat” without compilation in VS2012.
For this program, I’ll not need a compiled EXE anymore! Now I’d like to get your response! If you found any errors, please report them on the TechNet Gallery page: C#Script: Execute source code C# programs from PowerShell. Please feel free to modify C#Script and send me your changes.
~Ingo
Ingo, thank you for sharing this with us today. I love it.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy