<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DBA von Nebenan</title>
	<atom:link href="https://dbavonnebenan.de/feed/" rel="self" type="application/rss+xml" />
	<link>https://dbavonnebenan.de</link>
	<description>Sql Server, Performance &#38; PowerShell Automation</description>
	<lastBuildDate>Sun, 14 Jun 2026 20:02:35 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://dbavonnebenan.de/wp-content/uploads/2025/04/cropped-www_logo-32x32.png</url>
	<title>DBA von Nebenan</title>
	<link>https://dbavonnebenan.de</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>psTerminalPerfCounter &#8211; Performance Counter im Terminal &#8211; HowTo</title>
		<link>https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_de/</link>
					<comments>https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_de/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sun, 14 Jun 2026 20:02:34 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[DE]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<category><![CDATA[TERMINAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=714</guid>

					<description><![CDATA[<p>Hands-on zu psTerminalPerfCounter: Windows Performance Counter im Terminal überwachen, inklusive TUI, Multiserver-Monitoring sowie CSV- und HTML-Export.</p>
<p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_de/">psTerminalPerfCounter – Performance Counter im Terminal – HowTo</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--40)">Intro</h1>



<div class="wp-block-columns are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50px">
<figure class="wp-block-image size-full is-resized"><img fetchpriority="high" decoding="async" width="294" height="288" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/GitHub_Invertocat_Black.png" alt="Solid black square placeholder with no visible content." class="wp-image-720" style="aspect-ratio:1.0208344636753297;width:51px;height:auto"/></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><strong><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter" target="_blank" rel="noopener" title="">psTerminalPerfCounter</a></strong></p>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Im vorherigen Artikel habe ich einen kurzen Abriss in die <a href="https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_de/" target="_blank" rel="noopener" title="">Geschichte und Funktionsweise</a> der Windows Performance Counter gemacht, jetzt folgt das Hands-on. Grundlage ist Release 0.4.1, das ganz im Zeichen von Visualisierung und Datenexport steht. Neu dabei: CSV-Export, eine Terminal GUI als Ablösung der textbasierten Ansicht und der HTML-Export via PSWriteHTML. Klingt spannend&#8230; ist es auch 🙂 Ich denke das siehst du genau so, sonst würdest du nicht mehr lesen. 🙂</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Installation</h1>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Installation eines PowerShell Moduls, nichts besonderes</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Install psTerminalPerfcounter
Install-Module psTerminalPerfCounter

# List Cmdlets
Get-Command -Module psTerminalPerfCounter

# Install PSWriteHtml, required for HTML Export
Install-Module PSWriteHtml
</pre></div>


<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Grundlegender Aufbau, Counterconfigs</h1>



<p class="wp-block-paragraph">psTerminalPerfCounter arbeitet mit Konfigurationsdateien, in denen die Counter-Sets und deren Konfiguration beschrieben sind: Counter-IDs, Instanzen (ob zum Beispiel alle CPU-Cores oder nur Core 3 und 4 überwacht werden sollen), Wertkonvertierung, Units und die farbliche Kodierung der Graphen über die sogenannte ColorMap, die allerdings nur die Legacy-Visualisierung unterstützt.</p>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)">Counterconfigs können in beliebigen Pfaden gespeichert und von dort aufgerufen werden. Alternativ lassen sich Pfade registrieren, was den Aufruf einfach über denConfignamen ermöglicht. Der Default-Pfad ist der Config-Ordner im Modul selbst, der bereits einige vordefinierte Configs mitbringt.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all registered paths
Get-tpcConfigPaths

# Add custom path
Add-tpcConfigPath -Path &#039;C:\tpcConfig&#039;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img decoding="async" width="998" height="271" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109.png" alt="" class="wp-image-722" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109.png 998w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109-300x81.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109-768x209.png 768w" sizes="(max-width: 998px) 100vw, 998px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all Counterconfigs and details in all paths
Test-tpcAvailableCounterConfig
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="420" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-1024x420.png" alt="" class="wp-image-723" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-1024x420.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-300x123.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-768x315.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947.png 1273w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Single Server Monitoring</h1>



<p class="wp-block-paragraph" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--40)">Die schnellste Methode ist ein einzelner Server, lokal oder remote.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Use CPU Config locally
Start-tpcMonitor -Configname CPU
Start-tpcMonitor -Confipath &#039;C:\Users\labadmin\Documents\PowerShell\Modules\psterminalperfcounter\0.4.0\Config\tpc_CPU.json&#039;

# Use CPU Config remote
Start-tpcMonitor -Computername &#039;dev-node1&#039; -Configname CPU
Start-tpcMonitor -Computername &#039;dev-node1&#039; -Confipath &#039;C:\Users\labadmin\Documents\PowerShell\Modules\psterminalperfcounter\0.4.0\Config\tpc_CPU.json&#039;

# Use CPU Config rmeote with different credentials
Start-tpcMonitor -Computername &#039;dev-node1&#039; -Credentials $(Get-Credential) -Configname CPU
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1022" height="773" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524.png" alt="" class="wp-image-724" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524.png 1022w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524-300x227.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524-768x581.png 768w" sizes="auto, (max-width: 1022px) 100vw, 1022px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Da die Legacy-Visualisierung spätestens bei Multiserver-Umgebungen an ihre Grenzen kommt, nutze ich für dieses Hands-on den <code>-TUI</code> Switch.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Use CPU Config locally with TUI
Start-tpcMonitor -Configname CPU -TUI
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="562" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-1024x562.png" alt="" class="wp-image-725" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-1024x562.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-300x165.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-768x422.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159.png 1483w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Multi Server Monitoring</h1>



<p class="wp-block-paragraph">Das Multiserver-Monitoring funktioniert ebenfalls über Konfigurationsdateien, wobei mir beim Schreiben dieser Zeilen auffällt: Warum habe ich nie daran gedacht, einfach eine Counterconfig gegen eine Serverliste laufen zu lassen? Ab ins Backlog damit. Wie auch immer, in der Environment-Konfiguration lassen sich beliebig viele Server mit verschiedenen Configs definieren. Da ich zuletzt noch Probleme hatte, die Sparklines in der TUI scrollbar zu machen, sind diese in der Multiserver-Ansicht deaktiviert.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Start multi server monitoring
Start-tpcEnvironmentMonitor -EnvConfigPath &#039;C:\tpcConfig\ENV_SERVER_EXAMPLE.json&#039; -TUI
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="389" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-1024x389.png" alt="" class="wp-image-726" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-1024x389.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-300x114.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-768x292.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127.png 1472w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"><em>LAB-NODE03 ist in dem Fall ein deutsche Installation</em></p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">Die Spalte Duration zeigt die Zeit, die die Funktion auf dem jeweiligen Server gebraucht hat, um alle Werte einzusammeln. Den finalen Timestamp des gesamten Datensatzes definiert immer der langsamste Server, nur so ist eine homogene Zeitreihe möglich. Eine Varianz von in diesem Fall 1,3 Sekunden lässt sich dabei nicht vermeiden.</p>



<p class="wp-block-paragraph">Das wars auch schon zur Auführung, da dieses Modul nur das Framework bereitstellt. Das eigentliche Leben kommt mit den Counterconfigs. Wie diese erstellt werden schauen wir uns jetzt an.</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Erstellung von Counterconfigs</h1>



<p class="wp-block-paragraph">Am Anfang ist der Performance Counter. Bevor wir die Konfiguration schreiben können, brauchen wir die Counter-IDs statt der lokalisierten Namen. Dafür gibt es <code>Get-tpcPerformanceCounterInfo</code>, das in beide Richtungen funktioniert: Counterpath zu ID und umgekehrt.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all counter and counter objects containing &#039;processor time&#039;
Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;processor time&#039;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="973" height="297" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650.png" alt="" class="wp-image-727" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650.png 973w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650-300x92.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650-768x234.png 768w" sizes="auto, (max-width: 973px) 100vw, 973px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">Wichtig sind die letzten beiden Spalten. Es gibt Single-Instance-Counter mit nur einem Wert, aber auch Multi-Instance-Counter wie das Processor-Counterset, bei dem jede Instanz einem Core entspricht, oder halt gesamt (<code>_Total</code>).</p>



<p class="wp-block-paragraph">Genauso lässt sich mit dem Cmdlet herausfinden, welcher Counter sich hinter einer Composite-ID verbirgt.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Show counter name of composite ID
Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;238-6&#039;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="911" height="105" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093.png" alt="" class="wp-image-728" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093.png 911w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093-300x35.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093-768x89.png 768w" sizes="auto, (max-width: 911px) 100vw, 911px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Oder auf einem deutschen System</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="904" height="115" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840.png" alt="" class="wp-image-729" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840.png 904w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840-300x38.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840-768x98.png 768w" sizes="auto, (max-width: 904px) 100vw, 904px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">Nehmen wir noch Counter, die nicht standardmäßig auf einem Windows-System vorhanden sind: SQL Server. DEV22A ist in diesem Fall die erste Instanz auf dem System.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# &quot;Out-String -Stream&quot; converts PowerShell&#039;s internal formatting objects into actual strings line by 
# line, enabling string operations like `Select-String` to work on them.

Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;dev22a&#039; | 
		Out-String -Stream | 
		Select-String &quot;lookup&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="117" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-1024x117.png" alt="" class="wp-image-730" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-1024x117.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-300x34.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-768x88.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">Nehmen wir zum Testen <code>Page lookups/sec</code> &#8211;&gt; 12222-12272</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;dev22a&#039; | 
		Out-String -Stream | 
		Select-String &quot;log flushes&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="120" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-1024x120.png" alt="" class="wp-image-731" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-1024x120.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-300x35.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-768x90.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599.png 1471w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Und <code>log flush/sec</code> auf der Instanz TempDB &#8211;&gt; 12352-12446</p>



<p class="wp-block-paragraph">Die minimale Config sieht dann so aus. Bei den SQL-Server-Countern fehlen einige Werte, das ist aber nicht SQL-Server-spezifisch, sondern zeigt, dass die meisten Felder Defaults bekommen. Details dazu finden sich in der Doku im Repo. Erwähnenswert noch: bei CPU nutze ich <code>"counterInstance": "1|2"</code>, wodurch automatisch zwei Counter erstellt werden, und bei den Page Lookups die Konvertierung durch 1000, damit die Zahlen lesbar bleiben.\</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
{
	&quot;name&quot;: &quot;CPU and Sql Server Page Usage&quot;,
	&quot;description&quot;: &quot;CPU Usage&quot;,
	&quot;counters&quot;: &#x5B;
		{
			&quot;title&quot;: &quot;CPU Usage&quot;,
			&quot;unit&quot;: &quot;%&quot;,
			&quot;conversionFactor&quot;: 1,
			&quot;conversionExponent&quot;: 1,
			&quot;conversionType&quot;: &quot;D&quot;,
			&quot;format&quot;: &quot;table&quot;,
			&quot;counterID&quot;: &quot;238-6&quot;,
			&quot;counterSetType&quot;: &quot;MultiInstance&quot;,
			&quot;counterInstance&quot;: &quot;0|1&quot;,
			&quot;colorMap&quot;: {
				&quot;20&quot;: &quot;Green&quot;,
				&quot;50&quot;: &quot;Yellow&quot;,
				&quot;70&quot;: &quot;RED&quot;
			}
		},
		{
			&quot;title&quot;: &quot;Sql DEV22A Page Lookups/s&quot;,
			&quot;unit&quot;: &quot;#K&quot;,
			&quot;conversionFactor&quot;: 1000,
			&quot;conversionExponent&quot;: 1,
			&quot;conversionType&quot;: &quot;D&quot;,
			&quot;counterID&quot;: &quot;12222-12272&quot;,
			&quot;counterSetType&quot;: &quot;SingleInstance&quot;,
			&quot;counterInstance&quot;: &quot;&quot;
		},
		{
			&quot;title&quot;: &quot;Sql DEV22A TempDB Log Flushes/s&quot;,
			&quot;unit&quot;: &quot;#&quot;,
			&quot;counterID&quot;: &quot;12352-12446&quot;,
			&quot;counterSetType&quot;: &quot;MultiInstance&quot;,
			&quot;counterInstance&quot;: &quot;tempdb&quot;
		}

	]
}
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--40)">Das Ganze dann in einem registrierten Pfad speichern mit dem Präfix <code>tpc_NAME.json</code> und los geht&#8217;s.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="404" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-1024x404.png" alt="" class="wp-image-732" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-1024x404.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-300x118.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-768x303.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-1536x605.png 1536w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880.png 1713w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Monitoring einer Umgebung mit Environment File</h1>



<p class="wp-block-paragraph">Auch hier keine Magic. Es können Confignamen oder Pfade angegeben werden. Eine noch nicht vollständig dokumentierte Funktion ist die Nutzung von SecretVaults: Über die PowerShell-Konnektoren lassen sich Credentials aus fast allen gängigen Lösungen laden, womit auch Nicht-Admins die Möglichkeit gegeben werden kann, Systeme zu überwachen.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&#x5B;
    {
        &quot;name&quot;: &quot;SQL_ENVIRONMENT_001&quot;,
        &quot;description&quot;: &quot;SQL Server Environment Production&quot;,
        &quot;interval&quot;: 2,
        &quot;secretvaultname&quot;: &quot;SecretStore&quot;,
        &quot;credentialname&quot;: &quot;integrated&quot;,
        &quot;servers&quot;: &#x5B;
            {
                &quot;computername&quot;: &quot;DEV-NODE1&quot;,
                &quot;comment&quot;: &quot;Sql Server Node A Production&quot;,
                &quot;counterConfig&quot;: &#x5B;
                    &quot;SQLDEMO&quot;
                ]
            },
            {
                &quot;computername&quot;: &quot;DEV-NODE2&quot;,
                &quot;comment&quot;: &quot;Sql Server Node B Production&quot;,
                &quot;counterConfig&quot;: &#x5B;
                    &quot;C:\Users\devadmin\Desktop\tpc_SQLDEMO.json&quot;
                ]
            }
        ]
    }
]
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# without TUI
Start-tpcEnvironmentMonitor -EnvConfigPath &quot;C:\Users\devadmin\Desktop\ENV_SERVER_EXAMPLE2.json&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="277" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-1024x277.png" alt="" class="wp-image-733" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-1024x277.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-300x81.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-768x208.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078.png 1442w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Datenexport</h1>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">CSV</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="299" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-1024x299.png" alt="" class="wp-image-734" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-1024x299.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-300x88.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-768x224.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885.png 1129w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Um die Zeitreihen weiterzuverwenden, kann nach CSV exportiert werden. Achtung, aktuell noch ein bekannter Bug: der Export ist kommasepariert, Werte mit Komma werden dadurch ebenfalls getrennt, in 0.4.1 gefixt.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# -CsvPath is default desktop
	Start-tpcEnvironmentMonitor -EnvConfigPath &quot;C:\Users\devadmin\Desktop\ENV_SERVER_EXAMPLE2.json&quot; -ExportCsv
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">HTML Report</h1>



<p class="wp-block-paragraph">Eine alternative Visualisierung als HTML, nützlich wenn ich eine Zeitreihe weitergeben möchte ohne Excel oder weitere Tools zu bemühen. Gruppiert werden kann nach Counter oder nach Server, je nachdem ob ich bei mehreren Servern alle Counter eines Servers in einem Diagramm sehen möchte, oder einen bestimmten Counter über mehrere Server hinweg. Details dazu finden sich in den Docs im Repo.</p>



