<?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/de/categories/system-administration/</link><description>Recent content in System Administration on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 16:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/categories/system-administration/index.xml" rel="self" type="application/rss+xml"/><item><title>Integration von PowerShell und C++: Automatisierungstechniken für die Systemverwaltung</title><link>http://kenji.blog/de/p/powershell-cpp-system-automation/</link><pubDate>Sat, 12 Sep 2026 16:00:00 +0900</pubDate><guid>http://kenji.blog/de/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 Integration von PowerShell und C++: Automatisierungstechniken für die Systemverwaltung" />&lt;h2 id="einführung">Einführung
&lt;/h2>&lt;p>In der Windows-Systemverwaltung und -Automatisierung ist PowerShell zum De-facto-Standardwerkzeug geworden. Alle Aufgaben, wie die Verwaltung von Active Directory, Dateisystemoperationen und die Änderung von Netzwerkkonfigurationen, können mit Skripten beschrieben werden. Obwohl PowerShell vielseitig ist, gibt es jedoch Situationen, in denen man mit den Leistungsgrenzen kämpft, die für Skriptsprachen typisch sind, oder mit dem Zugriff auf sehr tiefgreifende Windows-APIs.&lt;/p>
&lt;p>Eine leistungsstarke Lösung hierfür ist die &amp;ldquo;Integration mit C++&amp;rdquo;. C++ bietet native Ausführungsgeschwindigkeit und vollständigen Zugriff auf Win32-APIs sowie COM-Objekte. Durch die Kombination von PowerShells &amp;ldquo;hoher Produktivität und Flexibilität&amp;rdquo; mit der &amp;ldquo;überwältigenden Leistung und Low-Level-Steuerung&amp;rdquo; von C++ ist es möglich, äußerst komplexe und umfangreiche Systemverwaltungsaufgaben in Unternehmensumgebungen zu optimieren.&lt;/p>
&lt;p>Dieser Artikel erklärt sehr detailliert die spezifischen Architekturen und Implementierungsmethoden für die bidirektionale Integration von PowerShell und C++ sowie Best Practices für Speicherverwaltung und Zeichenfolgenkonvertierung.&lt;/p>
&lt;h2 id="warum-powershell-und-c-integrieren">Warum PowerShell und C++ integrieren?
&lt;/h2>&lt;h3 id="1-überwindung-von-leistungsgrenzen">1. Überwindung von Leistungsgrenzen
&lt;/h3>&lt;p>PowerShell hat interpretierte, dynamisch typisierte Sprachmerkmale, die auf dem .NET Framework (oder .NET Core / .NET) ausgeführt werden. Daher können Ausführungsgeschwindigkeit und Speicherverbrauch bei der massenhaften Textverarbeitung, bei komplexen Verschlüsselungsprozessen oder bei der Analyse von Ereignisprotokollen mit Millionen von Zeilen zu Engpässen werden.&lt;/p>
&lt;p>Betrachten wir ein Modell für Rechenkomplexität und Verarbeitungszeit. Wenn die Gesamtverarbeitungszeit der Aufgabe $T_{total}$ ist, können die Verarbeitungszeiten für PowerShell allein und bei Auslagerung an C++ wie folgt formuliert werden:&lt;/p>
$$ T_{total}^{(PS)} = N \times (t_{overhead} + t_{compute}^{(PS)}) $$$$ T_{total}^{(C++)} = t_{interop} + N \times t_{compute}^{(C++)} $$&lt;p>Hier ist $N$ die Anzahl der zu verarbeitenden Elemente, $t_{overhead}$ der Overhead im Zusammenhang mit der Schleifenverarbeitung in PowerShell, $t_{compute}$ die reine Berechnungszeit pro Element und $t_{interop}$ der Overhead für den Grenzübergangsaufruf (P/Invoke etc.).&lt;/p>
&lt;p>Wenn $N$ groß genug ist, gilt $t_{overhead} \gg 0$ und $t_{compute}^{(PS)} > t_{compute}^{(C++)}$. Daher sinkt die Gesamtlatenz drastisch, wenn man die Verarbeitung an C++ delegiert (auslagert), selbst wenn man den anfänglichen $t_{interop}$ bezahlen muss.&lt;/p>
&lt;h3 id="2-zugriff-auf-native-win32-apis">2. Zugriff auf native Win32-APIs
&lt;/h3>&lt;p>Obwohl es möglich ist, Win32-APIs über C# mit &lt;code>Add-Type&lt;/code> auch in PowerShell allein aufzurufen, ist es äußerst schwierig, APIs mit komplexen Strukturen oder Callback-Funktionen (z. B. die Steuerung von Minifilter-Treibern, fortgeschrittene Prozessspeicher-Manipulationen) direkt in C# / PowerShell zu definieren. Durch das Erstellen einer in C++ gewrappten nativen DLL und deren Aufruf aus PowerShell wird eine typsichere und zuverlässige Systemsteuerung möglich.&lt;/p>
&lt;h2 id="aufrufen-nativer-c-dlls-aus-powershell">Aufrufen nativer C++ DLLs aus PowerShell
&lt;/h2>&lt;p>Das häufigste Integrationsmuster besteht darin, rechenintensive oder systemspezifische Prozesse als C++-DLLs zu implementieren und diese aus PowerShell-Skripten aufzurufen.&lt;/p>
&lt;h3 id="c-dll-implementierung-win32-api-und-benutzerdefinierte-logik">C++ DLL-Implementierung (Win32-API und benutzerdefinierte Logik)
&lt;/h3>&lt;p>Zunächst erstellen wir eine C++-DLL mit Exportfunktionen, die von PowerShell aus aufgerufen werden können. Hier zeigen wir einen einfachen C++-Code, der als Beispiel Funktionen für &amp;ldquo;Ver- und Entschlüsselung von großflächigen String-Daten oder komplexe Hash-Berechnungen&amp;rdquo; annimmt.&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">// Spezifikation von C-Bindung und __stdcall, um den P/Invoke-Aufruf zu erleichtern
&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">// Simulation eines absichtlich schweren Prozesses
&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">// Funktion zur Verarbeitung von Zeichenfolgen (verwendet LPWSTR für Unicode-Unterstützung)
&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">// Irgendeine komplexe String-Verarbeitung (z. B. Hinzufügen einer Systemkennung)
&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">// Verhindert Pufferüberlauf (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="speicherverwaltung-und-zeichenfolgenkonvertierung-bstr-lpwstr">Speicherverwaltung und Zeichenfolgenkonvertierung (&lt;code>BSTR&lt;/code>, &lt;code>LPWSTR&lt;/code>)
&lt;/h3>&lt;p>Beim Datenaustausch zwischen C++ und PowerShell (.NET) sind die &lt;strong>Zeichenfolgenkodierung&lt;/strong> und die &lt;strong>Speicherverwaltung&lt;/strong> die wichtigsten Punkte, auf die man achten muss.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>LPCWSTR&lt;/code> / &lt;code>LPWSTR&lt;/code>&lt;/strong>: Pointer auf C/C++ Wide Strings (UTF-16LE). Sie werden standardmäßig in den &lt;code>W&lt;/code>-Funktionen der Windows-API verwendet. Bei P/Invoke werden sie durch Angabe von &lt;code>CharSet = CharSet.Unicode&lt;/code> automatisch in .NET &lt;code>String&lt;/code> oder &lt;code>StringBuilder&lt;/code> gemarshallt.&lt;/li>
&lt;li>&lt;strong>&lt;code>BSTR&lt;/code>&lt;/strong>: Wide Strings mit Längenpräfix, die in COM (Component Object Model) verwendet werden. Der Speicher muss mit &lt;code>SysAllocString&lt;/code> und &lt;code>SysFreeString&lt;/code> verwaltet werden. In P/Invoke wird &lt;code>[MarshalAs(UnmanagedType.BStr)]&lt;/code> angegeben.&lt;/li>
&lt;/ul>
&lt;p>Wenn auf der C++-Seite neuer Speicher zugewiesen und an PowerShell zurückgegeben wird, stellt sich die Frage, wer den Speicher freigibt (Eigentümerschaft). In der obigen Funktion &lt;code>ProcessSystemString&lt;/code> wird das Standardmuster der Win32-API angewendet: &amp;ldquo;C++ schreibt das Ergebnis in den Puffer (&lt;code>outputBuffer&lt;/code>), den der Aufrufer (PowerShell) zuvor zugewiesen hat&amp;rdquo;. Dies verhindert Speicherlecks.&lt;/p>
&lt;h3 id="add-type-und-pinvoke-auf-der-powershell-seite">&lt;code>Add-Type&lt;/code> und P/Invoke auf der PowerShell-Seite
&lt;/h3>&lt;p>Nach dem Kompilieren der C++-DLL (&lt;code>NativeLib.dll&lt;/code>) rufen wir sie aus dem PowerShell-Skript auf. Wir verwenden &lt;code>Add-Type&lt;/code>, um die C#-P/Invoke-Signatur dynamisch zu kompilieren und zu nutzen.&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"> // Definition der 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"> // Definition der 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"># Kompiliert und fügt den C#-Code in die PowerShell-Sitzung ein&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. Aufruf der schweren numerischen Berechnung&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. Aufruf der String-Verarbeitung&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"># Verwendet StringBuilder als Puffer, damit C++ hineinschreiben kann&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="architekturvisualisierung">Architekturvisualisierung
&lt;/h3>&lt;p>Das folgende Sequenzdiagramm zeigt den Aufruffluss und den Speicheraustausch vom PowerShell-Skript zur C++-DLL.&lt;/p>
&lt;pre class="mermaid">
sequenceDiagram
participant PS as &amp;#34;PowerShell-Skript&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;Rufe ProcessSystemString auf&amp;#34;
note right of CLR: &amp;#34;Marshalle System.String zu LPCWSTR&amp;#34;
note right of CLR: &amp;#34;Übergebe StringBuilder-Referenz&amp;#34;
CLR-&amp;gt;&amp;gt;CPP: &amp;#34;ProcessSystemString(LPCWSTR, LPWSTR, int)&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;Führe native String-Manipulation aus&amp;#34;
CPP-&amp;gt;&amp;gt;CPP: &amp;#34;Schreibe Ergebnis in LPWSTR-Puffer&amp;#34;
CPP--&amp;gt;&amp;gt;CLR: &amp;#34;Gebe bool zurück (Erfolg)&amp;#34;
note left of CLR: &amp;#34;Lese modifizierten StringBuilder-Puffer&amp;#34;
CLR--&amp;gt;&amp;gt;PS: &amp;#34;Gebe Ausführungskontrolle zurück&amp;#34;
PS-&amp;gt;&amp;gt;PS: &amp;#34;Gib verarbeiteten String aus&amp;#34;
&lt;/pre>
&lt;h2 id="aufrufen-von-powershell-aus-c">Aufrufen von PowerShell aus C++
&lt;/h2>&lt;p>Jetzt betrachten wir den umgekehrten Ansatz. Es kann vorkommen, dass Sie PowerShell-Skripte dynamisch von einem in C++ geschriebenen Systemdienst oder einer Desktop-Anwendung aus ausführen und deren Ergebnisse abrufen möchten. Ein Szenario ist beispielsweise, wenn ein C++-Überwachungsagent eine bestimmte Anomalie erkennt und ein PowerShell-Wiederherstellungsskript ausführt.&lt;/p>
&lt;p>Es gibt hauptsächlich zwei Ansätze:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Prozessstart (&lt;code>CreateProcess&lt;/code> / &lt;code>_popen&lt;/code>)&lt;/strong>: Eine Methode, bei der &lt;code>powershell.exe&lt;/code> als unabhängiger Prozess gestartet und die Standard-Ein-/Ausgabe über eine Pipe verbunden wird.&lt;/li>
&lt;li>&lt;strong>PowerShell Hosting API (über C++/CLI)&lt;/strong>: Eine Methode, bei der die PowerShell-Laufzeitumgebung innerhalb desselben Prozesses gehostet wird.&lt;/li>
&lt;/ol>
&lt;p>In diesem Artikel erläutern wir die Methode mit &lt;strong>CreateProcess und einer Pipeline&lt;/strong>, da diese in der Systemprogrammierung am robustesten und universellsten ist.&lt;/p>
&lt;h3 id="ausführung-mit-createprocess-und-anonymous-pipe">Ausführung mit CreateProcess und Anonymous Pipe
&lt;/h3>&lt;p>Der folgende C++-Code erstellt eine anonyme Pipe (Anonymous Pipes), startet &lt;code>powershell.exe&lt;/code> als untergeordneten Prozess zur Skriptausführung und liest das Ergebnis aus der Standardausgabe.&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">// Pipe-Handle an den Child-Prozess vererben
&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. Erstellen der Pipe
&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. Festlegen der Startinformationen für den Child-Prozess (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">// Fenster ausblenden
&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">// Aufbau der Befehlszeile (Vereinfachte Version mit Bypass-Richtlinie zur Vermeidung von Base64-Kodierung etc.)
&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. Erstellen des Prozesses
&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">// Auf der Parent-Prozess-Seite wird die Schreib-Pipe nicht benötigt und daher geschlossen (sonst wird Read blockiert)
&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. Lesen des Ergebnisses
&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. Aufräumen (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">// Ein Befehl zum Abrufen der Prozessliste in PowerShell, sortiert nach CPU-Auslastung absteigend
&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-von-windows-registrierung-und-powershell">Integration von Windows-Registrierung und PowerShell
&lt;/h3>&lt;p>Bei der Ausführung von Skripten aus C++ sollte das Hardcodieren von dynamischen Konfigurationswerten oder Ausführungspfaden vermieden werden. In vielen Fällen lesen C++-Anwendungen ihre Einstellungen aus der &lt;strong>Windows-Registrierung&lt;/strong> (Registry).&lt;/p>
&lt;p>Eine Architektur, bei der die C++-Seite &lt;code>RegOpenKeyEx&lt;/code> und &lt;code>RegQueryValueEx&lt;/code> verwendet, um den Pfad des PowerShell-Skripts aus &lt;code>HKLM\SOFTWARE\MyApp&lt;/code> abzurufen und diesen als Argument an das obige &lt;code>CreateProcess&lt;/code> zu übergeben, wird in Unternehmenssystemen bevorzugt.&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;C++ Agentendienst&amp;#34;] --&amp;gt;|RegQueryValueEx| B[&amp;#34;Windows-Registrierung&amp;#34;]
B --&amp;gt;|Skriptpfad zurückgeben| A
A --&amp;gt;|CreateProcess| C[&amp;#34;powershell.exe&amp;#34;]
C --&amp;gt;|Ausführen| D[&amp;#34;Administrator-Skript (z.B. Restart-Service)&amp;#34;]
D --&amp;gt;|stdout via Pipe| C
C --&amp;gt;|ReadFile| A
A --&amp;gt;|Protokollieren| E[&amp;#34;Ereignisanzeige / Protokolldatei&amp;#34;]
&lt;/pre>
&lt;h2 id="leistungsanalyse-und-vorteile-des-offloadings">Leistungsanalyse und Vorteile des Offloadings
&lt;/h2>&lt;p>Warum wird eine so komplexe Architektur gewählt? Betrachten wir als konkretes Szenario die &amp;ldquo;Analyse von benutzerdefinierten IIS-Protokolldateien, die mehrere Gigabyte groß sind&amp;rdquo;.&lt;/p>
&lt;p>Wenn &lt;code>Get-Content&lt;/code> in PowerShell verwendet wird, um jede Zeile einzeln mit regulären Ausdrücken zu parsen, wird durch den Overhead der Objekterstellung und der Garbage Collection (GC) eine enorme Menge an CPU-Zeit verbraucht.&lt;/p>
&lt;p>Die Anzahl der Speicherzuweisungen $A$ und die Anzahl der GC-Auslöser $G$ verhalten sich bei der Skriptausführung proportional wie folgt:&lt;/p>
$$ G \propto \sum_{i=1}^{N} A_i $$&lt;p>Wenn der Prozess in nativen C++-Code ausgelagert wird, kann die gesamte Datei mit Memory-Mapping (&lt;code>CreateFileMapping&lt;/code>, &lt;code>MapViewOfFile&lt;/code>) direkt in den Speicher abgebildet und die Zeichenfolgensuche mithilfe von Zeigerarithmetik mittels Zero-Copy (Nullkopie) durchgeführt werden. In diesem Fall ist der Overhead für die Objekterstellung praktisch null, und das Parsen wird mit einer Geschwindigkeit abgeschlossen, die nahe der theoretischen Grenze der Speicherbandbreite liegt.&lt;/p>
&lt;p>Indem nur die geparsten Ergebnisse (z. B. eine Liste von IP-Adressen für unbefugte Zugriffe) an PowerShell zurückgegeben werden, können auch die P/Invoke-Marshalling-Kosten minimiert werden.&lt;/p>
&lt;h2 id="praktische-automatisierungsszenarien-für-die-systemverwaltung">Praktische Automatisierungsszenarien für die Systemverwaltung
&lt;/h2>&lt;h3 id="szenario-1-schneller-dateisystem-scan-und-berechtigungsänderungen">Szenario 1: Schneller Dateisystem-Scan und Berechtigungsänderungen
&lt;/h3>&lt;p>Auf großen Dateiservern müssen Dateien mit bestimmten Erweiterungen und spezifischen ACLs (Access Control Lists) extrahiert und ihre Berechtigungen stapelweise geändert werden.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rolle von C++&lt;/strong>: Verwendet &lt;code>FindFirstFile&lt;/code> / &lt;code>FindNextFile&lt;/code> und Multithreading, um den Verzeichnisbaum extrem schnell zu durchsuchen und eine Liste von Dateipfaden zu erstellen, die den Kriterien entsprechen.&lt;/li>
&lt;li>&lt;strong>Rolle von PowerShell&lt;/strong>: Verwendet &lt;code>Set-Acl&lt;/code> für die Liste, die von C++ empfangen wurde, um Berechtigungen stapelweise anzuwenden (oder Prozesse in Verbindung mit Active Directory durchzuführen).&lt;/li>
&lt;/ul>
&lt;h3 id="szenario-2-erfassung-spezifischer-hardwareinformationen">Szenario 2: Erfassung spezifischer Hardwareinformationen
&lt;/h3>&lt;p>Überwachung von Informationen von proprietären Hardwaregeräten (z. B. speziellen PCIe-Karten oder Sensoren), die über WMI (Windows Management Instrumentation) oder CIM (Common Information Model) nicht erfasst werden können.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rolle von C++&lt;/strong>: Eine DLL, die &lt;code>DeviceIoControl&lt;/code>-Aufrufe an Gerätetreiber durchführt, um Binärdaten abzurufen und zu analysieren.&lt;/li>
&lt;li>&lt;strong>Rolle von PowerShell&lt;/strong>: Ruft die DLL regelmäßig auf, formatiert die Analyseergebnisse in JSON und sendet sie an die REST-API des Überwachungsservers.&lt;/li>
&lt;/ul>
&lt;h2 id="best-practices-für-speicherverwaltung-und-fehlerbehebung">Best Practices für Speicherverwaltung und Fehlerbehebung
&lt;/h2>&lt;p>Die am häufigsten auftretenden Fehler bei der Integration sind &lt;strong>Speicherlecks (Memory Leaks)&lt;/strong> und &lt;strong>Zugriffsverletzungen (Access Violation: 0xC0000005)&lt;/strong>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Lebensdauer von Zeigern&lt;/strong>: Wenn &lt;code>[ref]&lt;/code> oder &lt;code>StringBuilder&lt;/code> von der PowerShell-Seite übergeben werden, fixiert (pinnt) P/Invoke den Speicher nur während des Aufrufs. Die C++-Seite darf diesen Zeiger nicht in einer globalen Variablen speichern und später darauf zugreifen. Wenn asynchrone Callbacks durchgeführt werden, muss der Speicher explizit mit &lt;code>GCHandle&lt;/code> fixiert werden.&lt;/li>
&lt;li>&lt;strong>Zeigergröße in 64-Bit-Umgebungen&lt;/strong>: Moderne Windows-Systeme basieren standardmäßig auf 64-Bit (x64). Die Zeigergröße auf der C++-Seite beträgt 8 Byte, und auf der PowerShell-Seite (.NET) muss &lt;code>IntPtr&lt;/code> verwendet werden. Da C++ &lt;code>long&lt;/code> in Windows 4 Byte groß ist, führt alter Code, bei dem Zeiger in &lt;code>long&lt;/code> gecastet und übergeben werden, zu Abstürzen.&lt;/li>
&lt;li>&lt;strong>Inkonsistenz bei der Zeichenfolgenkodierung&lt;/strong>: PowerShell verwendet intern UTF-16. Wenn Sie versuchen, diese auf der C++-Seite als ANSI-Zeichenfolgen (&lt;code>std::string&lt;/code>, &lt;code>char*&lt;/code>) zu empfangen, treten fehlerhafte Zeichen (Mojibake) auf. Verwenden Sie immer Wide Strings (&lt;code>std::wstring&lt;/code>, &lt;code>wchar_t*&lt;/code>) und geben Sie auf der P/Invoke-Seite ebenfalls &lt;code>CharSet = CharSet.Unicode&lt;/code> an.&lt;/li>
&lt;/ol>
&lt;h2 id="zusammenfassung">Zusammenfassung
&lt;/h2>&lt;p>Die Integration von PowerShell und C++ ist die stärkste Kombination, um die Einfachheit von Skriptsprachen mit der Leistungsfähigkeit von nativen Sprachen bei der Automatisierung der Systemverwaltung zu vereinen.&lt;/p>
&lt;p>Durch den Aufruf von C++-DLLs mithilfe von P/Invoke können rechenintensive Aufgaben ausgelagert und die Ausführungszeit drastisch verkürzt werden. Umgekehrt können Entwicklungskosten erheblich gesenkt werden, indem die umfangreichen PowerShell-Systemverwaltungsmodule über Prozessstarts oder Pipelines von C++-Anwendungen aus genutzt werden.&lt;/p>
&lt;p>Obwohl Vorsicht bei der Speicherverwaltung und Zeichenfolgenkonvertierung an den Grenzen geboten ist, werden Sie durch die Beherrschung der in diesem Artikel vorgestellten Architekturmuster und Implementierungstechniken in der Lage sein, fortschrittlichere und robustere Tools für die Windows-Systemverwaltung zu entwickeln.&lt;/p>
&lt;hr>
&lt;p>&lt;em>In diesem technischen Blog werden wir weiterhin tiefgreifende Themen im Zusammenhang mit internen Windows-Strukturen und fortgeschrittener Automatisierung behandeln. Wenn Sie Fragen oder Feedback haben, hinterlassen Sie bitte einen Kommentar im Kommentarbereich.&lt;/em>&lt;/p></description></item></channel></rss>