<?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/en/categories/system-administration/</link><description>Recent content in System Administration on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/en/categories/system-administration/index.xml" rel="self" type="application/rss+xml"/><item><title>PowerShell and C++ Integration: System Administration Automation Techniques</title><link>http://kenji.blog/en/p/powershell-cpp-system-automation/</link><pubDate>Sat, 12 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/en/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 and C++ Integration: System Administration Automation Techniques" />&lt;h2 id="introduction">Introduction
&lt;/h2>&lt;p>In Windows system administration and automation, PowerShell has become the de facto standard tool. You can script almost any task, such as managing Active Directory, manipulating the file system, or changing network configurations. However, while PowerShell is versatile, there are situations where you may struggle with the performance limitations typical of scripting languages or with accessing very low-level Windows APIs.&lt;/p>
&lt;p>This is where &amp;ldquo;integration with C++&amp;rdquo; becomes a powerful solution. C++ offers native execution speed and full access to Win32 APIs and COM objects. By combining PowerShell&amp;rsquo;s &amp;ldquo;high productivity and flexibility&amp;rdquo; with C++&amp;rsquo;s &amp;ldquo;overwhelming performance and low-level control&amp;rdquo;, it becomes possible to optimize extremely complex and large-scale system administration tasks in enterprise environments.&lt;/p>
&lt;p>In this article, we will explain in great detail the specific architectures, implementation techniques, and best practices for memory management and string conversion to integrate PowerShell and C++ bidirectionally.&lt;/p>
&lt;h2 id="why-integrate-powershell-and-c">Why Integrate PowerShell and C++?
&lt;/h2>&lt;h3 id="1-breaking-through-performance-limits">1. Breaking Through Performance Limits
&lt;/h3>&lt;p>PowerShell has interpreter-based and dynamically typed language elements running on the .NET Framework (or .NET Core / .NET). Because of this, execution speed and memory consumption can become bottlenecks when processing large amounts of text, performing complex cryptographic operations, or parsing event logs that span millions of lines.&lt;/p>
&lt;p>Let&amp;rsquo;s consider a model of computational complexity and processing time. Assuming the total processing time for a task is $T_{total}$, the processing time for PowerShell alone and the processing time when offloaded to C++ can be formulated as follows.&lt;/p>
$$ T_{total}^{(PS)} = N \times (t_{overhead} + t_{compute}^{(PS)}) $$$$ T_{total}^{(C++)} = t_{interop} + N \times t_{compute}^{(C++)} $$&lt;p>Here, $N$ is the number of elements to process, $t_{overhead}$ is the overhead associated with PowerShell loop processing, $t_{compute}$ is the pure computation time per element, and $t_{interop}$ is the boundary call overhead due to P/Invoke, etc.&lt;/p>
&lt;p>When $N$ is sufficiently large, since $t_{overhead} \gg 0$ and $t_{compute}^{(PS)} > t_{compute}^{(C++)}$, delegating (offloading) the processing to C++ will dramatically lower the overall latency, even if you have to pay the initial $t_{interop}$.&lt;/p>
&lt;h3 id="2-access-to-native-win32-apis">2. Access to Native Win32 APIs
&lt;/h3>&lt;p>Although it is possible to call Win32 APIs from PowerShell alone via C# using &lt;code>Add-Type&lt;/code>, it is very difficult to define APIs involving complex structures or callback functions (e.g., controlling mini-filter drivers, advanced process memory manipulation) directly in C# / PowerShell. By creating a native DLL wrapped in C++ and calling it from PowerShell, type-safe and reliable system control becomes possible.&lt;/p>
&lt;h2 id="calling-c-native-dlls-from-powershell">Calling C++ Native DLLs from PowerShell
&lt;/h2>&lt;p>The most common integration pattern is to implement heavy processing or system-specific processing as a C++ DLL and call it from a PowerShell script.&lt;/p>
&lt;h3 id="c-dll-implementation-win32-api-and-custom-logic">C++ DLL Implementation (Win32 API and Custom Logic)
&lt;/h3>&lt;p>First, create a C++ DLL with exported functions that can be called from PowerShell. Here, we show simple C++ code assuming &amp;ldquo;functions that perform encryption/decryption of large string data or complex hash calculations&amp;rdquo; as an example.&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">// Specify C linkage and __stdcall for easier calling via P/Invoke
&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">// Simulating intentionally heavy processing
&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">// Function to process strings (using LPWSTR for Unicode support)
&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">// Some complex string processing (e.g., adding a system identifier)
&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">// Prevent buffer overrun
&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="memory-management-and-string-conversion-bstr-lpwstr">Memory Management and String Conversion (&lt;code>BSTR&lt;/code>, &lt;code>LPWSTR&lt;/code>)
&lt;/h3>&lt;p>When exchanging data between C++ and PowerShell (.NET), the most important things to pay attention to are &lt;strong>string encoding&lt;/strong> and &lt;strong>memory management&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>LPCWSTR&lt;/code> / &lt;code>LPWSTR&lt;/code>&lt;/strong>: C/C++ wide string pointers (UTF-16LE). Standardly used in &lt;code>W&lt;/code> variant functions of the Windows API. In P/Invoke, by specifying &lt;code>CharSet = CharSet.Unicode&lt;/code>, they are automatically marshaled to .NET&amp;rsquo;s &lt;code>String&lt;/code> or &lt;code>StringBuilder&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;code>BSTR&lt;/code>&lt;/strong>: A length-prefixed wide string used in COM (Component Object Model). Memory must be managed with &lt;code>SysAllocString&lt;/code> and &lt;code>SysFreeString&lt;/code>. Specify &lt;code>[MarshalAs(UnmanagedType.BStr)]&lt;/code> in P/Invoke.&lt;/li>
&lt;/ul>
&lt;p>When allocating new memory on the C++ side and returning it to the PowerShell side, the issue is who will free the memory (ownership). The &lt;code>ProcessSystemString&lt;/code> function above adopts the standard Win32 API pattern: &amp;ldquo;C++ writes the result to a buffer (&lt;code>outputBuffer&lt;/code>) pre-allocated by the caller (PowerShell)&amp;rdquo;. This prevents memory leaks.&lt;/p>
&lt;h3 id="add-type-and-pinvoke-in-powershell">&lt;code>Add-Type&lt;/code> and P/Invoke in PowerShell
&lt;/h3>&lt;p>Once you have compiled the C++ DLL (&lt;code>NativeLib.dll&lt;/code>), you call it from your PowerShell script. You dynamically compile and use the C# P/Invoke signature with &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"> // Define 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"> // Define 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"># Compile and add the C# code to the PowerShell session&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. Calling the heavy numerical computation&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. Calling the string processing&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"># Using StringBuilder as a buffer for C++ to write into&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="visualizing-the-architecture">Visualizing the Architecture
&lt;/h3>&lt;p>The sequence diagram below shows the call flow and memory exchange from PowerShell to the C++ DLL.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant PS as &amp;#34;PowerShell Script&amp;#34;
participant CLR as &amp;#34;.NET CLR (P/Invoke)&amp;#34;
participant CPP as &amp;#34;C++ Native DLL&amp;#34;
PS-&amp;gt;&amp;gt;CLR: &amp;#34;Invoke ProcessSystemString&amp;#34;
note right of CLR: &amp;#34;Marshal System.String to LPCWSTR&amp;#34;
note right of CLR: &amp;#34;Pass StringBuilder reference&amp;#34;
CLR-&amp;gt;&amp;gt;CPP: &amp;#34;ProcessSystemString(LPCWSTR, LPWSTR, int)&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;Execute native string manipulation&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;Write result to LPWSTR buffer&amp;#34;
CPP--&amp;gt;&amp;gt;CLR: &amp;#34;return bool (Success)&amp;#34;
note left of CLR: &amp;#34;Read modified StringBuilder buffer&amp;#34;
CLR--&amp;gt;&amp;gt;PS: &amp;#34;Return execution control&amp;#34;
PS-&amp;gt;&amp;gt;PS: &amp;#34;Output processed string&amp;#34;
&lt;/pre>
&lt;h2 id="calling-powershell-from-c">Calling PowerShell from C++
&lt;/h2>&lt;p>Now for the reverse approach. You may want to dynamically execute a PowerShell script from a system service or desktop application written in C++ and retrieve its results. For example, a scenario where a C++ monitoring agent detects a specific anomaly and executes a PowerShell remediation script.&lt;/p>
&lt;p>There are two main approaches:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Process Launch (&lt;code>CreateProcess&lt;/code> / &lt;code>_popen&lt;/code>)&lt;/strong>: Launching &lt;code>powershell.exe&lt;/code> as an independent process and connecting standard input/output via pipes.&lt;/li>
&lt;li>&lt;strong>PowerShell Hosting API (via C++/CLI)&lt;/strong>: Hosting the PowerShell runtime within the same process.&lt;/li>
&lt;/ol>
&lt;p>In this article, we will explain the technique of &lt;strong>CreateProcess using pipelines&lt;/strong>, which is the most robust and versatile in system programming.&lt;/p>
&lt;h3 id="execution-via-createprocess-and-anonymous-pipes">Execution via CreateProcess and Anonymous Pipes
&lt;/h3>&lt;p>The following C++ code creates Anonymous Pipes, launches &lt;code>powershell.exe&lt;/code> as a child process to execute a script, and reads the results from standard output.&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">// Allow pipe handles to be inherited by the child process
&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. Create pipes
&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. Set startup information for the child process (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">// Hide the window
&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">// Build the command line (simplified version avoiding Base64 encoding with Bypass policy)
&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. Create the process
&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">// Close the write pipe in the parent process (otherwise Read will block)
&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. Read the results
&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. Cleanup
&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">// Command to get the list of processes in PowerShell and sort them by CPU usage
&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="integration-between-windows-registry-and-powershell">Integration Between Windows Registry and PowerShell
&lt;/h3>&lt;p>When executing scripts from C++, hardcoding dynamic settings or execution paths should be avoided. In many cases, C++ applications read settings from the &lt;strong>Windows Registry&lt;/strong>.&lt;/p>
&lt;p>An architecture where the C++ side uses &lt;code>RegOpenKeyEx&lt;/code> and &lt;code>RegQueryValueEx&lt;/code> to retrieve the PowerShell script path from &lt;code>HKLM\SOFTWARE\MyApp&lt;/code> and passes it as an argument to &lt;code>CreateProcess&lt;/code> above is preferred in enterprise systems.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;C++ Agent Service&amp;#34;] --&amp;gt;|RegQueryValueEx| B[&amp;#34;Windows Registry&amp;#34;]
B --&amp;gt;|Return Script Path| A
A --&amp;gt;|CreateProcess| C[&amp;#34;powershell.exe&amp;#34;]
C --&amp;gt;|Execute| D[&amp;#34;Admin Script (e.g., Restart-Service)&amp;#34;]
D --&amp;gt;|stdout via Pipe| C
C --&amp;gt;|ReadFile| A
A --&amp;gt;|Log| E[&amp;#34;Event Viewer / Log File&amp;#34;]
&lt;/pre>
&lt;h2 id="performance-analysis-and-benefits-of-offloading">Performance Analysis and Benefits of Offloading
&lt;/h2>&lt;p>Why adopt such a complex architecture? As a specific scenario, consider &amp;ldquo;parsing custom IIS log files spanning several gigabytes.&amp;rdquo;&lt;/p>
&lt;p>When parsing line by line using regular expressions with &lt;code>Get-Content&lt;/code> in PowerShell, a massive amount of CPU time is consumed due to object creation and Garbage Collection (GC) overhead.&lt;/p>
&lt;p>The number of memory allocations $A$ and the number of GC triggers $G$ are proportional to the following in script execution.&lt;/p>
$$ G \propto \sum_{i=1}^{N} A_i $$&lt;p>If you transfer the processing to native C++ code, you can use memory mapping (&lt;code>CreateFileMapping&lt;/code>, &lt;code>MapViewOfFile&lt;/code>) to expand the entire file directly into memory and perform string searches with zero-copy using pointer arithmetic. In this case, the overhead associated with object creation becomes effectively zero, and parsing is completed at speeds close to the theoretical limit of memory bandwidth.&lt;/p>
&lt;p>By returning only the parsed results (e.g., a list of IP addresses from unauthorized accesses) to the PowerShell side, P/Invoke marshaling costs can also be minimized.&lt;/p>
&lt;h2 id="practical-system-administration-automation-scenarios">Practical System Administration Automation Scenarios
&lt;/h2>&lt;h3 id="scenario-1-fast-file-system-scanning-and-permission-modification">Scenario 1: Fast File System Scanning and Permission Modification
&lt;/h3>&lt;p>In a large-scale file server, a task to extract files that have a specific extension and a specific ACL (Access Control List) set, and change their permissions in bulk.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Role of C++&lt;/strong>: Use &lt;code>FindFirstFile&lt;/code> / &lt;code>FindNextFile&lt;/code> and multithreading to traverse the directory tree extremely fast and generate a list of file paths that match the conditions.&lt;/li>
&lt;li>&lt;strong>Role of PowerShell&lt;/strong>: Apply permissions in bulk using &lt;code>Set-Acl&lt;/code> (or processing integrated with Active Directory) against the list received from C++.&lt;/li>
&lt;/ul>
&lt;h3 id="scenario-2-collecting-proprietary-hardware-information">Scenario 2: Collecting Proprietary Hardware Information
&lt;/h3>&lt;p>Monitoring information from proprietary hardware devices (e.g., specialized PCIe cards or sensors) that cannot be retrieved via WMI (Windows Management Instrumentation) or CIM (Common Information Model).&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Role of C++&lt;/strong>: A DLL that makes &lt;code>DeviceIoControl&lt;/code> calls to the device driver to retrieve and parse binary data.&lt;/li>
&lt;li>&lt;strong>Role of PowerShell&lt;/strong>: Periodically call the DLL, format the parsing results into JSON, and send it to the monitoring server&amp;rsquo;s REST API.&lt;/li>
&lt;/ul>
&lt;h2 id="best-practices-for-memory-management-and-troubleshooting">Best Practices for Memory Management and Troubleshooting
&lt;/h2>&lt;p>The most common bugs that occur during integration are &lt;strong>memory leaks&lt;/strong> and &lt;strong>Access Violations (0xC0000005)&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Pointer Lifetimes&lt;/strong>: When passing &lt;code>[ref]&lt;/code> or &lt;code>StringBuilder&lt;/code> from the PowerShell side, P/Invoke pins the memory only during the call. Do not save that pointer to a global variable on the C++ side and access it later. When performing asynchronous callbacks, you must explicitly pin the memory using &lt;code>GCHandle&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Pointer Sizes in 64-bit Environments&lt;/strong>: Modern Windows is fundamentally 64-bit (x64). Pointer sizes on the C++ side are 8 bytes, so you must use &lt;code>IntPtr&lt;/code> on the PowerShell (.NET) side. Since a C++ &lt;code>long&lt;/code> is 4 bytes on Windows, old code that casts a pointer to a &lt;code>long&lt;/code> and passes it will cause crashes.&lt;/li>
&lt;li>&lt;strong>String Encoding Mismatches&lt;/strong>: PowerShell uses UTF-16 internally. If you try to receive it as an ANSI string (&lt;code>std::string&lt;/code>, &lt;code>char*&lt;/code>) on the C++ side, garbled characters will occur. Always use wide strings (&lt;code>std::wstring&lt;/code>, &lt;code>wchar_t*&lt;/code>) and ensure you specify &lt;code>CharSet = CharSet.Unicode&lt;/code> on the P/Invoke side as well.&lt;/li>
&lt;/ol>
&lt;h2 id="conclusion">Conclusion
&lt;/h2>&lt;p>The integration of PowerShell and C++ is the most powerful combination in system administration automation, balancing the convenience of a scripting language with the power of a native language.&lt;/p>
&lt;p>By calling C++ DLLs using P/Invoke, you can offload computationally intensive tasks and dramatically reduce execution times. Conversely, by utilizing PowerShell&amp;rsquo;s rich system administration modules from a C++ application via process launching or pipelines, you can significantly reduce development costs.&lt;/p>
&lt;p>Although careful attention is required for memory management and string conversion at the boundaries, by mastering the architectural patterns and implementation techniques introduced in this article, you will be able to build more advanced and robust Windows system administration tools.&lt;/p>
&lt;hr>
&lt;p>&lt;em>In this technical blog, we will continue to cover deep topics related to Windows internal structures and advanced automation. If you have any questions or feedback, please feel free to leave them in the comments section.&lt;/em>&lt;/p></description></item></channel></rss>