<p class="wp-block-paragraph">Zu beachten: das HTML enthält ein rollendes Datenset, das an die maximale Sample-Anzahl gebunden ist. Je mehr Samples, desto träger wird das HTML. Für große Zeitreihen lieber CSV nutzen.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# -HTMLPath is default desktop
	Start-tpcEnvironmentMonitor -EnvConfigPath &quot;C:\Users\devadmin\Desktop\ENV_SERVER_EXAMPLE2.json&quot; -ExportHTML
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="339" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-1024x339.png" alt="" class="wp-image-735" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-1024x339.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-300x99.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-768x254.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-1536x508.png 1536w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-2048x678.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-container-core-column-is-layout-cc415327 wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="295" height="294" src="https://dbavonnebenan.de/wp-content/uploads/2025/04/2025-04-21_16-19.png" alt="" class="wp-image-113" style="width:157px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/04/2025-04-21_16-19.png 295w, https://dbavonnebenan.de/wp-content/uploads/2025/04/2025-04-21_16-19-150x150.png 150w" sizes="auto, (max-width: 295px) 100vw, 295px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph">Das war&#8217;s als Schnelleinstieg, mehr Details zu den einzelnen Funktionen finden sich wie immer in den Docs und der <a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/README.md" title="">README </a>im Repository.</p>
</div>
</div><p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_de/">psTerminalPerfCounter – Performance Counter im Terminal – HowTo</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_de/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>psTerminalPerfCounter &#8211; Performance Counter in Terminal &#8211; HowTo</title>
		<link>https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_en/</link>
					<comments>https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_en/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sun, 14 Jun 2026 20:02:16 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[eng]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<category><![CDATA[TERMINAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=741</guid>

					<description><![CDATA[<p>Hands-on with psTerminalPerfCounter: monitor Windows Performance Counters in the terminal, including a TUI, multi-server monitoring, and CSV/HTML export.</p>
<p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_en/">psTerminalPerfCounter – Performance Counter in Terminal – HowTo</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--40)">Intro</h1>



<div class="wp-block-columns are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50px">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="294" height="288" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/GitHub_Invertocat_Black.png" alt="Solid black square placeholder with no visible content." class="wp-image-720" style="aspect-ratio:1.0208344636753297;width:51px;height:auto"/></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><strong><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter" target="_blank" rel="noopener" title="">psTerminalPerfCounter</a></strong></p>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">In the previous article I gave a quick rundown of the <a href="/windows-performance-counters-how-the-os-monitors-itself_en/" title="">history and inner workings</a> of Windows Performance Counters, now comes the hands-on part. The basis is release 0.4.1, which is all about visualization and data export. New additions: CSV export, a terminal GUI replacing the text-based view, and HTML export via PSWriteHTML. Sounds exciting&#8230; and it is 🙂 I figure you see it the same way, otherwise you wouldn&#8217;t still be reading. 🙂</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Installation</h1>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Installing a PowerShell module, nothing special</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Install psTerminalPerfcounter
Install-Module psTerminalPerfCounter

# List Cmdlets
Get-Command -Module psTerminalPerfCounter

# Install PSWriteHtml, required for HTML Export
Install-Module PSWriteHtml
</pre></div>


<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Basic Structure, Counter Configs</h1>



<p class="wp-block-paragraph">psTerminalPerfCounter works with configuration files that describe the counter sets and their configuration: counter IDs, instances (whether, for example, all CPU cores or only core 3 and 4 should be monitored), value conversion, units, and the color coding of the graphs via the so-called ColorMap, which however is only supported by the legacy visualization.</p>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)">Counter configs can be stored in any path and called from there. Alternatively, paths can be registered, which allows calling them simply by the config name. The default path is the config folder within the module itself, which already ships with a few predefined configs.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all registered paths
Get-tpcConfigPaths

# Add custom path
Add-tpcConfigPath -Path &#039;C:\tpcConfig&#039;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="998" height="271" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109.png" alt="" class="wp-image-722" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109.png 998w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109-300x81.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184010109-768x209.png 768w" sizes="auto, (max-width: 998px) 100vw, 998px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all Counterconfigs and details in all paths
Test-tpcAvailableCounterConfig
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="420" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-1024x420.png" alt="" class="wp-image-723" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-1024x420.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-300x123.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947-768x315.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611184610947.png 1273w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Single Server Monitoring</h1>



<p class="wp-block-paragraph" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--40)">The fastest method is a single server, local or remote.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Use CPU Config locally
Start-tpcMonitor -Configname CPU
Start-tpcMonitor -Confipath &#039;C:\Users\labadmin\Documents\PowerShell\Modules\psterminalperfcounter\0.4.0\Config\tpc_CPU.json&#039;

# Use CPU Config remote
Start-tpcMonitor -Computername &#039;dev-node1&#039; -Configname CPU
Start-tpcMonitor -Computername &#039;dev-node1&#039; -Confipath &#039;C:\Users\labadmin\Documents\PowerShell\Modules\psterminalperfcounter\0.4.0\Config\tpc_CPU.json&#039;

# Use CPU Config rmeote with different credentials
Start-tpcMonitor -Computername &#039;dev-node1&#039; -Credentials $(Get-Credential) -Configname CPU
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1022" height="773" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524.png" alt="" class="wp-image-724" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524.png 1022w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524-300x227.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611185126524-768x581.png 768w" sizes="auto, (max-width: 1022px) 100vw, 1022px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Since the legacy visualization reaches its limits at the latest with multi-server environments, I use the <code>-TUI</code> switch for this hands-on.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Use CPU Config locally with TUI
Start-tpcMonitor -Configname CPU -TUI
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="562" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-1024x562.png" alt="" class="wp-image-725" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-1024x562.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-300x165.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159-768x422.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611190144159.png 1483w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Multi Server Monitoring</h1>



<p class="wp-block-paragraph">Multi-server monitoring also works via configuration files, although while writing these lines it occurs to me: why did I never think of simply running a counter config against a server list? Onto the backlog with that. Anyway, in the environment configuration you can define any number of servers with different configs. Since I recently still had trouble making the sparklines in the TUI scrollable, they are disabled in the multi-server view.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Start multi server monitoring
Start-tpcEnvironmentMonitor -EnvConfigPath &#039;C:\tpcConfig\ENV_SERVER_EXAMPLE.json&#039; -TUI
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="389" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-1024x389.png" alt="" class="wp-image-726" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-1024x389.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-300x114.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127-768x292.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611191606127.png 1472w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph"><em>LAB-NODE03 is a German installation in this case</em></p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">The Duration column shows the time the function needed on each server to collect all values. The final timestamp of the entire data set is always defined by the slowest server, as only this way is a homogeneous time series possible. A variance of, in this case, 1.3 seconds cannot be avoided here.</p>



<p class="wp-block-paragraph">That&#8217;s all there is to running it, since this module only provides the framework. The actual life comes with the counter configs. Let&#8217;s now take a look at how these are created.</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Creating Counter Configs</h1>



<p class="wp-block-paragraph">In the beginning there is the performance counter. Before we can write the configuration, we need the counter IDs instead of the localized names. For that there is <code>Get-tpcPerformanceCounterInfo</code>, which works in both directions: counter path to ID and vice versa.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all counter and counter objects containing &#039;processor time&#039;
Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;processor time&#039;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="973" height="297" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650.png" alt="" class="wp-image-727" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650.png 973w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650-300x92.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082832650-768x234.png 768w" sizes="auto, (max-width: 973px) 100vw, 973px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">The last two columns are important. There are single-instance counters with only one value, but also multi-instance counters like the Processor counter set, where each instance corresponds to a core, or the total (<code>_Total</code>).</p>



<p class="wp-block-paragraph">In the same way you can use the cmdlet to find out which counter is hidden behind a composite ID.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Show counter name of composite ID
Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;238-6&#039;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="911" height="105" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093.png" alt="" class="wp-image-728" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093.png 911w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093-300x35.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083119093-768x89.png 768w" sizes="auto, (max-width: 911px) 100vw, 911px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Or on a German system</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="904" height="115" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840.png" alt="" class="wp-image-729" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840.png 904w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840-300x38.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612083431840-768x98.png 768w" sizes="auto, (max-width: 904px) 100vw, 904px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">Let&#8217;s also take counters that are not present by default on a Windows system: SQL Server. DEV22A in this case is the first instance on the system.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# &quot;Out-String -Stream&quot; converts PowerShell&#039;s internal formatting objects into actual strings line by 
# line, enabling string operations like `Select-String` to work on them.

Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;dev22a&#039; | 
		Out-String -Stream | 
		Select-String &quot;lookup&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="117" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-1024x117.png" alt="" class="wp-image-730" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-1024x117.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-300x34.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564-768x88.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612081940564.png 1235w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0">Let&#8217;s take <code>Page lookups/sec</code> for testing &#8211;&gt; 12222-12272</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
Get-tpcPerformanceCounterInfo -ComputerName &#039;dev-node1&#039; -SearchTerm &#039;dev22a&#039; | 
		Out-String -Stream | 
		Select-String &quot;log flushes&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="120" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-1024x120.png" alt="" class="wp-image-731" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-1024x120.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-300x35.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599-768x90.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612082340599.png 1471w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">And <code>log flush/sec</code> on the TempDB instance &#8211;&gt; 12352-12446</p>



<p class="wp-block-paragraph">The minimal config then looks like this. Some values are missing for the SQL Server counters, but that is not SQL Server specific, it shows that most fields receive defaults. Details on this can be found in the docs in the repo. Also worth mentioning: for CPU I use <code>"counterInstance": "1|2"</code>, which automatically creates two counters, and for the page lookups the conversion by 1000 so that the numbers stay readable.\</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
{
	&quot;name&quot;: &quot;CPU and Sql Server Page Usage&quot;,
	&quot;description&quot;: &quot;CPU Usage&quot;,
	&quot;counters&quot;: &#x5B;
		{
			&quot;title&quot;: &quot;CPU Usage&quot;,
			&quot;unit&quot;: &quot;%&quot;,
			&quot;conversionFactor&quot;: 1,
			&quot;conversionExponent&quot;: 1,
			&quot;conversionType&quot;: &quot;D&quot;,
			&quot;format&quot;: &quot;table&quot;,
			&quot;counterID&quot;: &quot;238-6&quot;,
			&quot;counterSetType&quot;: &quot;MultiInstance&quot;,
			&quot;counterInstance&quot;: &quot;0|1&quot;,
			&quot;colorMap&quot;: {
				&quot;20&quot;: &quot;Green&quot;,
				&quot;50&quot;: &quot;Yellow&quot;,
				&quot;70&quot;: &quot;RED&quot;
			}
		},
		{
			&quot;title&quot;: &quot;Sql DEV22A Page Lookups/s&quot;,
			&quot;unit&quot;: &quot;#K&quot;,
			&quot;conversionFactor&quot;: 1000,
			&quot;conversionExponent&quot;: 1,
			&quot;conversionType&quot;: &quot;D&quot;,
			&quot;counterID&quot;: &quot;12222-12272&quot;,
			&quot;counterSetType&quot;: &quot;SingleInstance&quot;,
			&quot;counterInstance&quot;: &quot;&quot;
		},
		{
			&quot;title&quot;: &quot;Sql DEV22A TempDB Log Flushes/s&quot;,
			&quot;unit&quot;: &quot;#&quot;,
			&quot;counterID&quot;: &quot;12352-12446&quot;,
			&quot;counterSetType&quot;: &quot;MultiInstance&quot;,
			&quot;counterInstance&quot;: &quot;tempdb&quot;
		}

	]
}
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--40)">Then save the whole thing in a registered path with the prefix <code>tpc_NAME.json</code> and off we go.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="404" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-1024x404.png" alt="" class="wp-image-732" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-1024x404.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-300x118.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-768x303.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880-1536x605.png 1536w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612090849880.png 1713w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Monitoring an Environment with an Environment File</h1>



<p class="wp-block-paragraph">No magic here either. Config names or paths can be specified. A function that is not yet fully documented is the use of SecretVaults: via the PowerShell connectors, credentials can be loaded from almost all common solutions, which also gives non-admins the ability to monitor systems.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&#x5B;
    {
        &quot;name&quot;: &quot;SQL_ENVIRONMENT_001&quot;,
        &quot;description&quot;: &quot;SQL Server Environment Production&quot;,
        &quot;interval&quot;: 2,
        &quot;secretvaultname&quot;: &quot;SecretStore&quot;,
        &quot;credentialname&quot;: &quot;integrated&quot;,
        &quot;servers&quot;: &#x5B;
            {
                &quot;computername&quot;: &quot;DEV-NODE1&quot;,
                &quot;comment&quot;: &quot;Sql Server Node A Production&quot;,
                &quot;counterConfig&quot;: &#x5B;
                    &quot;SQLDEMO&quot;
                ]
            },
            {
                &quot;computername&quot;: &quot;DEV-NODE2&quot;,
                &quot;comment&quot;: &quot;Sql Server Node B Production&quot;,
                &quot;counterConfig&quot;: &#x5B;
                    &quot;C:\Users\devadmin\Desktop\tpc_SQLDEMO.json&quot;
                ]
            }
        ]
    }
]
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# without TUI
Start-tpcEnvironmentMonitor -EnvConfigPath &quot;C:\Users\devadmin\Desktop\ENV_SERVER_EXAMPLE2.json&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="277" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-1024x277.png" alt="" class="wp-image-733" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-1024x277.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-300x81.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078-768x208.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092052078.png 1442w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Data Export</h1>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">CSV</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="299" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-1024x299.png" alt="" class="wp-image-734" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-1024x299.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-300x88.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885-768x224.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612092726885.png 1129w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">To reuse the time series, you can export to CSV. Caution, currently still a known bug: the export is comma-separated, so values containing a comma get split as well, fixed in 0.4.1.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# -CsvPath is default desktop
	Start-tpcEnvironmentMonitor -EnvConfigPath &quot;C:\Users\devadmin\Desktop\ENV_SERVER_EXAMPLE2.json&quot; -ExportCsv
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">HTML Report</h1>



<p class="wp-block-paragraph">An alternative visualization as HTML, useful when I want to pass on a time series without bothering with Excel or other tools. Grouping can be done by counter or by server, depending on whether, with multiple servers, I want to see all counters of one server in a single chart, or one specific counter across multiple servers. Details on this can be found in the docs in the repo.</p>



