Creating .EXE-files using C# without Visual Studio

Creating .EXE-files using C# without Visual Studio

2014, Nov 18    

While needing a method to time the response time of the Microsoft Active Directory services I came the conclusion that it is possible to create an .EXE using the Microsoft .NET framework software. Microsoft included a command line compiler which is able to create an .EXE from a .CS file. Below you may find the source (borrowed from PinVoke.NET which I used to include the timing measuring.

More info here on MSDN

Contents of C:\GetUsername.cmd

@echo off
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:C:\GetUsername.exe C:\GetUsername.cs
If not %errorlevel%==0 goto :EOF
Echo 1st Try
C:\GetUsername.exe
Echo.
Echo 2nd Try
C:\GetUsername.exe
Echo.
Echo 3rd Try
C:\GetUsername.exe

Contents of C:\GetUsername.cs

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace test
	{

		class clsLookupAccountName
		{

			const int NO_ERROR = 0;
			const int ERROR_INSUFFICIENT_BUFFER = 122;
			const int ERROR_INVALID_FLAGS = 1004; // On Windows Server 2003 this error is/can be returned, but processing can still continue

			enum SID_NAME_USE
			{
				SidTypeUser = 1,
				SidTypeGroup,
				SidTypeDomain,
				SidTypeAlias,
				SidTypeWellKnownGroup,
				SidTypeDeletedAccount,
				SidTypeInvalid,
				SidTypeUnknown,
				SidTypeComputer
				}

			[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError = true)]
			static extern bool LookupAccountName ( 
			string lpSystemName,
			string lpAccountName,
			[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
			ref uint cbSid,
			StringBuilder ReferencedDomainName,
			ref uint cchReferencedDomainName,
			out SID_NAME_USE peUse);

			[DllImport("advapi32", CharSet=CharSet.Auto, SetLastError=true)]
			static extern bool ConvertSidToStringSid(
			[MarshalAs(UnmanagedType.LPArray)] byte [] pSID,
			out IntPtr ptrSid);

			[DllImport("kernel32.dll")]
			static extern IntPtr LocalFree(IntPtr hMem);

			[STAThread]
			static void Main(string[] args)
			{

				DateTime now1 = DateTime.Now;
				Console.WriteLine(now1);

				string accountName = "DOMAIN\\username";

				byte [] Sid = null;
				uint cbSid = 0;
				StringBuilder referencedDomainName = new StringBuilder();
				uint cchReferencedDomainName = (uint)referencedDomainName.Capacity;
				SID_NAME_USE sidUse;

				int err = NO_ERROR;
				if (!LookupAccountName(null,accountName,Sid,ref cbSid,referencedDomainName,ref cchReferencedDomainName,out sidUse))
				{
					err = Marshal.GetLastWin32Error();
					if (err == ERROR_INSUFFICIENT_BUFFER || err == ERROR_INVALID_FLAGS)
					{
						Sid = new byte[cbSid];
						referencedDomainName.EnsureCapacity((int)cchReferencedDomainName);
						err = NO_ERROR;
						if (!LookupAccountName(null,accountName,Sid,ref cbSid,referencedDomainName,ref cchReferencedDomainName,out sidUse))
						err = Marshal.GetLastWin32Error();
					}
				}
				else
				{
					// Consider throwing an exception since no result was found
					}
				if (err == 0)
				{
					IntPtr ptrSid;
					if (!ConvertSidToStringSid(Sid,out ptrSid))
					{
						err = Marshal.GetLastWin32Error();
						Console.WriteLine(@"Could not convert sid to string. Error : {0}",err);
					}
					else
					{
						string sidString = Marshal.PtrToStringAuto(ptrSid);
						LocalFree(ptrSid);
						Console.WriteLine(@"Found sid {0} : {1}",sidUse,sidString);
					}
				}
				else
				Console.WriteLine(@"Error : {0}",err);

				DateTime now2 = DateTime.Now;
				Console.WriteLine(now2);
				Console.WriteLine(accountName);
				Console.WriteLine(@" ");
				Console.WriteLine(now2-now1);
			}
		}
	}