PowershellでC#を実行、exeファイルを作成

# やること
Powershellを使えば、C#をそのまま実行したりexeファイルを作成することができる。
この機能により、Powershellだけだと難しい複雑な処理もC#で記述して実行することができる。

### C#を実行
PowershellにC#のプログラムを文字列で渡し、実行する。

~~~powershell
$code = @"
using System;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

public static class Test {
    private static int numThreads = 1;
    
    public static void Main(string[] args) {
        Console.WriteLine("NamedPipe Test (s: server, c: client)");
        
        var sorc = Console.ReadLine();
        
        if(sorc == "c") {
            CreateClientTask("pipe1").Wait();
        }
        if(sorc == "s") {
            CreatePipeServerTask("pipe1").Wait();
        }
    }
    
    public static Task CreatePipeServerTask(string pipeName) {
        return Task.Run(() => {
            NamedPipeServerStream pipeServer = null;
            
            while(true) {
                try {
                    pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, numThreads);
                    pipeServer.WaitForConnection();
                    StreamString ss = new StreamString(pipeServer);
                    
                    while (true)
                    {
                        var read = ss.ReadString();
                        var write = ss.WriteString("Server read OK.");
                        Console.WriteLine("Read Data = " + read);

                        if (read == "end") break;
                    }
                    
                }
                catch(OverflowException ofex) {
                    Console.WriteLine(ofex.Message);
                }
                finally {
                    pipeServer.Close();
                }
            }
        });
    }
    
    public static Task CreateClientTask(string pipeName){
        return Task.Run(() => {
            while (true) {
                NamedPipeClientStream pipeClient = null;

                try {
                    pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
                    pipeClient.Connect();
                    var ss = new StreamString(pipeClient);

                    while (true) {
                        var writeData = Console.ReadLine();
                        var write = ss.WriteString(writeData);
                        var read = ss.ReadString();
                        Console.WriteLine("Server Response = " + read);

                        if (writeData == "end") break;
                    }
                }
                catch (OverflowException ofex) {
                    Console.WriteLine(ofex.Message);
                }
                catch (IOException ioe) {
                    Console.WriteLine(ioe.Message);
                }
                finally {
                    pipeClient.Close();
                }
            }
        });
    }
}

public class StreamString
{
    private Stream ioStream;
    private UnicodeEncoding streamEncoding;

    public StreamString(Stream ioStream)
    {
        this.ioStream = ioStream;
        streamEncoding = new UnicodeEncoding();
    }

    public string ReadString()
    {
        int len = 0;

        len = ioStream.ReadByte() * 256;
        len += ioStream.ReadByte();
        byte[] inBuffer = new byte[len];
        ioStream.Read(inBuffer, 0, len);

        return streamEncoding.GetString(inBuffer);
    }

    public int WriteString(string outString)
    {
        byte[] outBuffer = streamEncoding.GetBytes(outString);
        int len = outBuffer.Length;
        if (len > UInt16.MaxValue)
        {
            len = (int)UInt16.MaxValue;
        }
        ioStream.WriteByte((byte)(len / 256));
        ioStream.WriteByte((byte)(len & 255));
        ioStream.Write(outBuffer, 0, len);
        ioStream.Flush();

        return outBuffer.Length + 2;
    }
}
"@

Add-Type -TypeDefinition $code -Language CSharp
[Test]::Main("")
~~~

### C#をコンパイルした実行ファイルを作成
C#からPowershellでexeを作成。

~~~powershell
$exeName = "test.exe"
$exeFullPath = ($PSScriptRoot + "\" + $exeName)

$code = @"
using System;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

public static class Test {
    private static int numThreads = 1;
    
    public static void Main(string[] args) {
        Console.WriteLine("NamedPipe Test (s: server, c: client)");
        
        var sorc = Console.ReadLine();
        
        if(sorc == "c") {
            CreateClientTask("pipe1").Wait();
        }
        if(sorc == "s") {
            CreatePipeServerTask("pipe1").Wait();
        }
    }
    
    public static Task CreatePipeServerTask(string pipeName) {
        return Task.Run(() => {
            NamedPipeServerStream pipeServer = null;
            
            while(true) {
                try {
                    pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, numThreads);
                    pipeServer.WaitForConnection();
                    StreamString ss = new StreamString(pipeServer);
                    
                    while (true)
                    {
                        var read = ss.ReadString();
                        var write = ss.WriteString("Server read OK.");
                        Console.WriteLine("Read Data = " + read);

                        if (read == "end") break;
                    }
                    
                }
                catch(OverflowException ofex) {
                    Console.WriteLine(ofex.Message);
                }
                finally {
                    pipeServer.Close();
                }
            }
        });
    }
    
    public static Task CreateClientTask(string pipeName){
        return Task.Run(() => {
            while (true) {
                NamedPipeClientStream pipeClient = null;

                try {
                    pipeClient = new NamedPipeClientStream(".", pipeName, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Impersonation);
                    pipeClient.Connect();
                    var ss = new StreamString(pipeClient);

                    while (true) {
                        var writeData = Console.ReadLine();
                        var write = ss.WriteString(writeData);
                        var read = ss.ReadString();
                        Console.WriteLine("Server Response = " + read);

                        if (writeData == "end") break;
                    }
                }
                catch (OverflowException ofex) {
                    Console.WriteLine(ofex.Message);
                }
                catch (IOException ioe) {
                    Console.WriteLine(ioe.Message);
                }
                finally {
                    pipeClient.Close();
                }
            }
        });
    }
}

public class StreamString
{
    private Stream ioStream;
    private UnicodeEncoding streamEncoding;

    public StreamString(Stream ioStream)
    {
        this.ioStream = ioStream;
        streamEncoding = new UnicodeEncoding();
    }

    public string ReadString()
    {
        int len = 0;

        len = ioStream.ReadByte() * 256;
        len += ioStream.ReadByte();
        byte[] inBuffer = new byte[len];
        ioStream.Read(inBuffer, 0, len);

        return streamEncoding.GetString(inBuffer);
    }

    public int WriteString(string outString)
    {
        byte[] outBuffer = streamEncoding.GetBytes(outString);
        int len = outBuffer.Length;
        if (len > UInt16.MaxValue)
        {
            len = (int)UInt16.MaxValue;
        }
        ioStream.WriteByte((byte)(len / 256));
        ioStream.WriteByte((byte)(len & 255));
        ioStream.Write(outBuffer, 0, len);
        ioStream.Flush();

        return outBuffer.Length + 2;
    }
}
"@

Add-Type -TypeDefinition $code -Language CSharp -OutputAssembly $exeFullPath -OutputType ConsoleApplication

~~~