<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>System Administration on kenji.blog</title><link>http://kenji.blog/ko/categories/system-administration/</link><description>Recent content in System Administration on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ko</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ko/categories/system-administration/index.xml" rel="self" type="application/rss+xml"/><item><title>PowerShell과 C++ 연동: 시스템 관리 자동화 테크닉</title><link>http://kenji.blog/ko/p/powershell-cpp-system-automation/</link><pubDate>Sat, 12 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/ko/p/powershell-cpp-system-automation/</guid><description>&lt;img src="http://kenji.blog/p/powershell-cpp-system-automation/img/eyecatch.jpg" alt="Featured image of post PowerShell과 C++ 연동: 시스템 관리 자동화 테크닉" />&lt;h2 id="시작하며">시작하며
&lt;/h2>&lt;p>Windows 시스템 관리 및 자동화에 있어 PowerShell은 사실상 표준 도구가 되었습니다. Active Directory 관리, 파일 시스템 조작, 네트워크 구성 변경 등 모든 작업을 스크립트로 작성할 수 있습니다. 그러나 PowerShell이 만능인 한편, 스크립트 언어 특유의 성능 한계나 매우 낮은 수준의 Windows API에 접근하는 데 어려움을 겪는 상황이 존재합니다.&lt;/p>
&lt;p>여기서 강력한 해결책이 되는 것이 &amp;lsquo;C++과의 연동&amp;rsquo;입니다. C++은 네이티브 실행 속도와 Win32 API 및 COM 객체에 대한 완전한 접근을 제공합니다. PowerShell의 &amp;lsquo;높은 생산성·유연성&amp;rsquo;과 C++의 &amp;lsquo;압도적인 성능·로우 레벨 제어&amp;rsquo;를 결합함으로써, 엔터프라이즈 환경에서의 매우 복잡하고 대규모인 시스템 관리 작업을 최적화하는 것이 가능해집니다.&lt;/p>
&lt;p>이 글에서는 PowerShell과 C++를 양방향으로 연동하기 위한 구체적인 아키텍처, 구현 기법, 그리고 메모리 관리 및 문자열 변환의 베스트 프랙티스에 대해 매우 상세하게 해설합니다.&lt;/p>
&lt;h2 id="왜-powershell과-c를-연동하는가">왜 PowerShell과 C++를 연동하는가?
&lt;/h2>&lt;h3 id="1-성능의-한계-돌파">1. 성능의 한계 돌파
&lt;/h3>&lt;p>PowerShell은 .NET Framework(또는 .NET Core / .NET) 상에서 동작하는 인터프리터형·동적 타이핑 언어 요소를 가집니다. 그렇기 때문에 대량의 텍스트 처리나 복잡한 암호화 처리, 또는 수백만 줄에 달하는 이벤트 로그 분석 등을 수행할 때 실행 속도나 메모리 소비량이 병목이 될 수 있습니다.&lt;/p>
&lt;p>계산량과 처리 시간 모델을 생각해 봅시다. 전체 작업의 처리 시간을 $T_{total}$ 이라고 했을 때, PowerShell 단독 처리와 C++로 오프로드했을 경우의 처리 시간은 다음과 같이 공식화할 수 있습니다.&lt;/p>
$$ T_{total}^{(PS)} = N \times (t_{overhead} + t_{compute}^{(PS)}) $$$$ T_{total}^{(C++)} = t_{interop} + N \times t_{compute}^{(C++)} $$&lt;p>여기서 $N$ 은 처리할 요소의 수, $t_{overhead}$ 는 PowerShell의 루프 처리에 따른 오버헤드, $t_{compute}$ 는 1요소당 순수한 계산 시간, $t_{interop}$ 은 P/Invoke 등에 의한 경계 호출 오버헤드입니다.&lt;/p>
&lt;p>$N$ 이 충분히 클 경우, $t_{overhead} \gg 0$ 이고 $t_{compute}^{(PS)} > t_{compute}^{(C++)}$ 이기 때문에, 초기의 $t_{interop}$ 을 지불하더라도 C++에 처리를 위임(오프로드)하는 편이 전체 대기 시간(레이턴시)을 극적으로 낮출 수 있습니다.&lt;/p>
&lt;h3 id="2-네이티브-win32-api에-대한-접근">2. 네이티브 Win32 API에 대한 접근
&lt;/h3>&lt;p>PowerShell 단독으로도 &lt;code>Add-Type&lt;/code>을 사용하여 C#을 통해 Win32 API를 호출하는 것은 가능하지만, 복잡한 구조체나 콜백 함수를 동반하는 API(예: 미니 필터 드라이버 제어, 고도의 프로세스 메모리 조작)를 직접 C# / PowerShell로 정의하는 것은 매우 어렵습니다. C++로 래핑한 네이티브 DLL을 생성하고 이를 PowerShell에서 호출함으로써, 타입에 안전하고 확실한 시스템 제어가 가능해집니다.&lt;/p>
&lt;h2 id="powershell에서-c-네이티브-dll-호출하기">PowerShell에서 C++ 네이티브 DLL 호출하기
&lt;/h2>&lt;p>가장 일반적인 연동 패턴은 무거운 처리나 시스템 고유의 처리를 C++ DLL로 구현하고, 이를 PowerShell 스크립트에서 호출하는 방법입니다.&lt;/p>
&lt;h3 id="c-측의-dll-구현-win32-api-및-커스텀-로직">C++ 측의 DLL 구현 (Win32 API 및 커스텀 로직)
&lt;/h3>&lt;p>먼저, PowerShell에서 호출할 수 있는 익스포트 함수를 가진 C++ DLL을 생성합니다. 여기서는 예시로 &amp;lsquo;대규모 문자열 데이터의 암호화·복호화, 또는 복잡한 해시 계산을 수행하는 함수&amp;rsquo;를 가정한 간단한 C++ 코드를 보여줍니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// NativeLib.cpp
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// P/Invoke로 호출하기 쉽도록 C 링키지와 __stdcall 지정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">extern&lt;/span> &lt;span class="s">&amp;#34;C&amp;#34;&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kr">__declspec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dllexport&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="kr">__stdcall&lt;/span> &lt;span class="n">ComputeHeavyTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">multiplier&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">dataSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 의도적인 무거운 처리 시뮬레이션
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">for&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="kt">int&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="n">i&lt;/span> &lt;span class="o">&amp;lt;&lt;/span> &lt;span class="n">dataSize&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="o">++&lt;/span>&lt;span class="n">i&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">result&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">i&lt;/span> &lt;span class="o">%&lt;/span> &lt;span class="n">multiplier&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 문자열을 처리하는 함수 (유니코드 지원을 위해 LPWSTR 사용)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kr">__declspec&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">dllexport&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="kr">__stdcall&lt;/span> &lt;span class="n">ProcessSystemString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">LPCWSTR&lt;/span> &lt;span class="n">inputString&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">LPWSTR&lt;/span> &lt;span class="n">outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="n">bufferSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">inputString&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">outputBuffer&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">inputString&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 어떠한 복잡한 문자열 처리 (예: 시스템 식별자 부여)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">wstring&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;PROCESSED_&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">size_t&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="n">bufferSize&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">false&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 버퍼 오버런 방지
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">wcscpy_s&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">bufferSize&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">c_str&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nb">true&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="메모리-관리와-문자열-변환-bstr-lpwstr">메모리 관리와 문자열 변환 (&lt;code>BSTR&lt;/code>, &lt;code>LPWSTR&lt;/code>)
&lt;/h3>&lt;p>C++와 PowerShell(.NET) 간에 데이터를 주고받을 때 가장 주의해야 할 점은 &lt;strong>문자열 인코딩&lt;/strong>과 &lt;strong>메모리 관리&lt;/strong>입니다.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>LPCWSTR&lt;/code> / &lt;code>LPWSTR&lt;/code>&lt;/strong>: C/C++의 와이드 문자열 포인터(UTF-16LE). Windows API의 &lt;code>W&lt;/code> 계열 함수에서 표준으로 사용됩니다. P/Invoke에서는 &lt;code>CharSet = CharSet.Unicode&lt;/code>를 지정함으로써 .NET의 &lt;code>String&lt;/code>이나 &lt;code>StringBuilder&lt;/code>와 자동으로 마샬링됩니다.&lt;/li>
&lt;li>&lt;strong>&lt;code>BSTR&lt;/code>&lt;/strong>: COM(Component Object Model)에서 사용되는 길이 접두사가 있는 와이드 문자열. &lt;code>SysAllocString&lt;/code>이나 &lt;code>SysFreeString&lt;/code>으로 메모리를 관리해야 합니다. P/Invoke에서 &lt;code>[MarshalAs(UnmanagedType.BStr)]&lt;/code>를 지정합니다.&lt;/li>
&lt;/ul>
&lt;p>C++ 측에서 새로 메모리를 할당하여 PowerShell 측에 반환할 경우, 누가 메모리를 해제할 것인가(소유권)가 문제가 됩니다. 앞서 살펴본 &lt;code>ProcessSystemString&lt;/code> 함수에서는 &amp;lsquo;호출자(PowerShell)가 사전에 할당한 버퍼(&lt;code>outputBuffer&lt;/code>)에 C++이 결과를 기록한다&amp;rsquo;라는 Win32 API의 표준적인 패턴을 채택하고 있습니다. 이를 통해 메모리 누수를 방지할 수 있습니다.&lt;/p>
&lt;h3 id="powershell-측의-add-type과-pinvoke">PowerShell 측의 &lt;code>Add-Type&lt;/code>과 P/Invoke
&lt;/h3>&lt;p>C++ DLL(&lt;code>NativeLib.dll&lt;/code>)을 컴파일했다면, PowerShell 스크립트에서 이를 호출합니다. C#의 P/Invoke 시그니처를 &lt;code>Add-Type&lt;/code>으로 동적 컴파일하여 이용합니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-powershell" data-lang="powershell">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># PowerShell Script: Invoke-NativeDLL.ps1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$signature&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="sh">@&amp;#39;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System.Runtime.InteropServices;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">using System.Text;
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">public class NativeInterop
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> // C++의 ComputeHeavyTask를 정의
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> [DllImport(&amp;#34;NativeLib.dll&amp;#34;, CallingConvention = CallingConvention.StdCall)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> public static extern int ComputeHeavyTask(int multiplier, int dataSize);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> // C++의 ProcessSystemString을 정의
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> [DllImport(&amp;#34;NativeLib.dll&amp;#34;, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh"> public static extern bool ProcessSystemString(string inputString, StringBuilder outputBuffer, int bufferSize);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="sh">&amp;#39;@&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># C# 코드를 PowerShell 세션에 컴파일하여 추가&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Add-Type&lt;/span> &lt;span class="n">-TypeDefinition&lt;/span> &lt;span class="nv">$signature&lt;/span> &lt;span class="n">-PassThru&lt;/span> &lt;span class="p">|&lt;/span> &lt;span class="nb">Out-Null&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 1. 무거운 수치 계산 호출&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$result&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">NativeInterop&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ComputeHeavyTask&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mf">7&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mf">100000000&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Compute Task Result: &lt;/span>&lt;span class="nv">$result&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># 2. 문자열 처리 호출&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$input&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s2">&amp;#34;SYSTEM_NODE_001&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$bufferSize&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mf">256&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># C++ 측에 기록하게 하기 위한 버퍼로서 StringBuilder를 사용&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$outputBuffer&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">New-Object&lt;/span> &lt;span class="n">System&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">Text&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">StringBuilder&lt;/span> &lt;span class="n">-ArgumentList&lt;/span> &lt;span class="nv">$bufferSize&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nv">$success&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="no">NativeInterop&lt;/span>&lt;span class="p">]::&lt;/span>&lt;span class="n">ProcessSystemString&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nv">$input&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$outputBuffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nv">$bufferSize&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nv">$success&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;Processed String: &lt;/span>&lt;span class="p">$(&lt;/span>&lt;span class="nv">$outputBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="py">ToString&lt;/span>&lt;span class="p">())&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nb">Write-Host&lt;/span> &lt;span class="s2">&amp;#34;String processing failed.&amp;#34;&lt;/span> &lt;span class="n">-ForegroundColor&lt;/span> &lt;span class="n">Red&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="아키텍처-시각화">아키텍처 시각화
&lt;/h3>&lt;p>다음 시퀀스 다이어그램은 PowerShell에서 C++ DLL로의 호출 흐름과 메모리 교환을 보여줍니다.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant PS as &amp;#34;PowerShell 스크립트&amp;#34;
participant CLR as &amp;#34;.NET CLR (P/Invoke)&amp;#34;
participant CPP as &amp;#34;C++ 네이티브 DLL&amp;#34;
PS-&amp;gt;&amp;gt;CLR: &amp;#34;ProcessSystemString 호출&amp;#34;
note right of CLR: &amp;#34;System.String을 LPCWSTR로 마샬링&amp;#34;
note right of CLR: &amp;#34;StringBuilder 참조 전달&amp;#34;
CLR-&amp;gt;&amp;gt;CPP: &amp;#34;ProcessSystemString(LPCWSTR, LPWSTR, int)&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;네이티브 문자열 조작 실행&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;LPWSTR 버퍼에 결과 기록&amp;#34;
CPP--&amp;gt;&amp;gt;CLR: &amp;#34;bool 반환 (성공)&amp;#34;
note left of CLR: &amp;#34;수정된 StringBuilder 버퍼 읽기&amp;#34;
CLR--&amp;gt;&amp;gt;PS: &amp;#34;실행 제어 반환&amp;#34;
PS-&amp;gt;&amp;gt;PS: &amp;#34;처리된 문자열 출력&amp;#34;
&lt;/pre>
&lt;h2 id="c에서-powershell-호출하기">C++에서 PowerShell 호출하기
&lt;/h2>&lt;p>이번에는 반대의 접근입니다. C++로 만들어진 시스템 서비스나 데스크톱 애플리케이션에서 PowerShell 스크립트를 동적으로 실행하고 그 결과를 얻고 싶은 경우가 있습니다. 예를 들어, C++ 모니터링 에이전트가 특정 이상을 감지했을 때 PowerShell의 복구 스크립트를 실행하는 시나리오입니다.&lt;/p>
&lt;p>접근 방식은 주로 두 가지가 있습니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>프로세스 기동 (&lt;code>CreateProcess&lt;/code> / &lt;code>_popen&lt;/code>)&lt;/strong>: 독립된 프로세스로 &lt;code>powershell.exe&lt;/code>를 실행하고 표준 입출력을 파이프로 연결하는 방법.&lt;/li>
&lt;li>&lt;strong>PowerShell Hosting API (C++/CLI 경유)&lt;/strong>: 동일 프로세스 내에서 PowerShell 런타임을 호스팅하는 방법.&lt;/li>
&lt;/ol>
&lt;p>이 글에서는 시스템 프로그래밍에 있어 가장 견고하고 범용적인 &lt;strong>파이프라인을 사용한 CreateProcess&lt;/strong> 기법을 해설합니다.&lt;/p>
&lt;h3 id="createprocess와-익명-파이프를-이용한-실행">CreateProcess와 익명 파이프를 이용한 실행
&lt;/h3>&lt;p>다음 C++ 코드는 익명 파이프(Anonymous Pipes)를 생성하고 자식 프로세스로 &lt;code>powershell.exe&lt;/code>를 실행하여 스크립트를 실행한 후, 표준 출력에서 결과를 읽어옵니다.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;windows.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">ExecutePowerShellScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">script&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HANDLE&lt;/span> &lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SECURITY_ATTRIBUTES&lt;/span> &lt;span class="n">sa&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nLength&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">SECURITY_ATTRIBUTES&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">bInheritHandle&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 파이프 핸들을 자식 프로세스에 상속시킴
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">sa&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lpSecurityDescriptor&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 1. 파이프 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">CreatePipe&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">sa&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;Error: CreatePipe failed.&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 2. 자식 프로세스(PowerShell)의 시작 정보 설정
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">STARTUPINFOA&lt;/span> &lt;span class="n">si&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ZeroMemory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">si&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">STARTUPINFOA&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">cb&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">STARTUPINFOA&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">dwFlags&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">STARTF_USESTDHANDLES&lt;/span> &lt;span class="o">|&lt;/span> &lt;span class="n">STARTF_USESHOWWINDOW&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hStdOutput&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hStdError&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">si&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">wShowWindow&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">SW_HIDE&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 창 숨기기
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">PROCESS_INFORMATION&lt;/span> &lt;span class="n">pi&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ZeroMemory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">PROCESS_INFORMATION&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 명령줄 구성 (Bypass 정책으로 Base64 인코딩 등을 피하는 간략화 버전)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">cmd&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;powershell.exe -NoProfile -NonInteractive -Command &lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">script&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\&amp;#34;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">char&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">begin&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">cmd&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">end&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 3. 프로세스 생성
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">CreateProcessA&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">cmdBuffer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">TRUE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">si&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="s">&amp;#34;Error: CreateProcess failed.&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 부모 프로세스 측에서는 쓰기 파이프가 불필요하므로 닫음 (닫지 않으면 Read가 블로킹됨)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hWritePipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 4. 결과 읽기
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">output&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">DWORD&lt;/span> &lt;span class="n">bytesRead&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">4096&lt;/span>&lt;span class="p">];&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ReadFile&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="k">sizeof&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">buffer&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">bytesRead&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nb">NULL&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">bytesRead&lt;/span> &lt;span class="o">&amp;gt;&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">buffer&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">bytesRead&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="sc">&amp;#39;\0&amp;#39;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">output&lt;/span> &lt;span class="o">+=&lt;/span> &lt;span class="n">buffer&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 5. 정리(클린업)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">WaitForSingleObject&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hProcess&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">INFINITE&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hProcess&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">pi&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">hThread&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">CloseHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hReadPipe&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">output&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// PowerShell에서 프로세스 목록을 가져와 CPU 사용률로 정렬하는 명령
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">psCommand&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s">&amp;#34;Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 | Format-Table Name, CPU, Id&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Executing PowerShell from C++...&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">ExecutePowerShellScript&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">psCommand&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Result:&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="windows-레지스트리와-powershell의-연동">Windows 레지스트리와 PowerShell의 연동
&lt;/h3>&lt;p>C++에서 스크립트를 실행할 때, 동적인 설정 값이나 실행 경로를 하드코딩하는 것은 피해야 합니다. 많은 경우, C++ 애플리케이션은 설정을 &lt;strong>Windows 레지스트리&lt;/strong>에서 읽어옵니다.&lt;/p>
&lt;p>C++ 측에서 &lt;code>RegOpenKeyEx&lt;/code>와 &lt;code>RegQueryValueEx&lt;/code>를 사용하여 &lt;code>HKLM\SOFTWARE\MyApp&lt;/code>으로부터 PowerShell 스크립트의 경로를 가져오고, 이를 인수로 앞서 설명한 &lt;code>CreateProcess&lt;/code>에 전달하는 아키텍처가 엔터프라이즈 시스템에서 선호됩니다.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;C++ 에이전트 서비스&amp;#34;] --&amp;gt;|RegQueryValueEx| B[&amp;#34;Windows 레지스트리&amp;#34;]
B --&amp;gt;|스크립트 경로 반환| A
A --&amp;gt;|CreateProcess| C[&amp;#34;powershell.exe&amp;#34;]
C --&amp;gt;|실행| D[&amp;#34;관리자 스크립트 (예: Restart-Service)&amp;#34;]
D --&amp;gt;|파이프를 통한 stdout| C
C --&amp;gt;|ReadFile| A
A --&amp;gt;|로그 기록| E[&amp;#34;이벤트 뷰어 / 로그 파일&amp;#34;]
&lt;/pre>
&lt;h2 id="성능-분석과-오프로드의-이점">성능 분석과 오프로드의 이점
&lt;/h2>&lt;p>왜 이러한 복잡한 아키텍처를 채택하는 것일까요? 구체적인 시나리오로 &amp;lsquo;수 기가바이트에 달하는 커스텀 IIS 로그 파일 분석&amp;rsquo;을 생각해 봅니다.&lt;/p>
&lt;p>PowerShell에서 &lt;code>Get-Content&lt;/code>를 사용하고 정규식을 이용해 한 줄씩 파싱할 경우, 객체 생성과 가비지 컬렉션(GC)의 오버헤드로 인해 CPU 시간을 대량으로 소비합니다.&lt;/p>
&lt;p>메모리 할당 횟수 $A$ 와 GC의 트리거 횟수 $G$ 는 스크립트 실행에 있어 다음과 같이 비례합니다.&lt;/p>
$$ G \propto \sum_{i=1}^{N} A_i $$&lt;p>C++ 네이티브 코드로 처리를 이관할 경우, 메모리 매핑(&lt;code>CreateFileMapping&lt;/code>, &lt;code>MapViewOfFile&lt;/code>)을 사용하여 파일 전체를 직접 메모리에 전개하고, 포인터 연산을 통해 제로 카피(Zero-copy)로 문자열 탐색을 수행할 수 있습니다. 이 경우 객체 생성에 따른 오버헤드는 사실상 제로가 되며, 이론적인 메모리 대역폭의 상한에 가까운 속도로 파싱이 완료됩니다.&lt;/p>
&lt;p>파싱한 결과(예: 부정 접근 IP 주소 목록 등)만을 PowerShell 측에 반환함으로써, P/Invoke의 마샬링 비용도 최소한으로 억제할 수 있습니다.&lt;/p>
&lt;h2 id="실천적인-시스템-관리-자동화-시나리오">실천적인 시스템 관리 자동화 시나리오
&lt;/h2>&lt;h3 id="시나리오-1-고속-파일-시스템-스캔-및-권한-변경">시나리오 1: 고속 파일 시스템 스캔 및 권한 변경
&lt;/h3>&lt;p>대규모 파일 서버에서 특정 확장자를 가진 파일 중 특정 ACL(접근 제어 목록)이 설정된 것을 추출하여 일괄적으로 권한을 변경하는 작업.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>C++의 역할&lt;/strong>: &lt;code>FindFirstFile&lt;/code> / &lt;code>FindNextFile&lt;/code> 및 멀티스레딩을 사용하여 초고속으로 디렉토리 트리를 순회하고, 조건에 일치하는 파일 경로 목록을 생성.&lt;/li>
&lt;li>&lt;strong>PowerShell의 역할&lt;/strong>: C++로부터 받은 목록에 대해 &lt;code>Set-Acl&lt;/code>을 사용하여 일괄적으로 권한을 적용(또는 Active Directory와 연동된 처리).&lt;/li>
&lt;/ul>
&lt;h3 id="시나리오-2-독자적인-하드웨어-정보-수집">시나리오 2: 독자적인 하드웨어 정보 수집
&lt;/h3>&lt;p>WMI(Windows Management Instrumentation)나 CIM(Common Information Model)으로는 얻을 수 없는 독자적인 하드웨어 장치(예: 특수한 PCIe 카드나 센서)의 정보를 모니터링한다.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>C++의 역할&lt;/strong>: 장치 드라이버에 대해 &lt;code>DeviceIoControl&lt;/code>을 호출하여 바이너리 데이터를 획득·분석하는 DLL.&lt;/li>
&lt;li>&lt;strong>PowerShell의 역할&lt;/strong>: 정기적으로 DLL을 호출하고, 분석 결과를 JSON으로 포맷하여 모니터링 서버의 REST API로 전송한다.&lt;/li>
&lt;/ul>
&lt;h2 id="메모리-관리와-트러블슈팅의-베스트-프랙티스">메모리 관리와 트러블슈팅의 베스트 프랙티스
&lt;/h2>&lt;p>연동에 있어 가장 많이 발생하는 버그는 &lt;strong>메모리 누수&lt;/strong>와 **접근 위반(Access Violation: 0xC0000005)**입니다.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>포인터의 유효 기간&lt;/strong>: PowerShell 측에서 &lt;code>[ref]&lt;/code>나 &lt;code>StringBuilder&lt;/code>를 전달할 경우, P/Invoke는 호출 중에만 그 메모리를 고정(Pin)합니다. C++ 측에서 그 포인터를 전역 변수에 저장하고 나중에 접근해서는 안 됩니다. 비동기 콜백을 수행할 경우에는 &lt;code>GCHandle&lt;/code>을 사용하여 명시적으로 메모리를 고정할 필요가 있습니다.&lt;/li>
&lt;li>&lt;strong>64bit 환경의 포인터 크기&lt;/strong>: 현대의 Windows는 64bit(x64)가 기본입니다. C++ 측에서의 포인터 크기는 8바이트이며, PowerShell(.NET) 측에서는 &lt;code>IntPtr&lt;/code>을 사용해야 합니다. C++의 &lt;code>long&lt;/code>은 Windows에서 4바이트이므로, 포인터를 &lt;code>long&lt;/code>으로 캐스팅하여 전달하는 낡은 코드는 크래시의 원인이 됩니다.&lt;/li>
&lt;li>&lt;strong>문자열 인코딩의 불일치&lt;/strong>: PowerShell은 내부적으로 UTF-16을 사용합니다. C++ 측에서 ANSI 문자열(&lt;code>std::string&lt;/code>, &lt;code>char*&lt;/code>)로 받으려고 하면 글자 깨짐이 발생합니다. 반드시 와이드 문자열(&lt;code>std::wstring&lt;/code>, &lt;code>wchar_t*&lt;/code>)을 사용하고, P/Invoke 측에서도 &lt;code>CharSet = CharSet.Unicode&lt;/code>를 지정해 주세요.&lt;/li>
&lt;/ol>
&lt;h2 id="요약">요약
&lt;/h2>&lt;p>PowerShell과 C++의 연동은 시스템 관리 자동화에 있어 스크립트 언어의 편리함과 네이티브 언어의 강력함을 양립시키는 최강의 조합입니다.&lt;/p>
&lt;p>P/Invoke를 이용한 C++ DLL 호출을 통해 계산 부하가 높은 작업을 오프로드하여 실행 시간을 극적으로 단축할 수 있습니다. 반대로 C++ 애플리케이션에서 프로세스 기동이나 파이프라인을 통해 PowerShell의 풍부한 시스템 관리 모듈을 활용함으로써 개발 비용을 대폭 절감할 수 있습니다.&lt;/p>
&lt;p>경계 부분에서의 메모리 관리나 문자열 변환에는 주의가 필요하지만, 이 글에서 소개한 아키텍처 패턴과 구현 테크닉을 마스터함으로써 보다 고도화되고 견고한 Windows 시스템 관리 도구를 구축할 수 있게 될 것입니다.&lt;/p>
&lt;hr>
&lt;p>&lt;em>이 기술 블로그에서는 앞으로도 Windows 내부 구조나 고도화된 자동화와 관련된 깊이 있는 주제를 다룰 예정입니다. 질문이나 피드백이 있으시다면 꼭 댓글란에 남겨주세요.&lt;/em>&lt;/p></description></item></channel></rss>