<p class="wp-block-paragraph">To note: the HTML contains a rolling data set bound to the maximum number of samples. The more samples, the more sluggish the HTML becomes. For large time series, better use CSV.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# -HTMLPath is default desktop
	Start-tpcEnvironmentMonitor -EnvConfigPath &quot;C:\Users\devadmin\Desktop\ENV_SERVER_EXAMPLE2.json&quot; -ExportHTML
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="339" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-1024x339.png" alt="" class="wp-image-735" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-1024x339.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-300x99.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-768x254.png 768w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-1536x508.png 1536w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260612093443448-2048x678.png 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-container-core-column-is-layout-cc415327 wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="295" height="294" src="https://dbavonnebenan.de/wp-content/uploads/2025/04/2025-04-21_16-19.png" alt="" class="wp-image-113" style="width:157px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/04/2025-04-21_16-19.png 295w, https://dbavonnebenan.de/wp-content/uploads/2025/04/2025-04-21_16-19-150x150.png 150w" sizes="auto, (max-width: 295px) 100vw, 295px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="wp-block-paragraph">That&#8217;s it as a quick start, more details on the individual functions can be found, as always, in the docs and the <a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/README.md" title="">README </a>in the repository.</p>
</div>
</div><p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_en/">psTerminalPerfCounter – Performance Counter in Terminal – HowTo</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_en/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows Performance Counter: Wie sich das OS selbst überwacht</title>
		<link>https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_de/</link>
					<comments>https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_de/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sun, 14 Jun 2026 20:01:30 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[DE]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<category><![CDATA[TERMINAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=686</guid>

					<description><![CDATA[<p>Performance Counter sind seit Windows NT 3.1 ein fester Bestandteil des Betriebssystems. In diesem Artikel erkläre ich kurz, wie das System intern funktioniert, warum Counter-Namen sprachabhängig sind und wie mein PowerShell Modul psTerminalPerfCounter genau dieses Problem löst.</p>
<p>The post <a href="https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_de/">Windows Performance Counter: Wie sich das OS selbst überwacht</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading" style="margin-bottom:var(--wp--preset--spacing--40)">Intro</h1>



<div class="wp-block-columns are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50px">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="294" height="288" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/GitHub_Invertocat_Black.png" alt="Solid black square placeholder with no visible content." class="wp-image-720" style="aspect-ratio:1.0208344636753297;width:51px;height:auto"/></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><strong><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter" target="_blank" rel="noopener" title="">psTerminalPerfCounter</a></strong></p>
</div>
</div>



<p class="wp-block-paragraph">Knapp ein Jahr ist es nun her, dass ich mit der Entwicklung von psTerminalPerfCounter begann. Stolz auf die &#8222;grafische&#8220; Implementierung, Sprachunabhängigkeit mittels 3rd-Party-Lib und den damaligen heiligen Gral: Klassen in PowerShell.</p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--40)">Nichts davon ist geblieben:</p>



<ul class="wp-block-list">
<li>Grafische Implementierung? Schön bunt aber&#8230;
<ul class="wp-block-list">
<li>Bei Multiserver Umgebungen träge wie ein Stein</li>



<li>Dynamisch und Skalierbar, Fehlanzeige</li>



<li>Neuimplementierung in TUI (BETA)<br></li>
</ul>
</li>



<li>Multilanguage per 3rd Party Lib
<ul class="wp-block-list">
<li>Geht alles direkt per Windows Registry, durch Zufall darüber gestolpert<br></li>
</ul>
</li>



<li>Klassen in PowerShell? Sehr schlechte Entscheidung.
<ul class="wp-block-list">
<li>Nicht praktikabel, Instanzen nicht ohne weiteres serialisierbar, Methoden gehen verloren, Parallel Remoting mit Runspaces kaum umsetzbar</li>



<li>Rebuild in C#</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--50)">Mit dem aktuellen Release 0.4.1 sind erst mal alle Funktionen implementiert, welche ich im Backlog hatte. Da mir die nächsten Monate dazu die Zeit für dieses Projekt fehlen wird, ist dies ein guter Moment ein <a href="/psterminalperfcounter-counter-in-terminal-handson_de" target="_blank" rel="noopener" title="">HandsOn</a> zu schreiben, da die README.md im Repo doch manchmal herausfordernd ist&#8230; wie es scheint 🙂 Bevor es zum <a href="http://\/psterminalperfcounter-counter-in-terminal-handson_de" target="_blank" rel="noopener" title="">HandsOn</a> geht, aber erst mal ein wenig zur Technik und Geschichte der Performance Counter.</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Geschichte</h1>



<p class="wp-block-paragraph">Windows Performance Counter gibt es in Windows seit <strong>NT 3.1 (1993)</strong>, da hatte ich noch nicht mal einen Computer. Microsoft brauchte damals eine standardisierte Methode, um Systemzustände anzeigbar zu machen, ohne dass jede Anwendung eigene Monitoring-Mechanismen implementieren musste. Das hieẞ aber auch Messwerte aus der Registry kratzen und Deltas berechnen.</p>



<p class="wp-block-paragraph">Mit <strong>Windows 2000</strong> kam der <em>Performance Data Helper</em> (PDH) als komfortable High-Level-API dazu, die den Zugriff auf Performance Counter so gestaltet, wie wir ihn heute kennen. Gleichzeitig wurde WMI eingeführt, das Performance-Daten über eine objektorientierte Schnittstelle zugänglich machte. CIM war ja nicht proprietär und zu kompatibel 😛</p>



<p class="wp-block-paragraph"><strong>Windows Vista</strong> brachte das überarbeitete <strong>Provider V2-Modell</strong>: Statt einer DLL, die vom System in einen fremden Prozess geladen wurde (fehleranfällig, Absturz des Providers = Absturz des abfragenden Prozesses), registrieren sich Provider seitdem als eigenständige ausführbare Dateien oder Dienste. Das ist das heute noch gültige Modell.</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Aufbau und Funktion</h1>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><img loading="lazy" decoding="async" width="1241" height="825" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741.png" alt="Diagram of the Applications &amp; Tools stack: PDH and WMI/Perflib feed into Registry, then Performance Counter Provider, then Kernel &amp; Drivers and Usermode Processes." class="wp-image-694" style="width:676px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741.png 1241w, https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741-300x199.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741-1024x681.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741-768x511.png 768w" sizes="auto, (max-width: 1241px) 100vw, 1241px" /></figure>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Metadaten in der Registry</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--40)">Alle bekannten Counter sind unter <code>HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib</code> registriert. Dort liegen Name, Beschreibung und eine numerische Index-Nummer pro Counter, getrennt nach Sprache (Unterkey <code>009</code> für Englisch, <code>007</code> für Deutsch usw.). </p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List available language packs (counter IDs)
Get-ChildItem &quot;HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0"><img loading="lazy" decoding="async" width="1012" height="441" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632.png" alt="Registry view of Perflib under HKEY_LOCAL_MACHINE showing entries like 009 and _V2Providers with Counter/Help text for Windows performance counters in a dark UI." class="wp-image-690" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632.png 1012w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632-300x131.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632-768x335.png 768w" sizes="auto, (max-width: 1012px) 100vw, 1012px" /></figure>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Provider liefern die Rohdaten</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--40)">Jede Komponente (Kernel, Treiber, Dienste wie IIS oder SQL Server, die .NET-Runtime) kann eigene Counter registrieren. Der Provider wartet passiv und liefert Daten erst dann, wenn sie jemand abfragt. Es gibt keinen dauerhaften Sammeldienst im Hintergrund.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all services that have a Performance subkey

Get-ChildItem &quot;HKLM:\SYSTEM\CurrentControlSet\Services&quot; |
    Where-Object { Test-Path &quot;$($_.PSPath)\Performance&quot; } |
    ForEach-Object {
        $perf = Get-ItemProperty &quot;$($_.PSPath)\Performance&quot;
        &#x5B;PSCustomObject]@{
            Service      = $_.PSChildName
            FirstCounter = $perf.&#039;First Counter&#039;
            LastCounter  = $perf.&#039;Last Counter&#039;
            Library      = $perf.Library
        }
    } | Format-Table -AutoSize
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="1229" height="650" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687.png" alt="Console output listing Windows services with counters and DLL paths (names like .NET CLR Data, IIS, SQL Server) and their FirstCounter/LastCounter values." class="wp-image-691" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687.png 1229w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687-300x159.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687-1024x542.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687-768x406.png 768w" sizes="auto, (max-width: 1229px) 100vw, 1229px" /></figure>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">APIs für Anwendungen (CONSUMER)</h2>



<ul class="wp-block-list">
<li><strong>PDH</strong> (Performance Data Helper): Die bequeme API, die Werte bereits formatiert (z. B. Prozentwerte berechnet, Intervalle berücksichtigt). <code>Get-Counter</code> in PowerShell nutzt PDH.</li>



<li style="margin-top:0;margin-bottom:0"><strong>PerfLib / Registry direkt</strong>: Schneller, aber roh. WMI nutzt diesen Weg intern.</li>
</ul>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40)"><strong>Aufbau</strong></p>



<p class="wp-block-paragraph">   \Prozessor(_Total)\Prozessorzeit (%)<br>   └─ Objekt: &#8222;Prozessor&#8220;<br>   └─ Instanz: &#8222;_Total&#8220; (Summe aller Kerne)<br>   └─ Counter: &#8222;Prozessorzeit (%)&#8220;</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Microsofts Tools</h1>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Der Großvater PerfMon</h2>



<p class="wp-block-paragraph">Der Performance Monitor ist seit NT-Zeiten das offizielle Werkzeug von Microsoft und für das, wofür er gebaut wurde, nach wie vor ausgezeichnet: interaktive, grafische Tiefenanalyse einzelner Systeme, mit Aufzeichnung über Data Collector Sets, CSV-Export via <code>relog</code> und grundlegendem Remoting. Die Grenzen zeigen sich, sobald man skalieren, automatisieren oder schlicht im Terminal arbeiten will. Portable Konfigurationsdateien, mehrere Server gleichzeitig im Blick oder ein strukturierter Konsolenworkflow sind nicht seine Stärken.</p>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Der NewComer Windows Admin Center</h2>



<p class="wp-block-paragraph">Microsofts browserbasierte Verwaltungsoberfläche bringt ebenfalls eine Performance-Ansicht mit, übersichtlicher als Perfmon und ohne lokale Installation auf dem verwalteten System. Für einen schnellen Blick auf CPU, Speicher und Netzwerk reicht das völlig aus. Zwei Punkte schränken den praktischen Nutzen jedoch ein: Erstens setzt WAC eine zentrale Installation voraus, mal eben auf einem Client oder beim Kunden starten geht nicht. Zweitens basiert die Counter-Auswahl wie überall auf der lokalisierten PDH-API, was Workspaces nicht wirklich transportabel macht.</p>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Das Evergreen &#8211; Get-Counter</h2>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><code>Get-Counter</code> ist das PowerShell-Äquivalent für den Konsolenbetrieb und damit das flexibelste der drei Werkzeuge, solange man <del>frickeln möchte</del> bereit ist, selbst Hand anzulegen. Counter lassen sich direkt abfragen, per Schleife wiederholen und in die Pipeline schicken. Remoting funktioniert über den <code>-ComputerName</code>-Parameter. Das Problem ist dasselbe wie überall: Die Counter-Pfade sind sprachabhängig, ein auf einem deutschen System geschriebenes Skript schlägt auf einem englischen fehl. Hinzu kommt, dass <code>Get-Counter</code> Rohdaten liefert. Formatierung, Schwellenwerte, Verlaufsdarstellung und strukturierte Ausgabe sind vollständig Handarbeit. Für Einmalabfragen und schnelle Checks ist es ideal, für reproduzierbare, mehrsprachige Umgebungen stößt es schnell an seine Grenzen.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Query CPU, memory and disk counters every 5 seconds, format output as table
$counters = @(
    &#039;\Processor(_Total)\% Processor Time&#039;,
    &#039;\Memory\Available MBytes&#039;,
    &#039;\PhysicalDisk(_Total)\Disk Bytes/sec&#039;
)

# German Counternames
# $counters = @( 
#	&#039;\Processor(_Total)\% Processor Time&#039;, 
#	&#039;\Memory\Available MBytes&#039;, 
#	&#039;\PhysicalDisk(_Total)\Disk Bytes/sec&#039; 
# )

Get-Counter -Counter $counters -SampleInterval 5 -Continuous | ForEach-Object {
    $sample = $_.CounterSamples

    &#x5B;PSCustomObject]@{
        Timestamp       = $_.Timestamp
        &#039;CPU %&#039;         = &#x5B;math]::Round(($sample | Where-Object Path -like &#039;*processor*&#039;).CookedValue, 1)
        &#039;RAM frei (MB)&#039; = &#x5B;math]::Round(($sample | Where-Object Path -like &#039;*available*&#039;).CookedValue, 0)
        &#039;Disk B/s&#039;      = &#x5B;math]::Round(($sample | Where-Object Path -like &#039;*disk bytes*&#039;).CookedValue, 0)
    } | Format-Table -AutoSize
}
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="604" height="546" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323778.png" alt="Series of monitor entries showing time stamps, CPU usage percentages, free RAM (MB), and disk throughput (B/s) across samples." class="wp-image-692" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323778.png 604w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323778-300x271.png 300w" sizes="auto, (max-width: 604px) 100vw, 604px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Der Weg in die Sprachunabhängigkeit</h1>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">Wie ihr seht, ist die Sprachabhängigkeit bei allen Implementierungen ein großes Problem. Dabei ist das gar nicht nötig. Unter der Haube hat jedes Counterobjekt und jeder Counter eine eindeutige ID. Schaut mal oben in den Screenshots, da steht immer First und Last Counter. Somit wird aus <code>\Processor(_Total)\Processor Time (%)</code> &#8211;&gt; <code>\238(_Total)\6</code> .</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Read counter ID/name mapping from registry (English - key 009, German - key 007)
Get-ItemProperty -Path &#039;HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009&#039; -Name Counter |
		Select-Object -ExpandProperty Counter | Select-Object -First 20
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="658" height="498" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323832.png" alt="Side-by-side terminal screenshots showing performance metrics in English (left) and German (right). Left window lists System, Memory, % Processor Time, File Read/Write Operations/sec, File Control Operations/sec, File Read Bytes/sec, File Write Bytes/sec, and a path; right window shows equivalent German terms like Arbeitsspeicher, Prozessorzeit, Lesevorgänge/s, Schreibvorgänge/s, Dateisteuerungen/s, Bytes gelesen/s, Bytes geschrieben/s, etc." class="wp-image-693" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323832.png 658w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323832-300x227.png 300w" sizes="auto, (max-width: 658px) 100vw, 658px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--70)">That&#8217;s it. Nun müssen einmal das Counter-Objekt und der Pfad übersetzt werden und schon habe ich meinen sprachunabhängigen CounterPfad. Vor dem Ausführen wird er auf dem Zielsystem übersetzt und dann <code>Get-Counter -Counter &lt;TRANSLATION&gt;</code> ausgeführt. Das übernimmt in psTerminalPerfcounter das CMDLET <a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/src/psTerminalPerfCounter/psTerminalPerfCounter/Public/Get-tpcPerformanceCounterInfo.ps1" target="_blank" rel="noreferrer noopener"><strong>get-tpcPerformanceCounterInfo</strong></a></p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-container-core-column-is-layout-cc415327 wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="284" height="334" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_3.png" alt="" class="wp-image-355" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_3.png 284w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_3-255x300.png 255w" sizes="auto, (max-width: 284px) 100vw, 284px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_de/</div>
</div><p>The post <a href="https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_de/">Windows Performance Counter: Wie sich das OS selbst überwacht</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_de/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows Performance Counters: How the OS Monitors Itself</title>
		<link>https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_en/</link>
					<comments>https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_en/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sun, 14 Jun 2026 20:01:15 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[eng]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<category><![CDATA[TERMINAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=711</guid>

					<description><![CDATA[<p>Performance counters have been an integral part of the operating system since Windows NT 3.1. In this article I briefly explain how the system works internally, why counter names are language-dependent and how my PowerShell module psTerminalPerfCounter solves exactly that problem.</p>
<p>The post <a href="https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_en/">Windows Performance Counters: How the OS Monitors Itself</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading" style="margin-bottom:var(--wp--preset--spacing--40)">Intro</h1>



<div class="wp-block-columns are-vertically-aligned-center is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50px">
<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="294" height="288" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/GitHub_Invertocat_Black.png" alt="Solid black square placeholder with no visible content." class="wp-image-720" style="aspect-ratio:1.0208344636753297;width:51px;height:auto"/></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><strong><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter" target="_blank" rel="noopener" title="">psTerminalPerfCounter</a></strong></p>
</div>
</div>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)">It has been almost a year now since I started developing psTerminalPerfCounter. Proud of the &#8222;graphical&#8220; implementation, language independence via a 3rd-party lib and the holy grail of the time: classes in PowerShell.</p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--40)">None of it survived:</p>



<ul class="wp-block-list">
<li>Graphical implementation? Nice and colorful, but&#8230;
<ul class="wp-block-list">
<li>Sluggish as a rock in multi-server environments</li>



<li>Dynamic and scalable? Nope</li>



<li>Reimplemented as a TUI (BETA)<br></li>
</ul>
</li>



<li>Multi-language via 3rd-party lib
<ul class="wp-block-list">
<li>Turns out it all works directly through the Windows registry, stumbled across it by accident<br></li>
</ul>
</li>



<li>Classes in PowerShell? Very bad decision.
<ul class="wp-block-list">
<li>Not practical, instances aren&#8217;t easily serializable, methods get lost, parallel remoting with runspaces barely doable</li>



<li>Rebuild in C#</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--50)">With the current release 0.4.1, all the features I had in my backlog are implemented for now. Since I will be lacking the time for this project over the next few months, this is a good moment to write a HowTo, because the README.md in the repo can be a bit challenging at times&#8230; as it seems 🙂 But before we get to the <a href="/psterminalperfcounter-counter-in-terminal-handson_en" title="">hands-on</a>, let&#8217;s first talk a little about the technology and history of performance counters.</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">History</h1>



<p class="wp-block-paragraph">Windows performance counters have been around since <strong>NT 3.1 (1993)</strong>, back then I didn&#8217;t even own a computer. At the time, Microsoft needed a standardized way to expose system states without every application having to implement its own monitoring mechanisms. But that also meant scraping measurement values out of the registry and calculating deltas yourself.</p>



<p class="wp-block-paragraph">Windows 2000 added the <em>Performance Data Helper</em> (PDH) as a convenient high-level API, which shaped access to performance counters the way we know it today. At the same time, WMI was introduced, making performance data accessible through an object-oriented interface. CIM just wasn&#8217;t proprietary enough and a bit too compatible 😛</p>



<p class="wp-block-paragraph"><strong>Windows Vista</strong> brought the revised <strong>Provider V2 model</strong>: instead of a DLL that was loaded by the system into a foreign process (error-prone, provider crash = crash of the querying process), providers now register as standalone executables or services. That is the model still in use today.</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Structure and Function</h1>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><img loading="lazy" decoding="async" width="1241" height="825" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741.png" alt="Diagram of the Applications &amp; Tools stack: PDH and WMI/Perflib feed into Registry, then Performance Counter Provider, then Kernel &amp; Drivers and Usermode Processes." class="wp-image-694" style="width:676px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741.png 1241w, https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741-300x199.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741-1024x681.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/Screenshot_20260611_102741-768x511.png 768w" sizes="auto, (max-width: 1241px) 100vw, 1241px" /></figure>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Metadata in the registry</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--40)">All known counters are registered under <code>HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib</code>. That&#8217;s where the name, description and a numeric index number per counter live, separated by language (subkey <code>009</code> for English, <code>007</code> for German, etc.). </p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List available language packs (counter IDs)
Get-ChildItem &quot;HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib&quot;
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:0"><img loading="lazy" decoding="async" width="1012" height="441" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632.png" alt="Registry view of Perflib under HKEY_LOCAL_MACHINE showing entries like 009 and _V2Providers with Counter/Help text for Windows performance counters in a dark UI." class="wp-image-690" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632.png 1012w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632-300x131.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323632-768x335.png 768w" sizes="auto, (max-width: 1012px) 100vw, 1012px" /></figure>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Providers deliver the raw data</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--40)">Every component (kernel, drivers, services like IIS or SQL Server, the .NET runtime) can register its own counters. The provider waits passively and only delivers data once someone queries it. There is no permanent collection service running in the background.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# List all services that have a Performance subkey

Get-ChildItem &quot;HKLM:\SYSTEM\CurrentControlSet\Services&quot; |
    Where-Object { Test-Path &quot;$($_.PSPath)\Performance&quot; } |
    ForEach-Object {
        $perf = Get-ItemProperty &quot;$($_.PSPath)\Performance&quot;
        &#x5B;PSCustomObject]@{
            Service      = $_.PSChildName
            FirstCounter = $perf.&#039;First Counter&#039;
            LastCounter  = $perf.&#039;Last Counter&#039;
            Library      = $perf.Library
        }
    } | Format-Table -AutoSize
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="1229" height="650" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687.png" alt="Console output listing Windows services with counters and DLL paths (names like .NET CLR Data, IIS, SQL Server) and their FirstCounter/LastCounter values." class="wp-image-691" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687.png 1229w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687-300x159.png 300w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687-1024x542.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323687-768x406.png 768w" sizes="auto, (max-width: 1229px) 100vw, 1229px" /></figure>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">APIs for applications (CONSUMER)</h2>



<ul class="wp-block-list">
<li><strong>PDH</strong> (Performance Data Helper): The convenient API that returns values already formatted (e.g. percentages calculated, intervals taken into account). <code>Get-Counter</code> in PowerShell uses PDH.</li>



<li style="margin-top:0;margin-bottom:0"><strong>PerfLib / registry directly</strong>: Faster, but raw. WMI uses this path internally.</li>
</ul>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40)"><strong>Structure</strong></p>



<p class="wp-block-paragraph">   \Processor(_Total)\% Processor Time<br>   └─ Object: &#8222;Processor&#8220;<br>   └─ Instance: &#8222;_Total&#8220; (sum of all cores)<br>   └─ Counter: &#8222;% Processor Time&#8220;</p>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">Microsoft&#8217;s Tools</h1>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">The grandfather: PerfMon</h2>



<p class="wp-block-paragraph">The Performance Monitor has been Microsoft&#8217;s official tool since the NT days and, for what it was built for, it is still excellent: interactive, graphical deep-dive analysis of individual systems, with recording via Data Collector Sets, CSV export via <code>relog</code> and basic remoting. The limits show up the moment you want to scale, automate or simply work in the terminal. Portable configuration files, keeping an eye on multiple servers at once or a structured console workflow are not its strengths.</p>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">The newcomer: Windows Admin Center</h2>



<p class="wp-block-paragraph">Microsoft&#8217;s browser-based management interface also comes with a performance view, cleaner than Perfmon and without a local installation on the managed system. For a quick look at CPU, memory and network that&#8217;s perfectly fine. Two things limit its practical value though: first, WAC requires a central installation, just quickly firing it up on a client or at a customer&#8217;s site isn&#8217;t an option. Second, the counter selection is based, as everywhere, on the localized PDH API, which makes workspaces not really portable.</p>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">The evergreen: Get-Counter</h2>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><code>Get-Counter</code> is the PowerShell equivalent for console use and therefore the most flexible of the three tools, as long as you&#8217;re <del>up for some fiddling</del> willing to get your hands dirty. Counters can be queried directly, repeated in a loop and sent down the pipeline. Remoting works via the <code>-ComputerName</code> parameter. The problem is the same as everywhere: the counter paths are language-dependent, a script written on a German system fails on an English one. On top of that, <code>Get-Counter</code> returns raw data. Formatting, thresholds, history visualization and structured output are entirely manual work. For one-off queries and quick checks it&#8217;s ideal, for reproducible, multi-language environments it quickly hits its limits.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Query CPU, memory and disk counters every 5 seconds, format output as table
$counters = @(
    &#039;\Processor(_Total)\% Processor Time&#039;,
    &#039;\Memory\Available MBytes&#039;,
    &#039;\PhysicalDisk(_Total)\Disk Bytes/sec&#039;
)

# German Counternames
# $counters = @( 
#	&#039;\Processor(_Total)\% Processor Time&#039;, 
#	&#039;\Memory\Available MBytes&#039;, 
#	&#039;\PhysicalDisk(_Total)\Disk Bytes/sec&#039; 
# )

Get-Counter -Counter $counters -SampleInterval 5 -Continuous | ForEach-Object {
    $sample = $_.CounterSamples

    &#x5B;PSCustomObject]@{
        Timestamp       = $_.Timestamp
        &#039;CPU %&#039;         = &#x5B;math]::Round(($sample | Where-Object Path -like &#039;*processor*&#039;).CookedValue, 1)
        &#039;RAM frei (MB)&#039; = &#x5B;math]::Round(($sample | Where-Object Path -like &#039;*available*&#039;).CookedValue, 0)
        &#039;Disk B/s&#039;      = &#x5B;math]::Round(($sample | Where-Object Path -like &#039;*disk bytes*&#039;).CookedValue, 0)
    } | Format-Table -AutoSize
}
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="604" height="546" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323778.png" alt="Series of monitor entries showing time stamps, CPU usage percentages, free RAM (MB), and disk throughput (B/s) across samples." class="wp-image-692" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323778.png 604w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323778-300x271.png 300w" sizes="auto, (max-width: 604px) 100vw, 604px" /></figure>



<h1 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--40)">The path to language independence</h1>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)">As you can see, language dependence is a big problem across all implementations. And it&#8217;s not even necessary. Under the hood, every counter object and every counter has a unique ID. Take a look at the screenshots above, there&#8217;s always a First and Last Counter. So <code>\Processor(_Total)\Processor Time (%)</code> &#8211;&gt; <code>\238(_Total)\6</code> .</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Read counter ID/name mapping from registry (English - key 009, German - key 007)
Get-ItemProperty -Path &#039;HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009&#039; -Name Counter |
		Select-Object -ExpandProperty Counter | Select-Object -First 20
