배치 파일에 C# 코드 포함 실행

배치 파일 내에서 powershell을 통해 C# 코드를 실행하는 기사는 이미 몇 가지 존재하지만, 1 파일에서 배치 파일 부분과 C# 코드 부분이 깨끗하게 나뉘어있는 것을 찾을 수 없었기 때문에 더 가독성과 유지 보수 성 향상을 목표로 작성해 보았습니다.

코드



RunCSCode.bat
@echo off
setlocal
set BAT_PATH=%~f0
powershell -NoProfile -Command "& {$cscode=[regex]::Split([IO.File]::ReadAllText($env:BAT_PATH,[Text.Encoding]::UTF8),':EndBatch')[2]; Add-Type -TypeDefinition $cscode -Language CSharpVersion3; [CSBatch.Program]::Main($Args);}" %*
endlocal
exit /b

:EndBatch

//CSCode
using System;
using System.Runtime.InteropServices;

namespace CSBatch
{
    public class Program
    {
        [DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        private static extern int MessageBox(IntPtr hWnd, string text, string caption, int options);

        public static int Main(string[] args)
        {
            string msg = "";
            for( int i=0; i<args.Length; i++)
            {
                msg += String.Format("args[{0}]={1}\r\n", i, args[i]);
            }
            if( msg=="" )
            {
                msg = "no args.";
            }

            int MB_OK = 0;
            MessageBox(IntPtr.Zero, msg, "CSTestCode", MB_OK);
            return args.Length;
        }
    }
}

실행 결과


>RunCSCode.bat あああ いいい ううう
3



작동 원리



1. 일반 배치 파일로 시작
2. 환경 변수에 배치 파일 자신의 경로를 저장 (직접 powershell 명령에 임베드해도 좋을지도)
3. (powershell 명령) 배치 파일 자체를 File.ReadAllText에서 utf-8 string 데이터로로드
4. (powershell 명령) Regex.Split을 사용하여 string 데이터를 :EndBatch 레이블로 분할하고 C# 코드 부분을 분리
5. (powershell 명령) 분리 된 C# 코드 부분을 Add-Type으로 형식 추가하고 C# 메서드를 실행
6. powershell에서 C# 메소드 실행 종료 후 exit/b 로 배치 파일 종료.
(이것에 의해, 이후의 C# 코드부의 영향을 받지 않게 된다)

주의) 배치 파일을 읽을 때 utf-8 인코딩을 지정했지만 BOM 없이 utf-8로 배치 파일을 저장하지 않으면 런타임에 쓰레기가 붙습니다.

MessageBox.Show가 아니라 WinAPI의 MessageBox 사용하고 있는 것은, WinAPI도 호출할 수 있다고 하는 것을 보여주고 싶었을 뿐입니다. 음 C#이므로 할 수 있어 당연합니다만…
뭔가 여러가지 재미있는 일(위험한 일이라고도 함) 할 수 있을 것 같네요.

참고 기사



배치 파일에 C# 코드 작성
배치 파일에서 ps1 파일에 작성한 C# 코드를 호출하여 만족한 후 이 기사를 보고 눈에서 비늘이 떨어졌습니다.

좋은 웹페이지 즐겨찾기