</pre></div>


<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="658" height="498" src="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323832.png" alt="Side-by-side terminal screenshots showing performance metrics in English (left) and German (right). Left window lists System, Memory, % Processor Time, File Read/Write Operations/sec, File Control Operations/sec, File Read Bytes/sec, File Write Bytes/sec, and a path; right window shows equivalent German terms like Arbeitsspeicher, Prozessorzeit, Lesevorgänge/s, Schreibvorgänge/s, Dateisteuerungen/s, Bytes gelesen/s, Bytes geschrieben/s, etc." class="wp-image-693" srcset="https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323832.png 658w, https://dbavonnebenan.de/wp-content/uploads/2026/06/IMG-20260611100323832-300x227.png 300w" sizes="auto, (max-width: 658px) 100vw, 658px" /></figure>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--70)">That&#8217;s it. The counter object and the path just need to be translated once and I&#8217;ve got my language-independent counter path. Before execution it gets translated on the target system and then <code>Get-Counter -Counter &lt;TRANSLATION&gt;</code> is run. In psTerminalPerfCounter this is handled by the cmdlet <a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/src/psTerminalPerfCounter/psTerminalPerfCounter/Public/Get-tpcPerformanceCounterInfo.ps1" target="_blank" rel="noreferrer noopener"><strong>get-tpcPerformanceCounterInfo</strong></a></p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-container-core-column-is-layout-cc415327 wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="284" height="334" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_3.png" alt="" class="wp-image-355" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_3.png 284w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_3-255x300.png 255w" sizes="auto, (max-width: 284px) 100vw, 284px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">https://dbavonnebenan.de/psterminalperfcounter-counter-in-terminal-handson_en/</div>
</div><p>The post <a href="https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_en/">Windows Performance Counters: How the OS Monitors Itself</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/windows-performance-counters-how-the-os-monitors-itself_en/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automate SQL Server HA: AD, SPN, and Cluster Setup</title>
		<link>https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_en/</link>
					<comments>https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_en/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Fri, 06 Feb 2026 11:47:28 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Sql Server]]></category>
		<category><![CDATA[AD]]></category>
		<category><![CDATA[AlwaysOn]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[eng]]></category>
		<category><![CDATA[GMSA]]></category>
		<category><![CDATA[SPN]]></category>
		<category><![CDATA[WSFC]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=669</guid>

					<description><![CDATA[<p>Production-Ready Windows Cluster Deployment: Automation of Failover Cluster, gMSA, Kerberos and local rights via PowerShell.</p>
<p>The post <a href="https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_en/">Automate SQL Server HA: AD, SPN, and Cluster Setup</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="border: 1px dotted #eb2b14;border-radius: 6px;background-color: #eeeeee;padding-top: var(--wp--preset--spacing--30);padding-left: var(--wp--preset--spacing--30);padding-right: var(--wp--preset--spacing--30);padding-bottom: var(--wp--preset--spacing--30)" class="ub-styled-box ub-bordered-box wp-block-ub-styled-box" id="ub-styled-box-11670a24-effc-43d1-9b6f-f1421b3d4c12">
<p class="has-open-sauce-sans-font-family wp-block-paragraph" style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" id="ub-styled-box-bordered-content-">What awaits you here?</p>



<ul style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" class="wp-block-list has-open-sauce-sans-font-family">
<li><a href="#WSFC" title="">Windows Server Failover Cluster Deployment with Extended AD and DNS Permissions</a></li>



<li><a href="#GMSA" title="">Identity Management: Group Managed Service Accounts (gMSA)</a></li>



<li><a href="#KERBEROS" title="">Kerberos and Service Principal Names (SPN)</a></li>



<li><a href="#LSP" title="">Local Security Policies</a></li>



<li>Background knowledge on why configurations are done the way they are</li>
</ul>


</div>


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>


https://github.com/gabrielkoehl/DBAScriptBox


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="0-intro" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p class="wp-block-paragraph">Who hasn&#8217;t been there? Before you can even start installing SQL Server, you&#8217;ve either repetitively clicked through pages of bad GUIs or, if available, juggled a loose collection of scripts to semi-automatically set up all dependencies and best practices.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:90%">
<p class="wp-block-paragraph">Even worse is the case when, as a consultant, you don&#8217;t have Domain Admin access (which is how it should be) and you have to guide the customer — who may have never done this before — via Teams &amp; Co. If this isn&#8217;t already a planned installation with knowledge transfer, something like this creates pain. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f92d.png" alt="🤭" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
</div>



<div class="wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:10%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="264" height="329" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png" alt="PAIN Emote" class="wp-image-516" style="aspect-ratio:0.8024665981500514;width:65px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png 264w, https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4-241x300.png 241w" sizes="auto, (max-width: 264px) 100vw, 264px" /></figure>
</div>
</div>



<p class="wp-block-paragraph">Accordingly, I&#8217;ve now gathered all my loose scripts and developed a function for each topic area that automates all these tasks and logs them for archival purposes. Thanks also to Claude for the support. Nobody reviews and documents code better than Claude. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f60b.png" alt="😋" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p class="wp-block-paragraph">Now you might ask: Aren&#8217;t there dbatools and DSC? Sure, I like using those too. But transparent, traceable scripts without framework overhead convey knowledge better — especially when aspiring DBAs lack the big-picture perspective. Operating SQL Server starts at the bare metal, goes through storage, Windows Server, Active Directory, and ends at a Certificate Authority. And for critical infrastructure companies or small mid-sized businesses with 3 clusters, I don&#8217;t want to start a fundamental discussion about dbatools or DSC right from the beginning.</p>



<p class="wp-block-paragraph">Let&#8217;s start with a production-ready Windows Server Failover Cluster — including CNO/VCO permissions, DNS registration, and quorum configuration. Everything repeatable, everything logged, everything traceable.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="1-das-lab-szenario" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">The Lab Scenario</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--40)">To make the steps tangible, the following environment and naming conventions are used</p>



<ul class="wp-block-list">
<li><strong>Nodes</strong>
<ul class="wp-block-list">
<li><code>LAB-NODE01</code> (192.168.100.12)</li>



<li><code>LAB-NODE02</code> (192.168.100.13)</li>
</ul>
</li>



<li><strong>Cluster Name</strong>
<ul class="wp-block-list">
<li><code>MSSQL-CL-01</code> (192.168.100.14)</li>
</ul>
</li>



<li><strong>SQL Instance</strong>
<ul class="wp-block-list">
<li><code>LAB22A</code></li>
</ul>
</li>



<li><strong>Domain</strong>
<ul class="wp-block-list">
<li><code>lab.local</code></li>
</ul>
</li>



<li><strong>Service Accounts</strong> Group Managed Service Accounts (gMSA)
<ul class="wp-block-list">
<li><code>g-LAB22A-oltp</code></li>



<li><code>g-LAB22A-agnt</code></li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"/>



<h2 class="wp-block-heading" id="WSFC" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Windows Server Failover Cluster Deployment </h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/system/cluster_manageSQLCluster.ps1" target="_blank" rel="noopener" title="cluster_manageSQLCluster.ps1"><code>cluster_manageSQLCluster.ps1</code></a></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/system/cluster_manageSQLCluster.md" target="_blank" rel="noopener" title="cluster_manageSQLCluster.md">cluster_manageSQLCluster.md</a></code></p>
</div>
</div>
</div>
</div>



<div style="height:14px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-text-align-left wp-block-paragraph">The WSFC forms the foundation for AlwaysOn Availability Groups. The script manages the entire lifecycle from feature installation to witness configuration.</p>



<h3 class="wp-block-heading has-text-align-left" id="3-feature-installation-amp-cluster-erstellung" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Feature Installation &amp; Cluster Creation</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">First, the <code>Failover-Clustering</code> feature is installed on the individual nodes and the cluster is created. An important aspect of automation is the Cluster Name Object (CNO): It needs write permissions in DNS and Active Directory to be able to automatically create listener records later. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; auto-links: false; title: ; notranslate">
.\cluster_manageSQLCluster.ps1 `
    -Operation InstallFeature `
    -Nodes &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -LogPath &quot;C:\Temp\Cluster_Feature_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<p class="has-text-align-left wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Afterwards, the cluster is created. The script additionally sets the corresponding permissions in AD and DNS.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\cluster_manageSQLCluster.ps1 `
    -Operation CreateCluster `
    -ClusterName &quot;MSSQL-CL-01&quot; `
    -Nodes &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -StaticIP &quot;192.168.100.14&quot; `
    -DnsDomain &quot;lab.local&quot; `
    -TargetOU &quot;OU=lab_computer,DC=lab,DC=local&quot; `
    -LogPath &quot;C:\Temp\Cluster_Create_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" id="4-file-share-witness-quorum" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">File Share Witness (Quorum)</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">For a 2-node cluster, a witness is mandatory to avoid split-brain scenarios. Here, a file share on the domain controller (<code>\\LAB-DC\quorum$</code>) is used. </p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Manual Intermediate Step</strong><br>The Cluster Computer Object (<code>MSSQL-CL-01$</code>) requires <strong>Full Control</strong> at both the share and NTFS permission level of the witness path (<code>\\LAB-DC\quorum$</code>). This must be ensured before running the following command.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\cluster_manageSQLCluster.ps1 `
    -Operation SetWitness `
    -ClusterName &quot;MSSQL-CL-01&quot; `
    -WitnessShare &quot;\\LAB-DC\quorum$&quot; `
    -LogPath &quot;C:\Temp\Cluster_Witness_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" id="5-verwendete-microsoft-cmdlets" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Microsoft Cmdlets Used</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">The script primarily uses the <a href="https://learn.microsoft.com/en-us/powershell/module/failoverclusters/" target="_blank" rel="noopener" title="FailoverClusters"><code>FailoverClusters</code></a> module</p>



<ul style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)" class="wp-block-list">
<li><code>New-Cluster</code>
<ul class="wp-block-list">
<li>Creates the cluster, adds the nodes, and sets the management IP</li>
</ul>
</li>



<li><code>Set-ClusterQuorum</code>
<ul class="wp-block-list">
<li>Configures the witness mode (here: File Share Witness)</li>
</ul>
</li>



<li><code>Install-WindowsFeature</code>
<ul class="wp-block-list">
<li>Installs the RSAT tools and the cluster service</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" id="GMSA" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Identity Management: gMSA</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_createGMSA.ps1" target="_blank" rel="noopener" title="security_createGMSA.ps1"><code>security_createGMSA.ps1</code></a></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_createGMSA.md" target="_blank" rel="noopener" title="security_createGMSA.md"><code>security_createGMSA.md</code></a></p>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Using standard users as service accounts can lead to expired passwords and downtime. The recommended method for SQL Server is <a href="https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-managed-service-accounts/group-managed-service-accounts/group-managed-service-accounts-overview" target="_blank" rel="noopener" title="gMSA"><code>Group Managed Service Accounts (gMSA)</code></a>. Here, the Key Distribution Service (KDS) of Active Directory handles password rotation; nobody needs to know the password.</p>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:0;margin-bottom:var(--wp--preset--spacing--50);margin-left:0">KDS Root Key</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Before the first gMSA can be created, a KDS Root Key must exist once per forest. If a key already exists, the creation will be skipped.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\security_createGMSA.ps1 `
    -InitializeKDS `
    -LogPath &quot;C:\Temp\KDS_Init.log&quot;
</pre></div>


<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:0;margin-bottom:var(--wp--preset--spacing--50);margin-left:0">gMSA Creation</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Instead of assigning servers directly to a gMSA, it is best practice to create a security group (<code>SQL_LAB_CL01</code>) that contains the computer accounts of the cluster nodes. In addition to setting up the actual gMSA, this script can also create the security groups and handle the assignments. And always keep the descriptions of AD objects well-maintained. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\security_createGMSA.ps1 `
    -AccountName @( `
        @(&quot;g-LAB22A-oltp&quot;, &quot;SQL Server Engine Account for LAB22A&quot;), `
        @(&quot;g-LAB22A-agnt&quot;, &quot;SQL Server Agent Account for LAB22A&quot;) ) `
    -SecurityGroupName &quot;SQL_LAB_CL01&quot; `
    -SecurityGroupDescription &quot;SQL Server Cluster CL01 gMSA Group&quot; `
    -ServerNames &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -CreateSecurityGroup `
    -SecurityGroupOU &quot;OU=lab_secgrp,DC=lab,DC=local&quot; `
    -PasswordIntervalDays 90 `
    -LogPath &quot;C:\Temp\gMSA_Creation_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">After this step, a restart of the nodes is required for the new group membership to take effect.</p>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:0;margin-bottom:var(--wp--preset--spacing--50);margin-left:0">Local Registration</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">After creation, the gMSAs must be registered locally on the nodes. The following script can be used for this purpose.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Required for local setup (Local Admin)
Add-WindowsFeature -Name RSAT-AD-PowerShell

$gMSAs = @(
    &#039;g-LAB22A-oltp&#039;,
    &#039;g-LAB22A-agnt&#039;
)

foreach ($gMSA in $gMSAs) {

    if (Test-ADServiceAccount -Identity $gMSA -ErrorAction SilentlyContinue) {
        try {
            Install-ADServiceAccount -Identity $gMSA -ErrorAction Stop
            Write-Host &quot;$gMSA installed&quot; -ForegroundColor Green
        } catch {
            Write-Host &quot;$gMSA - Installation error: $($_.Exception.Message)&quot; -ForegroundColor Red
        }
    } else {
        Write-Host &quot;$gMSA does not exist&quot; -ForegroundColor Yellow
    }
}
</pre></div>


<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">After this step, a restart of the nodes is required for the new group membership to take effect.</p>



<h3 class="wp-block-heading" id="5-verwendete-microsoft-cmdlets" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Microsoft Cmdlets Used</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">The script primarily uses the <a href="https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2025-ps" target="_blank" rel="noopener" title="ActiveDirectory"><code>ActiveDirectory</code></a> module</p>



<ul style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)" class="wp-block-list">
<li><code>Add-KdsRootKey</code>
<ul class="wp-block-list">
<li>Creates the root key for the Group Key Distribution Service</li>
</ul>
</li>



<li><code>New-ADServiceAccount</code>
<ul class="wp-block-list">
<li>Creates the gMSA object in AD</li>
</ul>
</li>



<li><code>Set-ADServiceAccount</code>
<ul class="wp-block-list">
<li>Configures which computers (PrincipalsAllowedToRetrieveManagedPassword) are allowed to read the password</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" id="KERBEROS" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Kerberos and Service Principal Names (SPN)</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlSpn.ps1" target="_blank" rel="noopener" title="cluster_manageSQLCluster.ps1">security_setSqlSpn.ps1</a></code></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlSpn.md" target="_blank" rel="noopener" title="">security_setSqlSpn</a></code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlSpn.md" title=""><code>.</code>md</a></p>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">A gMSA does not have the right to write its own SPNs in AD by default. When the SQL service starts, the registration often fails, leading to NTLM fallbacks. Even though I prefer to set SPNs in a controlled and manual manner, the automatic registration must be technically possible to avoid fallbacks.</p>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)">The script solves this problem by granting the gMSA the rights in AD to manage its own SPNs, in addition to creating the SPNs. It sets ACLs on the nodes for <code>Read</code>, <code>Write</code>, and <code>Validated write</code> on the <code>servicePrincipalName</code> attribute.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\security_setSqlSpn.ps1 `
    -ServiceAccount &quot;LAB\g-LAB22A-oltp&quot; `
    -InstanceName &quot;LAB22A&quot; `
    -Port 51101 `
    -Hostnames &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -Domain &quot;lab.local&quot; `
    -IsGMSA `
    -SetADPermissions `
    -LogPath &quot;C:\Temp\SPN_AlwaysOn_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" id="5-verwendete-microsoft-cmdlets" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Microsoft Cmdlets Used</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">On one hand, <a href="https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setspn" target="_blank" rel="noopener" title="setspn.exe"><code>setspn.exe</code></a> is used for SPN management, and on the other hand, the <a href="https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2025-ps" target="_blank" rel="noopener" title=""><code>ActiveDirectory</code></a> module is used again to verify accounts and extract SIDs.</p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Since none of the modules can manipulate Active Directory permissions, the .NET Framework <a href="https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices?view=windowsdesktop-10.0" target="_blank" rel="noopener" title="System.DirectoryServices"><code>System.DirectoryServices</code></a> is used directly for this purpose, which provides various classes to completely turn AD inside out. </p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" id="LSP" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Local Security Policies</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlLocalSec.ps1" target="_blank" rel="noopener" title="security_setSqlLocalSec.ps1">security_setSqlLocalSec.ps1</a></code></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlLocalSec.md" target="_blank" rel="noopener" title=""><code>security_setSqlLocalSec.md</code></a></p>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">As everywhere in IT, SQL Server should also follow the <a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege" target="_blank" rel="noopener" title="PoLP"><code>PoLP</code></a>, which is why no service account gets local administrator privileges. For SQL Server to still run flawlessly and performantly, the service account needs specific rights in the operating system (&#8222;User Rights Assignment&#8220;). Anyone who has done this manually a few times will be very happy about this solution. This must be executed locally on the respective node.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# ===== Set Engine Permissions for gMSA =====

    .\security_setSqlLocalSec.ps1 `
        -ServiceAccount &quot;g-LAB22A-oltp$&quot; `
        -ServiceType &quot;engine&quot; `
        -IsGMSA `
        -LogPath &quot;C:\Temp\LAB22A_Engine_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;

# ===== Set Agent Permissions for gMSA =====

    .\security_setSqlLocalSec.ps1 `
        -ServiceAccount &quot;g-LAB22A-agnt$&quot; `
        -ServiceType &quot;agent&quot; `
        -IsGMSA `
        -LogPath &quot;C:\Temp\LAB22A_Agent_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Microsoft Cmdlets Used</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Since PowerShell has no native cmdlets for editing local security policies, the Windows tool <a href="https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/secedit" target="_blank" rel="noopener" title="secedit.exe"><code>secedit.exe</code></a> is used and its export is manipulated.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Summary</h2>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">With these four building blocks, the foundation for a SQL Server installation has been laid. It wasn&#8217;t just an installation that was performed, but a valid, documented configuration that considers identity (gMSA), network (DNS/SPN), and OS performance. In the next step, the actual SQL Server instance can be installed.</p>



<p class="wp-block-paragraph">Also check out the linked MD files — they contain background information on best practices and further articles from Microsoft</p>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><img loading="lazy" decoding="async" width="307" height="328" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2.png" alt="good to know emote" class="wp-image-345" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2.png 307w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2-281x300.png 281w" sizes="auto, (max-width: 307px) 100vw, 307px" /></figure><p>The post <a href="https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_en/">Automate SQL Server HA: AD, SPN, and Cluster Setup</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_en/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server HA: AD, SPN und Cluster Setup automatisieren</title>
		<link>https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_de/</link>
					<comments>https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_de/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Fri, 06 Feb 2026 11:20:00 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Sql Server]]></category>
		<category><![CDATA[AD]]></category>
		<category><![CDATA[AlwaysOn]]></category>
		<category><![CDATA[DE]]></category>
		<category><![CDATA[Deployment]]></category>
		<category><![CDATA[GMSA]]></category>
		<category><![CDATA[SPN]]></category>
		<category><![CDATA[WSFC]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=641</guid>

					<description><![CDATA[<p>Production-Ready Windows Cluster Deployment: Automatisierung von Failover Cluster, gMSA, Kerberos und lokalen Rechten via PowerShell.</p>
<p>The post <a href="https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_de/">SQL Server HA: AD, SPN und Cluster Setup automatisieren</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="border: 1px dotted #eb2b14;border-radius: 6px;background-color: #eeeeee;padding-top: var(--wp--preset--spacing--30);padding-left: var(--wp--preset--spacing--30);padding-right: var(--wp--preset--spacing--30);padding-bottom: var(--wp--preset--spacing--30)" class="ub-styled-box ub-bordered-box wp-block-ub-styled-box" id="ub-styled-box-8bf7c8f5-ed36-44d1-82b0-6849bd1507a5">
<p class="has-open-sauce-sans-font-family wp-block-paragraph" style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" id="ub-styled-box-bordered-content-">Was erwartet dich hier?</p>



<ul style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" class="wp-block-list has-open-sauce-sans-font-family">
<li><a href="#WSFC" title="">Windows Server Failover Cluster Deployment mit erweiterten AD- und DNS-Berechtigungen</a></li>



<li><a href="#GMSA" title="">Identity Management: Group Managed Service Accounts (gMSA)</a></li>



<li><a href="#KERBEROS" title="">Kerberos und Service Principal Names (SPN)</a></li>



<li><a href="#LSP" title="">Lokale Sicherheitsrichtlinien (Local Security Policies)</a></li>



<li>Hintergrundwissen warum Konfigurationen gemacht werden wie sie gemacht werden</li>
</ul>


</div>


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>


https://github.com/gabrielkoehl/DBAScriptBox


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="0-intro" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p class="wp-block-paragraph">Wer kennt es nicht? Bevor man überhaupt mit der Installation von SQL Server loslegen kann, hat man sich entweder repetitiv durch seitenweise schlechte GUIs geklickt oder wenn verfügbar, mit einer losen Sammlung an Scripten jongliert und semiautomatisch alle Abhängigkeiten und Best Practices eingerichtet.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:80%">
<p class="wp-block-paragraph">Noch schlimmer ist der Fall, wenn man als Berater gar keinen Domain Admin hat (was auch so sein sollte) und man den Kunden, der dies vielleicht noch nie gemacht hat, per Teams &amp; Co anleiten muss. Wenn dies nicht eh eine geplante Installation mit Know-how-Transfer ist, erzeugt so etwas Schmerz. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f92d.png" alt="🤭" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="264" height="329" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png" alt="PAIN Emote" class="wp-image-516" style="aspect-ratio:0.8024665981500514;width:75px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png 264w, https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4-241x300.png 241w" sizes="auto, (max-width: 264px) 100vw, 264px" /></figure>
</div>
</div>



<p class="wp-block-paragraph">Dementsprechend habe ich nun mal all meine losen Scripte zusammengewürfelt und für jeden Themenbereich eine recht umfangreiche Funktion entwickelt, welche all diese Tasks automatisiert und für Archivzwecke loggt. Danke auch an Claude für die Unterstützung. Keiner kontrolliert und dokumentiert Code besser als Claude. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f60b.png" alt="😋" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p class="wp-block-paragraph">Nun könnte man sich fragen: Es gibt doch dbatools und DSC? Klar, nutze ich auch gerne. Aber transparente, nachvollziehbare Scripts ohne Framework-Overhead vermitteln Wissen besser &#8211; gerade wenn angehenden DBAs der Blick fürs Ganze fehlt. Betrieb von SQL Server fängt auf dem Blech an, geht über Storage, Windows Server, Active Directory und hört bei einer Certificate Authority auf. Und bei KRITIS-Unternehmen oder kleinen Mittelständlern mit 3 Clustern will ich zu Beginn keine Grundsatzdiskussion über dbatools oder DSC führen.</p>



<p class="wp-block-paragraph">Los geht&#8217;s mit einem Production-Ready Windows Server Failover Cluster &#8211; inklusive CNO/VCO-Berechtigungen, DNS-Registrierung und Quorum-Konfiguration. Alles wiederholbar, alles geloggt, alles nachvollziehbar.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="1-das-lab-szenario" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Das Lab Szenario</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--40)">Um die Schritte greifbar zu machen, wird folgende Umgebung und Naming-Conventions genutzt</p>



<ul class="wp-block-list">
<li><strong>Nodes</strong>
<ul class="wp-block-list">
<li><code>LAB-NODE01</code> (192.168.100.12)</li>



<li><code>LAB-NODE02</code> (192.168.100.13)</li>
</ul>
</li>



<li><strong>Cluster Name</strong>
<ul class="wp-block-list">
<li><code>MSSQL-CL-01</code> (192.168.100.14)</li>
</ul>
</li>



<li><strong>SQL Instanz</strong>
<ul class="wp-block-list">
<li><code>LAB22A</code></li>
</ul>
</li>



<li><strong>Domain</strong>
<ul class="wp-block-list">
<li><code>lab.local</code></li>
</ul>
</li>



<li><strong>Service Accounts</strong> Group Managed Service Accounts (gMSA)
<ul class="wp-block-list">
<li><code>g-LAB22A-oltp</code></li>



<li><code>g-LAB22A-agnt</code></li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"/>



<h2 class="wp-block-heading" id="WSFC" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Windows Server Failover Cluster Deployment </h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/system/cluster_manageSQLCluster.ps1" target="_blank" rel="noopener" title="cluster_manageSQLCluster.ps1"><code>cluster_manageSQLCluster.ps1</code></a></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/system/cluster_manageSQLCluster.md" target="_blank" rel="noopener" title="cluster_manageSQLCluster.md">cluster_manageSQLCluster.md</a></code></p>
</div>
</div>
</div>
</div>



<div style="height:14px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="has-text-align-left wp-block-paragraph">Der WSFC bildet das Fundament für AlwaysOn Availability Groups. Das Script steuert den gesamten Lifecycle von der Feature-Installation bis zur Witness-Konfiguration.</p>



<h3 class="wp-block-heading has-text-align-left" id="3-feature-installation-amp-cluster-erstellung" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Feature Installation &amp; Cluster Erstellung</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Zunächst wird das Feature <code>Failover-Clustering</code> auf den einzelnen Nodes installiert und der Cluster erstellt. Ein wichtiger Aspekt bei der Automatisierung ist das Cluster-Objekt (CNO): Es benötigt Schreibrechte im DNS und Active Directory um später automatisiert Listener-Records anlegen zu können. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; auto-links: false; title: ; notranslate">
.\cluster_manageSQLCluster.ps1 `
    -Operation InstallFeature `
    -Nodes &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -LogPath &quot;C:\Temp\Cluster_Feature_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<p class="has-text-align-left wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Anschließend wird der Cluster erstellt. Das Script setzt zusätzlich die entsprechenden Berechtigungen in AD und DNS.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\cluster_manageSQLCluster.ps1 `
    -Operation CreateCluster `
    -ClusterName &quot;MSSQL-CL-01&quot; `
    -Nodes &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -StaticIP &quot;192.168.100.14&quot; `
    -DnsDomain &quot;lab.local&quot; `
    -TargetOU &quot;OU=lab_computer,DC=lab,DC=local&quot; `
    -LogPath &quot;C:\Temp\Cluster_Create_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" id="4-file-share-witness-quorum" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">File Share Witness (Quorum)</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Für einen 2-Node Cluster ist ein Witness zwingend erforderlich, um Split-Brain-Szenarien zu vermeiden. Hier wird ein File Share auf dem Domain Controller (<code>\\LAB-DC\quorum$</code>) genutzt. </p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Manueller Zwischenschritt</strong><br>Das Cluster-Computer-Objekt (<code>MSSQL-CL-01$</code>) benötigt <strong>Full Control</strong> auf Ebene der Share- und NTFS-Berechtigungen des Witness-Pfads (<code>\\LAB-DC\quorum$</code>). Dies muss vor dem folgenden Befehl sichergestellt sein.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\cluster_manageSQLCluster.ps1 `
    -Operation SetWitness `
    -ClusterName &quot;MSSQL-CL-01&quot; `
    -WitnessShare &quot;\\LAB-DC\quorum$&quot; `
    -LogPath &quot;C:\Temp\Cluster_Witness_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" id="5-verwendete-microsoft-cmdlets" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Verwendete Microsoft Cmdlets</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Das Script nutzt primär das <a href="https://learn.microsoft.com/en-us/powershell/module/failoverclusters/" target="_blank" rel="noopener" title="FailoverClusters"><code>FailoverClusters</code></a> Modul</p>



<ul style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)" class="wp-block-list">
<li><code>New-Cluster</code>
<ul class="wp-block-list">
<li>Erstellt den Cluster, bindet die Nodes ein und setzt die Management-IP</li>
</ul>
</li>



<li><code>Set-ClusterQuorum</code>
<ul class="wp-block-list">
<li>Konfiguriert den Witness-Modus (hier: File Share Witness)</li>
</ul>
</li>



<li><code>Install-WindowsFeature</code>
<ul class="wp-block-list">
<li>Installiert die RSAT-Tools und den Cluster-Dienst</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" id="GMSA" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Identity Management: gMSA</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_createGMSA.ps1" target="_blank" rel="noopener" title="security_createGMSA.ps1"><code>security_createGMSA.ps1</code></a></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_createGMSA.md" target="_blank" rel="noopener" title="security_createGMSA.md"><code>security_createGMSA.md</code></a></p>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Die Nutzung von Standard-Usern als Service Accounts kann zu abgelaufenen Passwörtern und Downtime führen. Die empfohlene Methode für SQL Server sind <a href="https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-managed-service-accounts/group-managed-service-accounts/group-managed-service-accounts-overview" target="_blank" rel="noopener" title="gMSA"><code>Group Managed Service Accounts (gMSA)</code></a>. Hierbei übernimmt der Key Distribution Service (KDS) des Active Directory die Passwortrotation; Niemand muss das Passwort kennen.</p>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:0;margin-bottom:var(--wp--preset--spacing--50);margin-left:0">KDS Root Key</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Bevor der erste gMSA erstellt werden kann, muss einmalig pro Forest ein KDS Root Key existieren. Sollte bereits ein Key existieren, wird die Erstellung übersprungen.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\security_createGMSA.ps1 `
    -InitializeKDS `
    -LogPath &quot;C:\Temp\KDS_Init.log&quot;
</pre></div>


<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:0;margin-bottom:var(--wp--preset--spacing--50);margin-left:0">gMSA Erstellung</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Anstatt Server direkt einem gMSA zuzuordnen, ist es Best Practice, eine Security Group zu erstellen (<code>SQL_LAB_CL01</code>), welche die Computerkonten der Cluster-Nodes enthält. Neben der Einrichtung der eigentlichen gMSA kann dieses Script auch die Security Gruppen erstellen und die Zuordnungen vornehmen. Und immer schön die Beschreibungen bei AD-Objekten pflegen. </p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\security_createGMSA.ps1 `
    -AccountName @( `
        @(&quot;g-LAB22A-oltp&quot;, &quot;SQL Server Engine Account for LAB22A&quot;), `
        @(&quot;g-LAB22A-agnt&quot;, &quot;SQL Server Agent Account for LAB22A&quot;) ) `
    -SecurityGroupName &quot;SQL_LAB_CL01&quot; `
    -SecurityGroupDescription &quot;SQL Server Cluster CL01 gMSA Group&quot; `
    -ServerNames &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -CreateSecurityGroup `
    -SecurityGroupOU &quot;OU=lab_secgrp,DC=lab,DC=local&quot; `
    -PasswordIntervalDays 90 `
    -LogPath &quot;C:\Temp\gMSA_Creation_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">Nach diesem Schritt ist ein Neustart der Nodes erforderlich, damit die neue Gruppenmitgliedschaft wirksam wird.</p>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:0;margin-bottom:var(--wp--preset--spacing--50);margin-left:0">Lokale Registrierung</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Nach der Erstellung müssen die gMSA lokal auf den Nodes registriert werden. Hierzu kann folgendes  Script genutzt werden.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Wichtig für lokale Einrichtung ( Local Admin )
Add-WindowsFeature -Name RSAT-AD-PowerShell

$gMSAs = @(
    &#039;g-LAB22A-oltp&#039;,
    &#039;g-LAB22A-agnt&#039;
)

foreach ($gMSA in $gMSAs) {

    if (Test-ADServiceAccount -Identity $gMSA -ErrorAction SilentlyContinue) {
        try {
            Install-ADServiceAccount -Identity $gMSA -ErrorAction Stop
            Write-Host &quot;$gMSA installiert&quot; -ForegroundColor Green
        } catch {
            Write-Host &quot;$gMSA - Fehler bei Installation: $($_.Exception.Message)&quot; -ForegroundColor Red
        }
    } else {
        Write-Host &quot;$gMSA existiert nicht&quot; -ForegroundColor Yellow
    }
}
</pre></div>


<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">Nach diesem Schritt ist ein Neustart der Nodes erforderlich, damit die neue Gruppenmitgliedschaft (TGT) wirksam wird.</p>



<h3 class="wp-block-heading" id="5-verwendete-microsoft-cmdlets" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Verwendete Microsoft Cmdlets</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Das Script nutzt primär das <a href="https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2025-ps" target="_blank" rel="noopener" title="ActiveDirectory"><code>ActiveDirectory</code></a> Modul</p>



<ul style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)" class="wp-block-list">
<li><code>Add-KdsRootKey</code>
<ul class="wp-block-list">
<li>Erzeugt den Root Key für den Group Key Distribution Service</li>
</ul>
</li>



<li><code>New-ADServiceAccount</code>
<ul class="wp-block-list">
<li>Erstellt das gMSA Objekt im AD</li>
</ul>
</li>



<li><code>Set-ADServiceAccount</code>
<ul class="wp-block-list">
<li>Konfiguriert, welche Computer (PrincipalsAllowedToRetrieveManagedPassword) das Passwort lesen dürfen</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" id="KERBEROS" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Kerberos und Service Principal Names (SPN)</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlSpn.ps1" target="_blank" rel="noopener" title="cluster_manageSQLCluster.ps1">security_setSqlSpn.ps1</a></code></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlSpn.md" target="_blank" rel="noopener" title="">security_setSqlSpn</a></code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlSpn.md" title=""><code>.</code>md</a></p>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Ein gMSA besitzt standardmäßig nicht das Recht, seine eigenen SPNs im AD zu schreiben. Startet der SQL Dienst, schlägt die Registrierung oft fehl, was zu NTLM-Fallbacks führt. Auch wenn ich SPNs bevorzugt kontrolliert und manuell setze, muss die automatische Registrierung technisch möglich sein, um Fallbacks zu vermeiden.</p>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)">Das Script löst dieses Problem, indem es zusätzlich zur SPN Erstellung dem gMSA die Rechte im AD gewährt, seine eigenen SPNs zu verwalten. Es setzt ACLs der Nodes für <code>Read</code>, <code>Write</code> und <code>Validated write</code> auf das Attribut <code>servicePrincipalName</code>.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
.\security_setSqlSpn.ps1 `
    -ServiceAccount &quot;LAB\g-LAB22A-oltp&quot; `
    -InstanceName &quot;LAB22A&quot; `
    -Port 51101 `
    -Hostnames &quot;LAB-NODE01&quot;,&quot;LAB-NODE02&quot; `
    -Domain &quot;lab.local&quot; `
    -IsGMSA `
    -SetADPermissions `
    -LogPath &quot;C:\Temp\SPN_AlwaysOn_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" id="5-verwendete-microsoft-cmdlets" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Verwendete Microsoft Cmdlets</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Zum einen wird <a href="https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setspn" target="_blank" rel="noopener" title="setspn.exe"><code>setspn.exe</code></a> für Verwaltung der SPN genutzt, zum anderen wieder das <a href="https://learn.microsoft.com/en-us/powershell/module/activedirectory/?view=windowsserver2025-ps" target="_blank" rel="noopener" title=""><code>ActiveDirectory</code></a> Modul, um Accounts zu verifizieren und die SIDs zu extrahieren.</p>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Da keines der Module Active Directory Permsission manipulieren kann, wird hierfür direkt das .NET Framework <a href="https://learn.microsoft.com/en-us/dotnet/api/system.directoryservices?view=windowsdesktop-10.0" target="_blank" rel="noopener" title="System.DirectoryServices"><code>System.DirectoryServices</code></a> genutzt, welches diverse Klassen bereitstellt, um das AD komplett auf Links zu drehen. </p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" id="LSP" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Lokale Sicherheitsrichtlinien (Local Security Policies)</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-85e3fc83 wp-block-columns-is-layout-flex" style="border-width:1px;border-top-left-radius:2px;border-top-right-radius:2px;border-bottom-left-radius:2px;border-bottom-right-radius:2px;margin-top:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--20);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--80);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--80)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:100%">
<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2692.png" alt="⚒" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><code><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlLocalSec.ps1" target="_blank" rel="noopener" title="security_setSqlLocalSec.ps1">security_setSqlLocalSec.ps1</a></code></p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d3.png" alt="📓" class="wp-smiley" style="height: 1em; max-height: 1em;" /><br><a href="https://github.com/gabrielkoehl/DBAScriptBox/blob/main/windows/security/security_setSqlLocalSec.md" target="_blank" rel="noopener" title=""><code>security_setSqlLocalSec.md</code></a></p>
</div>
</div>
</div>
</div>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Wie überall in der IT sollte auch beim Sql Server nach dem <a href="https://en.wikipedia.org/wiki/Principle_of_least_privilege" target="_blank" rel="noopener" title="PoLP"><code>PoLP</code></a> gearbeitet werden, weshalb kein Service Account den lokalen Administrator bekommt.Damit SQL Server trotzdem fehlerfrei und performant läuft, benötigt der Service Account spezifische Rechte im Betriebssystem (&#8222;User Rights Assignment&#8220;). Wer dies ein paar mal manuell gemacht hat, wird sich sehr über diese Lösung freuen. Diese muss lokal auf dem jeweiligen Node ausgeführt werden.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# ===== Set Engine Permissions for gMSA =====

    .\security_setSqlLocalSec.ps1 `
        -ServiceAccount &quot;g-LAB22A-oltp$&quot; `
        -ServiceType &quot;engine&quot; `
        -IsGMSA `
        -LogPath &quot;C:\Temp\LAB22A_Engine_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;

# ===== Set Agent Permissions for gMSA =====

    .\security_setSqlLocalSec.ps1 `
        -ServiceAccount &quot;g-LAB22A-agnt$&quot; `
        -ServiceType &quot;agent&quot; `
        -IsGMSA `
        -LogPath &quot;C:\Temp\LAB22A_Agent_$(Get-Date -Format &#039;yyyyMMdd_HHmmss&#039;).log&quot;
</pre></div>


<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Verwendete Microsoft Cmdlets</h3>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Da PowerShell keine nativen Cmdlets besitzt, um lokale Sicherheitsrichtlinien (LSA) zu bearbeiten, wird das Windows-Tool <a href="https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/secedit" target="_blank" rel="noopener" title="secedit.exe"><code>secedit.exe</code></a> genutzt und der Export manipuliert.</p>



<hr class="wp-block-separator has-alpha-channel-opacity" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--70)"/>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Summary</h2>



<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Mit diesen vier Bausteinen wurde das Fundament für eine Sql Server Installation gelegt. Es wurde nicht nur eine Installation durchgeführt, sondern eine valide, dokumentierte Konfiguration geschaffen, die Identität (gMSA), Netzwerk (DNS/SPN) und OS-Performance (LSA) berücksichtigt. Im nächsten Schritt kann die eigentliche SQL Server Instanz installiert werden.</p>



<p class="wp-block-paragraph">Schaut euch auch die verlinkten MD-Files an, dort stehen Hintergrundinfos zu den Best Practices und weiterführende Artikel von Microsoft</p>



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><img loading="lazy" decoding="async" width="307" height="328" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2.png" alt="good to know emote" class="wp-image-345" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2.png 307w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2-281x300.png 281w" sizes="auto, (max-width: 307px) 100vw, 307px" /></figure><p>The post <a href="https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_de/">SQL Server HA: AD, SPN und Cluster Setup automatisieren</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/automate-sql-server-ha-ad-spn-and-cluster-setup_de/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>psTerminalPerfCounter – SpeedUp your Performance Counters in Terminal</title>
		<link>https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_en/</link>
					<comments>https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_en/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sat, 26 Jul 2025 16:07:18 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[eng]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<category><![CDATA[TERMINAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=618</guid>

					<description><![CDATA[<p>Visualize Windows Performance Counters directly in terminal with psTerminalPerfCounter. Language-independent templates, maximum customization. Perfect for quick AdHoc monitoring.</p>
<p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_en/">psTerminalPerfCounter – SpeedUp your Performance Counters in Terminal</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Current Release ( 2026-06-08 )</h2>



<div style="height:13px" aria-hidden="true" class="wp-block-spacer"></div>


https://www.powershellgallery.com/packages/psTerminalPerfCounter


<ul class="wp-block-list">
<li><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/CHANGELOG.md" target="_blank" rel="noopener" title="Changelog ">Changelog</a></li>



<li><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/tree/main?tab=readme-ov-file#documentation" target="_blank" rel="noopener" title="Documentation">Documentation</a></li>
</ul>



<div style="height:27px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p class="wp-block-paragraph">Windows Performance Counters are absolutely powerful, but when I need something quick or monitoring tailored to a specific problem, I get frustrated fast. Usually I fall back on other options &#8211; PowerShell native Get-Counter, CIM, or existing monitoring solutions at my clients. But that&#8217;s never truly ad-hoc either, and I&#8217;ve accepted it.</p>



<p class="wp-block-paragraph">Recently I had the chance to join Uwe Ricken&#8217;s Performance Tuning Workshop at DataSaturday, and he clearly named Performance Counters as a must-have in every DBA&#8217;s toolkit. What I didn&#8217;t know until then: SQL Server creates individual counters like <strong>Compile/sec</strong>, <strong>AdHoc Queries/sec</strong>, etc.</p>



<figure class="wp-block-image aligncenter size-full is-resized is-style-default" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><img loading="lazy" decoding="async" width="500" height="54" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/mindblowing.png" alt="MINDBLOWING" class="wp-image-608" style="width:500px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/mindblowing.png 500w, https://dbavonnebenan.de/wp-content/uploads/2025/07/mindblowing-300x32.png 300w" sizes="auto, (max-width: 500px) 100vw, 500px" /></figure>



<p class="wp-block-paragraph">The possibilities to visualize dependencies directly &#8211; endless. But how long should I sit there configuring that in Windows Performance Monitor, especially ad-hoc at a client site?</p>



<p class="wp-block-paragraph">Uwe showed the capabilities in Windows Admin Center, which enables templates you can use flexibly across servers. For systems or environments where Admin Center is used strategically, definitely a great choice.<br>But two problems remain: As a consultant, I can&#8217;t install software at every client, and if Admin Center happens to be running, my English templates fail on German systems.</p>



<p class="wp-block-paragraph">Still, I was so incredibly hooked by the template idea and the SQL Server possibilities that 4 weeks of after-work crunchtime were spinning in my head. So let me introduce my first module in the PowerShell Gallery:</p>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)"><strong>psTerminalPerfCounter 0.1.0-preview</strong> A PowerShell module for displaying real-time graphs of Windows Performance Counters directly in the terminal console. This module provides an easy way to visualize system performance metrics without requiring external graphing tools or GUI applications by using templates and multilanguage support.</p>


https://www.powershellgallery.com/packages/psTerminalPerfCounter/0.1.0-preview


<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">You&#8217;ll find all technical details and development status in the repository &#8211; I just want to show the different possibilities here.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Main Features</h2>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">100% PowerShell</h3>



<ul class="wp-block-list">
<li>no external dependencies</li>
</ul>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Terminal Graphics</h3>



<ul class="wp-block-list">
<li>obviously it&#8217;s not a real engine, the more counters the choppier it gets, but it&#8217;s sufficient</li>



<li>The foundation comes from <a href="https://github.com/PrateekKumarSingh/Graphical" target="_blank" rel="noopener" title="">Prateek Singh</a> solution. Without finding this, I would have had to solve this problem first, for which I probably wouldn&#8217;t have had time. THANKS!!!</li>
</ul>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="632" height="757" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_example_cpu.png" alt="" class="wp-image-609" style="width:383px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_example_cpu.png 632w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_example_cpu-250x300.png 250w" sizes="auto, (max-width: 632px) 100vw, 632px" /></figure>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Configuration Templates</h3>



<ul class="wp-block-list">
<li>every output element is controlled via configuration files</li>



<li>flexible, portable</li>
</ul>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Data Output Customization</h3>



<ul class="wp-block-list">
<li>each counter in the configuration file can use its own output
<ul class="wp-block-list">
<li>Table, Graph, or Both</li>
</ul>
</li>



<li>arbitrary axis scaling in steps and max values</li>



<li>arbitrary value coloring based on user-defined ColorMap per counter</li>



<li>value conversion via configuration file (Byte -&gt; KB -&gt; MB -&gt; GB)</li>
</ul>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Language Independent</h3>



<ul class="wp-block-list">
<li>configuration files are based on counter IDs, not paths 
<ul class="wp-block-list">
<li>portable, regardless of system language translation from ID to counter path happens at runtime </li>



<li>no external dependencies</li>
</ul>
</li>



<li>I had no idea this was possible with Windows built-in tools. Here too I stumbled across a blog at <a href="https://powershell.one/tricks/performance/performance-counters" target="_blank" rel="noopener" title="">PowerShell.ONE</a> by chance. Again, a big THANKS!!! My original solution had multiple language variants (DE, EN, FR, ES) which would be set by reading system locale.</li>
</ul>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Demo with CPU Configuration</h2>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Install module with required dependency (GripDevJsonSchemaValidator)
Install-Module -Name psTerminalPerfCounter -AllowPrerelease

# Import the module
Import-Module psTerminalPerfCounter

# Start Default Cpu Configuration
Start-tpcMonitor -ConfigName CPU
</pre></div>


<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-464c60d7 wp-block-columns-is-layout-flex" style="padding-top:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--50)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="552" height="110" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_load.png" alt="" class="wp-image-610" style="width:622px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_load.png 552w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_load-300x60.png 300w" sizes="auto, (max-width: 552px) 100vw, 552px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<p class="wp-block-paragraph">When loading the configuration, counter IDs are translated to counter paths and tested</p>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-b2e80fc7 wp-block-columns-is-layout-flex" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="613" height="155" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_sample.png" alt="" class="wp-image-611" style="width:629px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_sample.png 613w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_sample-300x76.png 300w" sizes="auto, (max-width: 613px) 100vw, 613px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<p class="wp-block-paragraph">If successful, the first samples are collected so a graph can be displayed</p>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9c5688cc wp-block-columns-is-layout-flex" style="padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="767" height="774" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run.png" alt="" class="wp-image-612" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run.png 767w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run-297x300.png 297w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run-150x150.png 150w" sizes="auto, (max-width: 767px) 100vw, 767px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<p class="wp-block-paragraph">Thats IT! </p>



<p class="wp-block-paragraph">Within 10 seconds, 2 Performance Counters running, no installation, no language issues.</p>
</div>
</div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Demo Counter Translation</h2>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Translate ID -&gt; Path
Get-tpcPerformanceCounterInfo 238-6
</pre></div>


<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="711" height="148" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_id.png" alt="" class="wp-image-613" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_id.png 711w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_id-300x62.png 300w" sizes="auto, (max-width: 711px) 100vw, 711px" /></figure>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Search Counter -&gt; Including ID
Get-tpcPerformanceCounterInfo &quot;Queue&quot;
</pre></div>


<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0"><img loading="lazy" decoding="async" width="1013" height="600" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1.png" alt="" class="wp-image-614" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1.png 1013w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1-300x178.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1-768x455.png 768w" sizes="auto, (max-width: 1013px) 100vw, 1013px" /></figure>



<p class="has-contrast-color has-text-color has-link-color wp-elements-dedb5f3a2a3a9c6525f87d44e77731d7 wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)"><em>Output is heavily truncated since the ResultSet is enormous</em></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Search Counter -&gt; Including ID
Get-tpcPerformanceCounterInfo &quot;Processor Queue&quot;
</pre></div>


<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="675" height="79" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search2.png" alt="" class="wp-image-615" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search2.png 675w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search2-300x35.png 300w" sizes="auto, (max-width: 675px) 100vw, 675px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>What&#8217;s next?</strong></h2>



<p class="wp-block-paragraph">The foundation works, the planned feature list is long, and what I really need for SQL Server is still far off. I hope I haven&#8217;t solved a problem that doesn&#8217;t exist, but this module simply addresses all the issues I&#8217;ve always had with Performance Counters, as mentioned above.</p>



<p class="wp-block-paragraph">Furthermore, this is my first larger project that I&#8217;m developing publicly, so GitHub might not always meet expected standards. I&#8217;m always happy about feedback and suggestions.</p>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="246" height="470" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png" alt="happy" class="wp-image-330" style="width:125px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png 246w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1-157x300.png 157w" sizes="auto, (max-width: 246px) 100vw, 246px" /></figure>


https://github.com/gabrielkoehl/psTerminalPerfCounter<p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_en/">psTerminalPerfCounter – SpeedUp your Performance Counters in Terminal</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_en/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>psTerminalPerfCounter &#8211; SpeedUp your Performance Counters in Terminal</title>
		<link>https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_de/</link>
					<comments>https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_de/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sat, 26 Jul 2025 15:53:33 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[CONSOLE]]></category>
		<category><![CDATA[counter]]></category>
		<category><![CDATA[DE]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<category><![CDATA[TERMINAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=605</guid>

					<description><![CDATA[<p>Visualisiere Windows Performance Counter direkt im Terminal mit psTerminalPerfCounter. Sprachunabhängige Templates, maximale Anpassbarkeit. Perfekt für schnelles AdHoc-Monitoring.</p>
<p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_de/">psTerminalPerfCounter – SpeedUp your Performance Counters in Terminal</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">Current Release ( 2026-06-08 )</h2>



<div style="height:13px" aria-hidden="true" class="wp-block-spacer"></div>


https://www.powershellgallery.com/packages/psTerminalPerfCounter


<ul class="wp-block-list">
<li><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/CHANGELOG.md" target="_blank" rel="noopener" title="Changelog ">Changelog</a></li>



<li><a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/tree/main?tab=readme-ov-file#documentation" target="_blank" rel="noopener" title="Documentation">Documentation</a></li>
</ul>



<div style="height:13px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p class="wp-block-paragraph">Die Windows Performance Counter sind absolut mächtig, aber wenn es mal schnell gehen muss oder ich genau passend zu einem Problem ein Monitoring benötige, bin ich schnell genervt. Meistens nutze ich dann doch andere Möglichkeiten, PowerShell Native Get-Counter, CIM oder greife auf vorhandene Monitoring-Lösungen bei meinen Kunden zurück. Aber auch das geht nie AdHoc aber ich habe es akzeptiert.</p>



<p class="wp-block-paragraph">Nun habe ich beim letzten DataSaturday Uwe Ricken beim Performance Tuning Workshop begleiten dürfen und auch er hat die Performance Counter noch mal klar als Musthave im Werkzeugkoffer eines jeden DBA benannt. Was mir bis dahin nicht bewusst war: SQL Server legt individuelle Counter wie <strong>Compile/sec</strong>, <strong>AdHoc Queries/sec</strong> usw. an.</p>



<figure class="wp-block-image aligncenter size-full is-resized is-style-default" style="margin-top:var(--wp--preset--spacing--60);margin-bottom:var(--wp--preset--spacing--60)"><img loading="lazy" decoding="async" width="500" height="54" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/mindblowing.png" alt="MINDBLOWING" class="wp-image-608" style="width:500px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/mindblowing.png 500w, https://dbavonnebenan.de/wp-content/uploads/2025/07/mindblowing-300x32.png 300w" sizes="auto, (max-width: 500px) 100vw, 500px" /></figure>



<p class="wp-block-paragraph">Die Möglichkeiten, Abhängigkeiten direkt zu visualisieren &#8211; endlos. Aber wie lange soll ich da sitzen, bis ich das im Windows Performance Monitor abgebildet habe, am besten Adhoc bei einem Kunden? </p>



<p class="wp-block-paragraph">Uwe zeigte die Möglichkeiten im <strong>Windows Admin Center</strong> auf, welches Templates ermöglicht, die man flexibel auf Servern nutzen kann. Für System oder Umgebungen, in denen das Admin Center strategisch genutzt wird, definitiv eine sehr gut Wahl.</p>



<p class="wp-block-paragraph">Aber zwei Probleme bleiben: Als Berater kann ich nicht bei jedem Kunden erst Software installieren und wenn das Admin Center doch läuft, scheitern meine englischen Templates an deutschen Systemen.</p>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)">Nun war ich trotzdem so unglaublich angefixt von der Template-Idee und den Sql Server Möglichkeiten, dass nach Feierabend 4 Wochen Crunchtime im Kopf waren. Somit möchte ich euch an dieser Stelle mein erstes Modul in der PowerShell Gallery vorstellen</p>


https://www.powershellgallery.com/packages/psTerminalPerfCounter/0.1.0-preview


<p class="wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Die technischen Details, Entwicklungsstand findet ihr alle im Repository, ich möchte hier einfach die verschiedenen Möglichkeiten zeigen.</p>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Main Features</h2>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">100% PowerShell</h3>



<ul class="wp-block-list">
<li>keine externen Abhängigkeiten</li>
</ul>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Terminal-Grafiken</h3>



<ul class="wp-block-list">
<li>natürlich ist es keine richtige Engine, je mehr Counter desto Hakeliger wird es, aber es reicht</li>



<li>Als Basis dient die Lösung von <a href="https://github.com/PrateekKumarSingh/Graphical" target="_blank" rel="noopener" title="">Prateek Singh</a>. Ohne diesen Fund hätte ich wohl dieses Problem erst lösen müssen, wofür ich vermutlich keine Zeit gehabt hätte. DANKE!!!</li>
</ul>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--40);margin-bottom:var(--wp--preset--spacing--40)"><img loading="lazy" decoding="async" width="632" height="757" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_example_cpu.png" alt="" class="wp-image-609" style="width:383px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_example_cpu.png 632w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_example_cpu-250x300.png 250w" sizes="auto, (max-width: 632px) 100vw, 632px" /></figure>



<p class="wp-block-paragraph"></p>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Configuration Templates</h3>



<ul class="wp-block-list">
<li>jedes Element der Ausgabe wird über Configuration Files gesteuert</li>



<li>flexibel, transportabel</li>
</ul>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Individualisierung der Datenausgaben </h3>



<ul class="wp-block-list">
<li>für jeden Counter im Configuration-File kann eine eigene Ausgabe genutzt werden
<ul class="wp-block-list">
<li>Table, Graph oder Beide</li>
</ul>
</li>



<li>beliebige Skalierungen der Achsen in Steps und Max</li>



<li>beliebige Einfärbung der Values auf Basis einer benutzerdefinierten ColorMap per Counter</li>



<li>Konvertierung der Values per Configuration-File ( Byte -&gt; KB -&gt; MB -&gt; GB )</li>
</ul>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Sprachunabhängig</h3>



<ul class="wp-block-list">
<li>Configuration Files basieren nicht auf den Counter-Pfaden sondern IDs</li>



<li>immer noch transportabel, egal welche Systemsprache</li>



<li>Translation von ID zu Counterpfad erfolgt erst zur Laufzeit</li>
</ul>



<ul class="wp-block-list">
<li>keine externen Abhängigkeiten</li>



<li>Ich wusste gar nicht, dass dies möglich ist mit Windows Bordmitteln. Auch hier bin ich durch Zufall über einen Blog gestolpert bei <a href="https://powershell.one/tricks/performance/performance-counters" target="_blank" rel="noopener" title="">PowerShell.ONE</a>. Auch hier ein dickes DANKE!!! Meine eigentliche Lösung sah mehrere Sprachvarianten ( DE, EN, FR, ES) vor, welche dann per auslesen der Systemlokalen gesetzt wurden.</li>
</ul>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Demo mit CPU Configuration</h2>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Install module with required dependency (GripDevJsonSchemaValidator)
Install-Module -Name psTerminalPerfCounter -AllowPrerelease

# Import the module
Import-Module psTerminalPerfCounter

# Start Default Cpu Configuration
Start-tpcMonitor -ConfigName CPU
</pre></div>


<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-464c60d7 wp-block-columns-is-layout-flex" style="padding-top:var(--wp--preset--spacing--50);padding-bottom:var(--wp--preset--spacing--50)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="552" height="110" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_load.png" alt="" class="wp-image-610" style="width:622px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_load.png 552w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_load-300x60.png 300w" sizes="auto, (max-width: 552px) 100vw, 552px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<p class="wp-block-paragraph">Beim Laden der Konfiguration werden die Counter IDs zu Counterpfaden übersetzt und getestet</p>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-b2e80fc7 wp-block-columns-is-layout-flex" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="613" height="155" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_sample.png" alt="" class="wp-image-611" style="width:629px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_sample.png 613w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_sample-300x76.png 300w" sizes="auto, (max-width: 613px) 100vw, 613px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<p class="wp-block-paragraph">Wenn das erfolgreich war, werden die ersten Samples gesammelt, damit ein Graph angezeigt werden kann</p>
</div>
</div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9c5688cc wp-block-columns-is-layout-flex" style="padding-top:var(--wp--preset--spacing--50);padding-right:0;padding-bottom:var(--wp--preset--spacing--50);padding-left:0">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="767" height="774" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run.png" alt="" class="wp-image-612" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run.png 767w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run-297x300.png 297w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfcounter_run-150x150.png 150w" sizes="auto, (max-width: 767px) 100vw, 767px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<p class="wp-block-paragraph">Thats IT! </p>



<p class="wp-block-paragraph">Innerhalb von 10 Sekunden 2 Performance Counter am Laufen, ohne Installation, ohne Sprachprobleme.</p>
</div>
</div>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Demo Counter Translation</h2>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Translate ID -&gt; Path
Get-tpcPerformanceCounterInfo 238-6
</pre></div>


<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="711" height="148" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_id.png" alt="" class="wp-image-613" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_id.png 711w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_id-300x62.png 300w" sizes="auto, (max-width: 711px) 100vw, 711px" /></figure>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Search Counter -&gt; Including ID
Get-tpcPerformanceCounterInfo &quot;Queue&quot;
</pre></div>


<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0"><img loading="lazy" decoding="async" width="1013" height="600" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1.png" alt="" class="wp-image-614" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1.png 1013w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1-300x178.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search1-768x455.png 768w" sizes="auto, (max-width: 1013px) 100vw, 1013px" /></figure>



<p class="has-contrast-color has-text-color has-link-color wp-elements-a85209788f442c1a4bfcffc9ae003cc8 wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)"><em>Die Ausgabe ist stark beschnitten, da das ResultSet enorm ist</em></p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Search Counter -&gt; Including ID
Get-tpcPerformanceCounterInfo &quot;Processor Queue&quot;
</pre></div>


<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="675" height="79" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search2.png" alt="" class="wp-image-615" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search2.png 675w, https://dbavonnebenan.de/wp-content/uploads/2025/07/perfmon_translate_search2-300x35.png 300w" sizes="auto, (max-width: 675px) 100vw, 675px" /></figure>



<div style="height:30px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Wie geht&#8217;s weiter?</h2>



<p class="wp-block-paragraph">Die Basis läuft, die planned Feature <a href="https://github.com/gabrielkoehl/psTerminalPerfCounter/blob/main/docs/en-US/DevelopmentStatus.MD" target="_blank" rel="noopener" title="">Liste</a> ist lang und das, was ich wirklich brauche bezüglich Sql Server ist noch in weiter Ferne. Ich hoffe ich habe nicht ein Problem bedient, was es gar nicht gibt, aber dieses Modul adressiert einfach alle Probleme, die ich schon immer mit den Performance Countern hatte, siehe oben.</p>



<p class="wp-block-paragraph">Weiterhin ist das mein erstes größeres Projekt, was ich Public entwickle, somit könnte Github nicht immer den erwarteten Standards entsprechen. Über Feedback und Hinweise freue ich mich immer.</p>



<figure class="wp-block-image aligncenter size-full is-resized" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="246" height="470" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png" alt="happy" class="wp-image-330" style="width:125px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png 246w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1-157x300.png 157w" sizes="auto, (max-width: 246px) 100vw, 246px" /></figure>


https://github.com/gabrielkoehl/psTerminalPerfCounter<p>The post <a href="https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_de/">psTerminalPerfCounter – SpeedUp your Performance Counters in Terminal</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/psterminalperfcounter-speedup-your-performance-counters_de/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Measuring SQL Server Disk Latency Correctly – snapDiskLatency</title>
		<link>https://dbavonnebenan.de/sql-server-disk-latency-en/</link>
					<comments>https://dbavonnebenan.de/sql-server-disk-latency-en/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Thu, 17 Jul 2025 14:21:36 +0000</pubDate>
				<category><![CDATA[Sql Server]]></category>
		<category><![CDATA[TSql]]></category>
		<category><![CDATA[diskio]]></category>
		<category><![CDATA[DISKSPD]]></category>
		<category><![CDATA[eng]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=579</guid>

					<description><![CDATA[<p>How to get correct SQL Server Disk Latency values instead of falsified DMV data. Open Source snapDiskLatency solution for long-term analysis.</p>
<p>The post <a href="https://dbavonnebenan.de/sql-server-disk-latency-en/">Measuring SQL Server Disk Latency Correctly – snapDiskLatency</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="border: 1px dotted #eb2b14;border-radius: 0%;background-color: #eeeeee;padding-top: var(--wp--preset--spacing--30);padding-left: var(--wp--preset--spacing--30);padding-right: var(--wp--preset--spacing--30);padding-bottom: var(--wp--preset--spacing--30)" class="ub-styled-box ub-bordered-box wp-block-ub-styled-box" id="ub-styled-box-ed9a98aa-0cd4-41e3-8f7e-56d29b672df9">
<p class="has-open-sauce-sans-font-family wp-block-paragraph" style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" id="ub-styled-box-bordered-content-">What&#8217;s available here?</p>



<ul style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" class="wp-block-list has-open-sauce-sans-font-family">
<li><a href="#DISKSPD" title="">DISKSPD Templates and Wrapper</a></li>



<li><a href="#sqlfilestats" title="">How can I display the latencies of individual database files?</a></li>



<li><a href="#snapdisk" title="">Long-term analysis of latencies with snapDiskLatency</a></li>
</ul>


</div>


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>


https://github.com/gabrielkoehl/DBAScriptBox


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p class="wp-block-paragraph">Currently, I&#8217;m involved in a code review at a client. We&#8217;re examining not only the application but also all interfaces. This naturally includes the SQL Server landscape, which I set up at the beginning of the year.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<p class="has-open-sauce-sans-font-family wp-block-paragraph">The result was more findings in my direction than expected, and I immediately felt challenged. I was able to refute most of it, some topics were the client&#8217;s responsibility, and one topic caught my interest purely out of curiosity.</p>



<p class="has-text-align-center wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Read- and Write Latencies of TempDB</strong> ( and every other DB )</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="264" height="329" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png" alt="" class="wp-image-516" style="width:131px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png 264w, https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4-241x300.png 241w" sizes="auto, (max-width: 264px) 100vw, 264px" /></figure>
</div>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Background</h2>



<p class="wp-block-paragraph">The client doesn&#8217;t operate their own data center, so they&#8217;re dependent on the hoster, who unfortunately isn&#8217;t very communicative. Therefore, I had to get a picture of the totally overcommitted hardware through various other means and challenge the hoster. This was also the reason why I was quite precisely informed about what the hoster&#8217;s hosts and storage systems were capable of delivering.</p>



<p class="wp-block-paragraph">That&#8217;s why I was very surprised that 32ms Write Latency was listed as a finding. No question, that&#8217;s a bad value for AllFlash NVMe, but it just stood there in the report without differentiation or deeper analysis. Just the statement &#8222;bad storage.&#8220; So I unpacked my tools, took another look at it, and also developed a new solution that I want to share with you.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="DISKSPD" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">DISKSPD</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)"><em><strong>Repo</strong>: perf_diskspeed/DISKSPD</em><br><strong><em>Microsoft</em>:</strong> <a href="https://github.com/microsoft/diskspd" target="_blank" rel="noopener" title="">https://github.com/microsoft/diskspd</a></p>



<p class="wp-block-paragraph">With DISKSPD, you should always start on unknown systems; often a large portion of problems is hidden here. At this client, for example, a DB with high workload was running on spindles, with latencies in the .2 percentile of 15 seconds latency, plus 14MB throughput. I don&#8217;t need to worry about indexes etc. anymore.</p>



<p class="wp-block-paragraph">To quickly get results, I built a wrapper for DISKSPD that always executes 3 standard tests:</p>



<ul class="wp-block-list">
<li>SQL Server Workload</li>



<li>Random 64KB Workload</li>



<li>Sequential 64KB Workload</li>
</ul>



<p class="wp-block-paragraph">The files are stored separately in the _Output subfolder and thus provide quite good hints about storage problems. Now these were, as expected, great values that correspond to NVMe storage. So let&#8217;s continue to SQL Server and see what it tells us. welche NVMe Storage entsprechen. Also weiter zu Sql Server und wir schauen mal was uns dieser so sagt.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="sqlfilestats" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">sys.dm_io_virtual_file_stats</h2>



<p class="wp-block-paragraph">SQL Server provides a view where all file metrics are cleanly listed.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
select * from sys.dm_io_virtual_file_stats(null,null)
</pre></div>


<ul class="wp-block-list">
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-io-virtual-file-stats-transact-sql?view=sql-server-ver17">Microsoft Learn</a></li>
</ul>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1117" height="458" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv.png" alt="sys.dm_io_virtual_file_stats" class="wp-image-569" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv.png 1117w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv-300x123.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv-1024x420.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv-768x315.png 768w" sizes="auto, (max-width: 1117px) 100vw, 1117px" /></figure>



<p class="wp-block-paragraph">Based on this, I built an analysis script that gives me more info and I can also draw further conclusions like ReadWrite Ratio, probable IOPS based on the number of operations, and also quantities. This allows you to build storage systems quite well for specific workloads.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:80%">
<p class="wp-block-paragraph">And this value also showed me 32ms Write Latency of the TempDB. Then I started wondering, how does this value even arise?</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="261" height="323" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/emotes_question.png" alt="Question" class="wp-image-575" style="width:125px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/emotes_question.png 261w, https://dbavonnebenan.de/wp-content/uploads/2025/07/emotes_question-242x300.png 242w" sizes="auto, (max-width: 261px) 100vw, 261px" /></figure>
</div>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Basic Calculation</h3>



<p class="wp-block-paragraph">SQL Server measures I/O latency through simple division of cumulative wait times by the number of operations:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
-- Read Latency in ms
io_stall_read_ms / num_of_reads = durchschnittliche Read-Latenz

-- Write Latency in ms  
io_stall_write_ms / num_of_writes = durchschnittliche Write-Latenz
</pre></div>


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">That&#8217;s it!!! And now it should be clear that the point-in-time use of this DMV is not really meaningful, on the contrary. The values can, as with the review company that specializes in such processes, lead to false conclusions and action recommendations. Scary.</p>



<p class="wp-block-paragraph">If the storage system had a hard hiccup since the start of SQL Server, the metrics are contaminated. According to my research, you can&#8217;t flush these, only by taking the DB offline, which I usually avoid in productive environments.</p>



<p class="wp-block-paragraph">After a few more rounds in my head, the solution came quite quickly. These are all snapshot values, I just need the delta between two values and I have real values. And I can also put the whole thing in a time series and have a long-term analysis. Mindblowing <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f61d.png" alt="😝" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p class="wp-block-paragraph">Google also quickly showed corresponding solutions that I used as a base idea. Thanks to Paul Randal ( <a href="https://www.sqlskills.com/blogs/paul/capturing-io-latencies-period-time/" target="_blank" rel="noopener" title="">sqlskills.com</a> )</p>



<p class="wp-block-paragraph">For analyzing a complete week, this is also not suitable. So I extended the whole thing to a long-term analysis with persistent table.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="snapdisk" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">The Solution &#8211;&gt; snapDiskLatency</h2>



<p class="wp-block-paragraph"><em><strong>Repo</strong>: </em>perf_diskspeed/snapDiskLatency</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">What does snapDiskLatency do?</h3>



<p class="wp-block-paragraph">The problem is well-known &#8211; the standard DMV <code>sys.dm_io_virtual_file_stats</code> shows cumulative values since SQL Server startup. One single storage hiccup weeks ago and the latency values are no longer representative.</p>



<p class="wp-block-paragraph">This solves the problem with two simple stored procedures:</p>



<p class="wp-block-paragraph">The first collects the raw data from the DMV hourly and writes it to a permanent table. Why hourly? Shorter intervals lead to unreliable delta calculations &#8211; too little I/O between snapshots makes the values inaccurate. However, this can be individually adjusted since the agent triggers the procedure.</p>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1360" height="382" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw.png" alt="snapDiskLatency collect" class="wp-image-567" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw.png 1360w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw-300x84.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw-1024x288.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw-768x216.png 768w" sizes="auto, (max-width: 1360px) 100vw, 1360px" /></figure>



<p class="wp-block-paragraph">The second does the delta calculations between snapshots and creates the result. Thus, real latency values are generated for defined time periods, without historical hiccups, which can then be compared with other metrics.</p>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1298" height="326" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2.png" alt="snapDiskLatency report" class="wp-image-571" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2.png 1298w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2-300x75.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2-1024x257.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2-768x193.png 768w" sizes="auto, (max-width: 1298px) 100vw, 1298px" /></figure>



<p class="wp-block-paragraph">Here we see, for example, in the <a href="https://dbavonnebenan.de/sql-server-truncate-vs-delete-dml-or-ddl-en/" title="TRUNCATE TABLE – DDL vs DML – deep dive in operations and practical tips">TRUNCATE TABLE</a> an outlier (NVMe is also underlying here). On the LAB system there&#8217;s no load, DOXIS is just a table with 2 columns and was artificially worked with workload.<br></p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>The Result</strong></h3>



<p class="wp-block-paragraph">Instead of possibly contaminated values:</p>



<ul class="wp-block-list">
<li>Average latencies per interval</li>



<li>Read/Write ratios</li>



<li>Breakdown by database and file type</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Setup</strong></h3>



<p class="wp-block-paragraph">Create Agent Job, run hourly, done. The complete instructions are in the README, copy &amp; paste &amp; enjoy</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="246" height="470" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png" alt="happy" class="wp-image-330" style="width:125px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png 246w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1-157x300.png 157w" sizes="auto, (max-width: 246px) 100vw, 246px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Diagrams</h2>



<p class="wp-block-paragraph">Since every good proprietary database monitoring tool does this and presents it graphically, I want to at least show one possibility in Excel in the result. For this, the result of the DataSource or Copy must be pivoted and you can easily recognize your daily peaks.</p>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1617" height="604" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph.png" alt="" class="wp-image-572" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph.png 1617w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-300x112.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-1024x382.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-768x287.png 768w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-1536x574.png 1536w" sizes="auto, (max-width: 1617px) 100vw, 1617px" /></figure><p>The post <a href="https://dbavonnebenan.de/sql-server-disk-latency-en/">Measuring SQL Server Disk Latency Correctly – snapDiskLatency</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/sql-server-disk-latency-en/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SQL Server Disk Latency richtig messen &#8211; snapDiskLatency</title>
		<link>https://dbavonnebenan.de/sql-server-disk-latency-de/</link>
					<comments>https://dbavonnebenan.de/sql-server-disk-latency-de/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Thu, 17 Jul 2025 14:06:35 +0000</pubDate>
				<category><![CDATA[Sql Server]]></category>
		<category><![CDATA[TSql]]></category>
		<category><![CDATA[DE]]></category>
		<category><![CDATA[diskio]]></category>
		<category><![CDATA[DISKSPD]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[PERFORMANCE]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=563</guid>

					<description><![CDATA[<p>Wie du richtige SQL Server Disk Latency Werte erhältst statt verfälschter DMV-Daten. Open Source snapDiskLatency Lösung für Langzeitanalyse.</p>
<p>The post <a href="https://dbavonnebenan.de/sql-server-disk-latency-de/">SQL Server Disk Latency richtig messen – snapDiskLatency</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<div style="border: 1px dotted #eb2b14;border-radius: 0%;background-color: #eeeeee;padding-top: var(--wp--preset--spacing--30);padding-left: var(--wp--preset--spacing--30);padding-right: var(--wp--preset--spacing--30);padding-bottom: var(--wp--preset--spacing--30)" class="ub-styled-box ub-bordered-box wp-block-ub-styled-box" id="ub-styled-box-ba0a6049-a2c1-44fc-b531-47f63f78c8b4">
<p class="wp-block-paragraph" style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" id="ub-styled-box-bordered-content-">Was erwartet dich hier?</p>



<ul style="margin-top:0;margin-right:0;margin-bottom:0;margin-left:0" class="wp-block-list">
<li><a href="#DISKSPD" title="DISKSPD Templates und Wrapper">DISKSPD Templates und Wrapper</a></li>



<li><a href="#sqlfilestats" title="">Wie kann ich die Latenzen der einzelnen Datenbank Files anzeigen lassen?</a></li>



<li><a href="#snapdisk" title="Langzeit Analyse der Latenzen!!!">Langzeit Analyse der Latenzen!!!</a></li>
</ul>


</div>


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>


https://github.com/gabrielkoehl/DBAScriptBox


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p class="wp-block-paragraph">Aktuell bin ich bei einem Kunden an einem Code Review beteiligt. Dabei beleuchten wir neben der Applikation auch alle Schnittstellen.. Dazu gehört natürlich auch die Sql Server Landschaft, welche ich Anfang des Jahres aufgesetzt habe.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:85%">
<p class="wp-block-paragraph">Das Ergebnis waren doch mehr Findings in meine Richtung als erwartet und ich fühlte mich sofort gechallenged. Das Meiste konnte ich widerlegen, bei einigen Themen war der Kunde in der Pflicht und ein Thema hat mich rein interessenhalber gepackt.</p>



<p class="has-text-align-center wp-block-paragraph" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Read- und Write Latenzen der TempDB</strong> ( und jeder anderen DB )</p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:15%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="264" height="329" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png" alt="" class="wp-image-516" style="width:131px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4.png 264w, https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-4-241x300.png 241w" sizes="auto, (max-width: 264px) 100vw, 264px" /></figure>
</div>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Vorgeschichte</h2>



<p class="wp-block-paragraph">Der Kunde betreibt kein eigenes Rechenzentrum, ist somit vom Hoster abhängig, welcher leider nicht sehr kommunikativ ist. Somit musste ich mir auf diverse andere Wege ein Bild von der total overcommitteten Hardware machen und den Hoster Challengen. Dies war auch der Grund, warum ich ziemlich genau im Bilde war, was die Hosts und Storage Systeme des Hosters im Stande waren zu leisten.</p>



<p class="wp-block-paragraph">Deshalb hat es mich doch sehr gewundert, dass als Finding 32ms Write Latency aufgeführt waren. Keine Frage, das ist ein schlechter Wert für AllFlash NVMe aber der stand da einfach so im Report, ohne Differenzierung oder tiefere Analysen. Nur die Aussage schlechter Storage. Also habe ich meine Werkzeuge ausgepackt, mir das noch mal angeschaut und auch eine neue Lösung entwickelt, die ich mit euch teilen möchte.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="DISKSPD" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">DISKSPD</h2>



<p class="wp-block-paragraph" style="margin-bottom:var(--wp--preset--spacing--50)"><em><strong>Repo</strong>: perf_diskspeed/DISKSPD</em><br><strong><em>Microsoft</em>:</strong> <a href="https://github.com/microsoft/diskspd">https://github.com/microsoft/diskspd</a></p>



<p class="wp-block-paragraph">Mit DISKSPD sollte man auf unbekannten Systemen immer anfangen, oft liegt hier schon ein großer Anteil an Problemen versteckt. Bei diesem Kudnen lief zum Beispiel eine DB mit hohem Workload auf Spindeln, mit Latenzen in der .2 Perzentile mit 15 Sekunden Latenz, dazu 14MB Durchsatz. Da brauche ich mir um Indexe usw. keine Gedanken mehr machen.</p>



<p class="wp-block-paragraph">Um schnell an Ergebnisse zu kommen, habe ich mir einen Wrapper für DISKSP gebaut, welcher immer 3 Standardtests ausführt</p>



<ul class="wp-block-list">
<li>Sql Server Workload</li>



<li>Random 64KB Workload</li>



<li>Sequenziell 64KB Workload</li>
</ul>



<p class="wp-block-paragraph">Die Dateien werden separat im Unterordner _Output gespeichert und ermöglichen somit recht gute Hinweise auf Storage-Probleme. Nun waren das wie erwartet super Werte, welche NVMe Storage entsprechen. Also weiter zu Sql Server und wir schauen mal was uns dieser so sagt.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="sqlfilestats" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">sys.dm_io_virtual_file_stats</h2>



<p class="wp-block-paragraph">Sql Server bietet eine View, in der alle Metriken der Files sauber aufgelistet werden.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
select * from sys.dm_io_virtual_file_stats(null,null)
</pre></div>


<ul class="wp-block-list">
<li><a href="https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-io-virtual-file-stats-transact-sql?view=sql-server-ver17" target="_blank" rel="noopener" title="">microsoft.com</a></li>
</ul>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1117" height="458" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv.png" alt="sys.dm_io_virtual_file_stats" class="wp-image-569" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv.png 1117w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv-300x123.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv-1024x420.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_dmv-768x315.png 768w" sizes="auto, (max-width: 1117px) 100vw, 1117px" /></figure>



<p class="wp-block-paragraph">Darauf basierend habe ich ein Analyse Script gebaut, welches mir mehr Infos gibt und ich auch weitere Rückschlüsse wie ReadWrite Ratio, wahrscheinliche IOPS auf Basis der Anzahl der Vorgänge und auch Mengen. Damit kann man schon ganz gut Storage Systeme zu speziellen Workloads aufbauen.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-461897f4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:80%">
<p class="wp-block-paragraph">Und auch dieser Wert hat mir 32ms Write Latency der TempDB angezeigt. Dann habe ich angefangen mich zu fragen, wie entstehet dieser Wert überhaupt? </p>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:20%">
<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="261" height="323" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/emotes_question.png" alt="Question" class="wp-image-575" style="width:125px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/emotes_question.png 261w, https://dbavonnebenan.de/wp-content/uploads/2025/07/emotes_question-242x300.png 242w" sizes="auto, (max-width: 261px) 100vw, 261px" /></figure>
</div>
</div>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Grundlegende Berechnung der Werte</h3>



<p class="wp-block-paragraph">SQL Server misst I/O-Latenz durch einfache Division der kumulativen Wartezeiten durch die Anzahl der Operationen:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: sql; title: ; notranslate">
-- Read Latency in ms
io_stall_read_ms / num_of_reads = durchschnittliche Read-Latenz

-- Write Latency in ms  
io_stall_write_ms / num_of_writes = durchschnittliche Write-Latenz
</pre></div>


<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<p class="wp-block-paragraph">Thats it!!! Und nun sollte klar sein, dass die punktuelle Nutzung dieser DMV nicht wirklich aussagekräftig ist, im Gegenteil. Die Werte können wie bei dem Review Unternehmen, was sich auf solche Prozesse spezialisiert hat, zu falschen Rückschlüssen und Handlungsempfehlungen führen. Gruselig.</p>



<p class="wp-block-paragraph">Wenn das Storagesystem seit dem Start von Sql Server mal hart Schluckauf hatte, sind die Metriken verunreiningt. Laut meinen Recherchen kann man diese nicht flushen, nur durch das Offline nehmen der DB, was ich üblicherweise in produktiven Umgebungen vermeide.</p>



<p class="wp-block-paragraph">Nach ein paar weiteren Runden in meinem Kopf kam recht schnell die Lösung. Das sind alles SnapShot Values, ich brauche ja nur das Delta zwischen zwei Werten und schon habe ich reale Werte. Und das Ganze kann ich auch noch in eine Zeitreihe packen und habe eine Langzeitanalyse.  Mindblowing <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f61d.png" alt="😝" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p class="wp-block-paragraph">Google hat auch schnell entsprechende Lösungen aufgezeigt, die ich als Basis Idee genutzt habe. Danke an Paul Randal ( <a href="https://www.sqlskills.com/blogs/paul/capturing-io-latencies-period-time/">sqlskills.com</a> )</p>



<p class="wp-block-paragraph">Für die Analyse einer kompletten Woche ist dies aber auch nicht geeignet. Somit habe ich das Ganze auf eine Langzeitanalyse mit persistenten Table erweitert.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" id="snapdisk" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">Die Lösung &#8211;&gt; snapDiskLatency</h2>



<p class="wp-block-paragraph"><em><strong>Repo</strong>: </em>perf_diskspeed/snapDiskLatency</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Was macht snapDiskLatency?</h3>



<p class="wp-block-paragraph">Das Problem ist bekannt &#8211; die Standard-DMV <code>sys.dm_io_virtual_file_stats</code> zeigt kumulative Werte seit dem SQL Server Start. Ein einziger Storage-Schluckauf vor Wochen und die Latenzwerte sind nicht mehr repräsentativ. </p>



<p class="wp-block-paragraph"><strong>snapDiskLatency</strong> löst das Problem mit zwei simplen Stored Procedures:</p>



<p class="wp-block-paragraph">Die Erste sammelt stündlich die Rohdaten aus der DMV und schreibt sie in einen permanenten Table. Warum stündlich? Kürzere Intervalle führen zu unzuverlässigen Delta-Berechnungen &#8211; zu wenig I/O zwischen den Snapshots macht die Werte ungenau. Dies kann aber individuell angepasst werden, da der Agent die Prozedur triggert.</p>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1360" height="382" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw.png" alt="snapDiskLatency collect" class="wp-image-567" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw.png 1360w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw-300x84.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw-1024x288.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_raw-768x216.png 768w" sizes="auto, (max-width: 1360px) 100vw, 1360px" /></figure>



<p class="wp-block-paragraph">Die Zweite macht die Delta-Berechnungen zwischen den Snapshots und erstellt das Resultset. Somit werden reale Latenzwerte für definierte Zeiträume erzeugt, ohne historischen Schluckauf, welche dann mit anderen Metriken abgeglichen werden können.</p>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1298" height="326" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2.png" alt="snapDiskLatency report" class="wp-image-571" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2.png 1298w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2-300x75.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2-1024x257.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_report-2-768x193.png 768w" sizes="auto, (max-width: 1298px) 100vw, 1298px" /></figure>



<p class="wp-block-paragraph">Hier sehen wir zum Beispiel im <a href="https://dbavonnebenan.de/sql-server-truncate-vs-delete-dml-or-ddl-de/" title="TRUNCATE TABLE Operationen im Detail – ROLLBACK ist doch möglich">TRUNCATE Table</a> einen Aureißer ( hier liegt auch NVMe drunter ). Auf dem LAB System ist keine Last, DOXIS ist nur ein Table mit 2 Spalten und wurde künstlich mit Workload bearbeitet.</p>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Das Ergebnis</strong></h3>



<p class="wp-block-paragraph">Statt möglicherweise verunreinigten Werten</p>



<ul class="wp-block-list">
<li>Durchschnittliche Latenzen pro Intervall</li>



<li>Read/Write-Verhältnisse</li>



<li>Aufschlüsselung nach Datenbank und File-Type</li>
</ul>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>Setup</strong></h3>



<p class="wp-block-paragraph">Agent Job erstellen, stündlich laufen lassen, fertig. Die komplette Anleitung steht in der README, copy &amp; paste &amp; freuen</p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="246" height="470" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png" alt="happy" class="wp-image-330" style="width:125px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1.png 246w, https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_standing_1-157x300.png 157w" sizes="auto, (max-width: 246px) 100vw, 246px" /></figure>



<div style="height:20px" aria-hidden="true" class="wp-block-spacer"></div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">Diagramme</h2>



<p class="wp-block-paragraph">Da dies auch jedes gute propritäre DatabaseMonitoringTool macht und hübsch grafisch darstellt, will ich zumindest eine Möglichkeit in Excel im Ergebnis zeigen. Dazu muss das Ergebnis der DataSource oder Copy pivotiert werden und schon kann man gut seine Daily Peaks erkennen.</p>



<figure class="wp-block-image size-full" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><img loading="lazy" decoding="async" width="1617" height="604" src="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph.png" alt="" class="wp-image-572" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph.png 1617w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-300x112.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-1024x382.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-768x287.png 768w, https://dbavonnebenan.de/wp-content/uploads/2025/07/disklat_graph-1536x574.png 1536w" sizes="auto, (max-width: 1617px) 100vw, 1617px" /></figure><p>The post <a href="https://dbavonnebenan.de/sql-server-disk-latency-de/">SQL Server Disk Latency richtig messen – snapDiskLatency</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/sql-server-disk-latency-de/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
