<?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>PowerShell | DBA von Nebenan</title>
	<atom:link href="https://dbavonnebenan.de/tag/powershell/feed/" rel="self" type="application/rss+xml" />
	<link>https://dbavonnebenan.de</link>
	<description>Sql Server, Performance &#38; PowerShell Automation</description>
	<lastBuildDate>Sat, 11 Oct 2025 18:28:31 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://dbavonnebenan.de/wp-content/uploads/2025/04/cropped-www_logo-32x32.png</url>
	<title>PowerShell | DBA von Nebenan</title>
	<link>https://dbavonnebenan.de</link>
	<width>32</width>
	<height>32</height>
</image> 
	<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 ( 2025-10-11 )</h2>



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


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


<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>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>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 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="(max-width: 500px) 100vw, 500px" /></figure>



<p>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>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>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 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 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 fetchpriority="high" 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="(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-51c0b34d 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 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="(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>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-0884d4d2 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>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-e242d015 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>Thats IT! </p>



<p>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" 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>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>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 ( 2025-10-11 )</h2>



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


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


<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>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>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>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>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>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 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 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></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-51c0b34d 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>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-0884d4d2 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>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-e242d015 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>Thats IT! </p>



<p>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" 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>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>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>PowerShell Classes for Beginners &#8211; Structured Code Instead of Function Chaos</title>
		<link>https://dbavonnebenan.de/powershell-classes-for-beginner-en/</link>
					<comments>https://dbavonnebenan.de/powershell-classes-for-beginner-en/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sat, 14 Jun 2025 18:36:58 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Classes]]></category>
		<category><![CDATA[eng]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[TUTORIAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=528</guid>

					<description><![CDATA[<p>Intro I&#8217;ve always used PowerShell following the same pattern, that&#8217;s roughly how my learning path followed the PowerShell Best Practices. I&#8217;ve been operating on these last two levels for quite a long time now, of course getting more efficient and generally my PowerShell knowledge became broader. During this development, however, I noticed a problem: I&#8217;m [&#8230;]</p>
<p>The post <a href="https://dbavonnebenan.de/powershell-classes-for-beginner-en/">PowerShell Classes for Beginners – Structured Code Instead of Function Chaos</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading" style="margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p>I&#8217;ve always used PowerShell following the same pattern, that&#8217;s roughly how my learning path followed the PowerShell Best Practices.</p>



<ul class="wp-block-list">
<li>Quick and Dirty one-liners in the console, nowadays Terminal</li>



<li>Gradually, those one-liners evolved into PowerShell scripts with better organized one-liners</li>



<li>Variables came along, then functions, reusability increased</li>



<li>Functions became modules, persistent data storage in JSON and technologically that was the end for a while</li>



<li>The last highlight was threading and runspaces</li>
</ul>



<p>I&#8217;ve been operating on these last two levels for quite a long time now, of course getting more efficient and generally my PowerShell knowledge became broader.</p>



<p>During this development, however, I noticed a problem: I&#8217;m a very organized person, at least in my professional environment 😉, and so should my code be, structured. I don&#8217;t think much of Clean Code, comments are just important at certain points, for me, for others, for my customers. Besides comments, structure is also important &#8211; what good do comments do me in a &#8218;bucket of chars&#8216;? I also love symmetrical code, yeah go ahead and laugh, but it immediately makes clear what&#8217;s a variable, what&#8217;s an assignment and what&#8217;s the value. When I see something like this&#8230;</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%"><div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
$userInfo = @{
   Name = $varSurename
   Address = $varStreet
   Data = $varRandomLongVar
}

$configSettings = @{
   ServerName = &#039;localhost&#039;
   Port = 5432
   Database = &#039;mydb&#039;
   Timeout = 30
}

$employee = @{
   Personal = @{
       FirstName = $varSurename
       LastName = &#039;Doe&#039;
       Street = $varStreet
   }
   Work = @{
       Department = &#039;IT&#039;
       Position = &#039;Developer&#039;
   }
}
</pre></div></div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<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:229px;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 style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)">… my insides turn outward 🤣 Maybe it&#8217;s also a disease. This is a normal writing style that&#8217;s considered clean, I know, but it should look like this …</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%"><div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
$userInfo = @{
   Name 	= $varSurename
   Address 	= $varStreet
   Data 	= $varRandomLongVar
}

$configSettings = @{
   ServerName 	= &#039;localhost&#039;
   Port 		= 5432
   Database 	= &#039;mydb&#039;
   Timeout 		= 30
}

$employee = @{
   Personal = @{
       FirstName 	= $varSurename
       LastName 	= &#039;Doe&#039;
       Street 		= $varStreet
   }
   Work 	= @{
       Department 	= &#039;IT&#039;
       Position 	= &#039;Developer&#039;
   }
}

$users = @(
   @{ Name = &#039;Alice&#039;; 		Role = &#039;Admin&#039; }
   @{ Name = $varSurename; 	Role = &#039;User&#039; }
)
</pre></div></div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="251" height="330" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-5.png" alt="" class="wp-image-515" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-5.png 251w, https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-5-228x300.png 228w" sizes="auto, (max-width: 251px) 100vw, 251px" /></figure>
</div>
</div>



<p style="margin-top:var(--wp--preset--spacing--50);margin-bottom:0">Anyway, that&#8217;s not what this is about. It&#8217;s basically the case that structure and order gradually decrease in larger projects and classes play exactly into this topic. But why only now? Classes have existed since PowerShell 5.0.</p>



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



<p>Of course I was an early adopter of all the AI chatbots and was amazed at what ChatGPT could already do 2 years ago. Of course the code, regardless of language, was unusable, but definitely useful for knowledge generation. As the quality progressed, the code got better and the solution approaches became more and more interesting.</p>



<p>At some point, classes started appearing in the suggestions and I consistently ignored them 😝. Through my C# journeys, I knew that classes are simply the standard, but you should fundamentally know what you want to do with them in the project to design them cleanly. And I didn&#8217;t want to make that effort.</p>



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



<p>It was time to adapt a 4-year-old solution to new requirements, as is sometimes the case. Since my knowledge doesn&#8217;t stand still either, after briefly skimming through the code, I decided:</p>



<p class="has-text-align-center" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>I&#8217;M NOT TOUCHING THIS ANYMORE</strong>, <strong>THIS ALL HAS TO BE NEW!!</strong></p>



<p>Now I was in the relaxed position that everything was available for the solution:</p>



<ul class="wp-block-list">
<li>Program flow chart</li>



<li>Function descriptions</li>



<li>Programmatic solution of the required functions at the lowest level</li>



<li>4 years of lessons learned</li>
</ul>



<p>So I only had to worry about orchestrating all the steps and decided to give classes a chance. In theory, this is namely the cleanest and most structured way to code.</p>



<p>The result hasn&#8217;t completely changed my way of coding, but it has sustainably changed it &#8211; but more on that later.</p>



<h2 class="wp-block-heading" id="powershell-classes-conclusion" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Conclusion After 5 Weeks in the Project</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full has-custom-border"><img loading="lazy" decoding="async" width="532" height="500" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/class-perfection.jpg" alt="I SAID PERFECTION" class="has-border-color has-contrast-border-color wp-image-518" style="border-width:1px" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/class-perfection.jpg 532w, https://dbavonnebenan.de/wp-content/uploads/2025/06/class-perfection-300x282.jpg 300w" sizes="auto, (max-width: 532px) 100vw, 532px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<p>Classes in PowerShell are so incredibly simple, so structured, so beautiful❤️. Of course the use case has to fit, since the implementation initially requires more structure, but when that&#8217;s given, there will be no way around classes for me anymore.</p>
</div>
</div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Why This Article, Aren&#8217;t There Enough Already?</h2>



<p>There are some articles about classes in PowerShell and object orientation, but still this topic is hardly covered in a classic tutorial. It&#8217;s always the functions and you have to know about this topic to find it. So I&#8217;m simply writing another article, also in german this time, to maybe reach one or the other additionally, because&#8230;</p>



<figure class="wp-block-image aligncenter size-large is-resized" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"><img loading="lazy" decoding="async" width="1024" height="191" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-1024x191.png" alt="" class="wp-image-517" style="width:493px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-1024x191.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-300x56.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-768x143.png 768w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw.png 1153w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



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



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--50)">Background Info on PowerShell Classes &#8211; OOP Since Version 5.0</h2>



<p>Classes have existed in PowerShell since PowerShell 5.0, so 2016&#8230; and I only learned about them a year ago 🤦‍♂️. PowerShell classes bring object-oriented programming concepts to PowerShell and thus also have all the basic features of a class.</p>



<ul class="wp-block-list">
<li><strong>Properties</strong>: Properties are strongly typed and support most validation attributes like [ValidateNotNull()], [ValidateRange()], etc.</li>



<li><strong>Methods</strong>: Methods are functions bound to an object and must explicitly define the return type</li>



<li><strong>Constructors</strong>: Enable initialization of objects with specific values</li>



<li><strong>Inheritance</strong>: Allows creating new classes from existing classes and extending their functionality</li>
</ul>



<p>A class, after loading, is its own data type &#8211; more on that later.</p>



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



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-right:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--50)">And How Does This Work Now?</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-top 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="307" height="328" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2.png" alt="Explanation incoming" class="wp-image-345" style="width:143px;height:auto" 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>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:80%">
<p>I still remember how I struggled with OOP many years ago and it&#8217;s generally assumed that rather admins than full-blood software developers initially deal with PowerShell. So I&#8217;ll try to keep it totally simple.</p>
</div>
</div>



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



<p>I&#8217;ll take a fictional module that queries server properties via remoting and evaluates them locally, a classic admin task.</p>



<p><strong>ATTENTION:</strong> Of course this example is very constructed and not necessarily practical, but in my opinion it shows the relationships quite well.</p>



<p>This PowerShell classes tutorial shows you the most important concepts for object-oriented programming with PowerShell.</p>



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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Properties</h3>



<p style="margin-top:0">A class has a firmly defined set of properties at all times. This cannot be changed at runtime, but must be described in the definition of the class.</p>



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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">The Class</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
# All Possible properties for the Server class
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem
# -------------------------------------------
}
</pre></div>


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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Constructors</h3>



<p style="margin-bottom:var(--wp--preset--spacing--50)">A constructor creates the instance of a class. The class can receive default values, or the constructor expects parameters. In our case, a server name makes sense. So I give the property <strong>ServerName</strong> a value directly when loading.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
# All Possible properties for the Server class
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem
# -------------------------------------------

    # Constructor
    Server(&#x5B;string]$name) {
        $this.ServerName = $name
    }
}
</pre></div>


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



<p>Now we have a class, but how do we get a server in there? By loading the class into a variable and preferably also dynamically for all servers.</p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
# All Possible properties for the Server class
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem
# -------------------------------------------

    # Constructor
    Server(&#x5B;string]$name) {
        $this.ServerName = $name
    }
}

$serverlist = @(&#039;Server1&#039;,&#039;Server2&#039;,&#039;Server3&#039;)

foreach ( $server in $serverlist ) {
    
    # Create a new Server object for each server name
    New-Variable -Name &quot;obj_$server&quot; -Value (&#x5B;Server]::new($server)) -Force

}
</pre></div>


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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Methods</h3>



<p>Methods make classes really interesting in my opinion. Methods are the functions with which I can manipulate properties of classes or generate RETURNS based on arguments that I add to the call. Here I already specify the type of return in the method definition. <strong>VOID</strong> thus logically creates no return.</p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem

    Server(&#x5B;string]$name) {
        $this.ServerName = $name
    }

    &#x5B;void] GetServerInfo() {

        try {

            $osInfo = Invoke-Command -ComputerName $this.ServerName -ScriptBlock {
                Get-CimInstance Win32_OperatingSystem | Select-Object Caption, LastBootUpTime
            } -ErrorAction Stop

            $this.IP = Invoke-Command -ComputerName $this.ServerName -ScriptBlock {
                (Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -notlike &#039;169.*&#039;} | Select-Object -First 1).IPAddress
            } -ErrorAction Stop

            $this.OperatingSystem = $osInfo.Caption
            $this.LastBootTime    = $osInfo.LastBootUpTime
            $this.Status          = &quot;Online&quot;

        } catch {

            $this.Status = &quot;Offline&quot;

        }
    }
}

$serverlist = @(&#039;Server1&#039;,&#039;Server2&#039;,&#039;Server3&#039;)

foreach ($server in $serverlist) {
    New-Variable -Name &quot;obj_$server&quot; -Value (&#x5B;Server]::new($server)) -Force
}

$obj_Server1.GetServerInfo()
$obj_Server2.GetServerInfo()
$obj_Server3.GetServerInfo()
</pre></div>


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



<p>Here I&#8217;ve inserted the method <strong>GetServerInfo()</strong>, which now collects the information about the server. I don&#8217;t need to pass an argument or start a cmdlet, since the instance (server name) of the class (Server) has inherited everything. I don&#8217;t need external functions, variables or anything else, everything is available in the class. ❤️ Following an example from the LAB:</p>



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



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--30)"><img loading="lazy" decoding="async" width="542" height="283" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell_classes_lab.png" alt="LAB Result of simple powershell class" class="wp-image-532" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell_classes_lab.png 542w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell_classes_lab-300x157.png 300w" sizes="auto, (max-width: 542px) 100vw, 542px" /><figcaption class="wp-element-caption">LAB Results</figcaption></figure>



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



<h2 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">And Now, Where&#8217;s the Benefit?</h2>



<p>Of course this isn&#8217;t the most optimal use case, but it&#8217;s understandable. One possibility would be to create a logging class. Here from my project:</p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class PatchLogger {
     &#x5B;string]        $ServerName
     &#x5B;string]        $LogPathServer
     &#x5B;string]        $LogLevel = &#039;INFO&#039;
     &#x5B;hashtable]     $LogTargets
     &#x5B;bool]          $ConsoleOutput
     &#x5B;bool]          $StreamOutput
     &#x5B;string]        $VerbosePreference
     &#x5B;string]        $DebugPreference

     # Constructor
     PatchLogger(	&#x5B;string]$LogPathServer,
					&#x5B;string]$ServerName,
					&#x5B;string]$MessageFile,
					&#x5B;string]$ErrorFile,
					&#x5B;string]$VerboseFile,
					&#x5B;string]$DebugFile,
					&#x5B;string]$SqlServerFile,
					&#x5B;bool]$ConsoleOutput 	= $true,
					&#x5B;bool]$StreamOutput 	= $false) {
					
          $this.LogPathServer   = $LogPathServer
          $this.ServerName      = $ServerName
          $this.ConsoleOutput   = $ConsoleOutput
          $this.StreamOutput    = $StreamOutput
          $this.LogTargets      = @{
               Main           = $MessageFile
               Error          = $ErrorFile
               Verbose        = $VerboseFile
               Debug          = $DebugFile
               SqlServer      = $SqlServerFile
          }

          $this.VerbosePreference = $Global:VerbosePreference
          $this.DebugPreference   = $Global:DebugPreference

          if ( -not (Test-Path $this.LogPathServer) ) {
               New-Item -Path $this.LogPathServer -ItemType Directory -Force | Out-Null
          }
    }
	
}
</pre></div>


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



<p>An instance of the class is loaded directly into the variable <strong>$PatchLogger</strong> when the module loads, and from now on I can start right away with <strong>$PatchLogger.Info($message)</strong>. How? Such a short command with such a complex class? Let&#8217;s get to the last thing, which in my opinion is the advantage par excellence: <strong>Overloading</strong>.</p>



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



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



<p>Overloading means nothing other than the number of arguments I pass to a method. Based on the number, the engine can distinguish which method is used, since I can have several with the same name. The technical term would be Method Overloading.</p>



<p>The added value lies in the fact that I don&#8217;t have to work with BoundParams, Switch or IF loops like with functions. When a helper method is called with only one argument, the missing arguments are filled in internally and the main method is called.</p>



<p>Let&#8217;s take the example <strong>$PatchLogger.Info($message)</strong></p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Hauptmethode
&#x5B;hashtable] WriteLog(&#x5B;string]$Level, &#x5B;string]$Message, &#x5B;string]$MessageCode, &#x5B;int]$Severity, &#x5B;string]$Target, &#x5B;bool]$ReturnObject) {...}

# Helfermethode
&#x5B;hashtable] Info(&#x5B;string]$Message) {
      return $this.WriteLog(&#039;INFO&#039;, $Message, $null, 0, &#039;Main&#039;, $true)
}

# Helfermethode 2
&#x5B;hashtable] Info(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
      return $this.WriteLog(&#039;INFO&#039;, $Message, $MessageCode, 0, &#039;Main&#039;, $true)
}
</pre></div>


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



<p>What will be most needed in a large module? A simple message to the main log, without message code and frills. So the helper method calls the main method with the default values that do exactly that.</p>



<p>Let&#8217;s look at helper method 2. This expects 2 arguments, namely a MessageCode. Now I can write a registered message with <strong>$PatchLogger.Info(&#8222;Process XY completed&#8220;,&#8220;I0002&#8243;)</strong>.</p>



<p>Of course I can also implement all this with functions, but I don&#8217;t think it&#8217;s as structured and pretty.</p>



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



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Complete PatchLogger Class</summary><div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class PatchLogger {
     &#x5B;string]        $ServerName
     &#x5B;string]        $LogPathServer
     &#x5B;string]        $LogLevel = &#039;INFO&#039;
     &#x5B;hashtable]     $LogTargets
     &#x5B;bool]          $ConsoleOutput
     &#x5B;bool]          $StreamOutput
     &#x5B;string]        $VerbosePreference
     &#x5B;string]        $DebugPreference

     # Constructor
     PatchLogger(&#x5B;string]$LogPathServer, &#x5B;string]$ServerName, &#x5B;string]$MessageFile, &#x5B;string]$ErrorFile, &#x5B;string]$VerboseFile, &#x5B;string]$DebugFile, &#x5B;string]$SqlServerFile, &#x5B;bool]$ConsoleOutput = $true, &#x5B;bool]$StreamOutput = $false) {
          $this.LogPathServer   = $LogPathServer
          $this.ServerName      = $ServerName
          $this.ConsoleOutput   = $ConsoleOutput
          $this.StreamOutput    = $StreamOutput
          $this.LogTargets      = @{
               Main           = $MessageFile
               Error          = $ErrorFile
               Verbose        = $VerboseFile
               Debug          = $DebugFile
               SqlServer      = $SqlServerFile
          }

          $this.VerbosePreference = $Global:VerbosePreference
          $this.DebugPreference   = $Global:DebugPreference

          if ( -not (Test-Path $this.LogPathServer) ) {
               New-Item -Path $this.LogPathServer -ItemType Directory -Force | Out-Null
          }
     }

     &#x5B;void] UpdatePreferences(&#x5B;string]$VerbosePreference, &#x5B;string]$DebugPreference) {
          $this.VerbosePreference = $VerbosePreference
          $this.DebugPreference   = $DebugPreference
     }

     # Central WriteLog method - all other methods call this one
     &#x5B;object] WriteLog(&#x5B;string]$Level, &#x5B;string]$Message, &#x5B;string]$MessageCode, &#x5B;int]$Severity, &#x5B;string]$Target, &#x5B;bool]$ReturnObject) {

          $timestamp          = Get-Date -Format &quot;yyyy-MM-dd HH:mm:ss&quot;
          $severityText       = if ($Severity -ne 9999) { &quot;S$Severity&quot; } else { &quot;&quot; }
          $messageCodeText    = if ($MessageCode) { &quot; $MessageCode&quot; } else { &quot;&quot; }

          $paddedLevel        = &quot;{0,-9}&quot; -f &quot;&#x5B;$Level]&quot;

          $additionalInfo     = &quot;$severityText$messageCodeText&quot;
          $logEntry           = if ( $level -eq &#039;BLANK&#039; ) {
                                   &quot;&quot;
                                } elseif ( $Level -notin @(&#039;VERBOSE&#039;,&#039;DEBUG&#039;) -and -not &#x5B;string]::IsNullOrEmpty($additionalInfo) ) {
                                   &quot;&#x5B;$timestamp] $paddedLevel &#x5B;$($this.ServerName)] $Message ($additionalInfo)&quot;
                                } else {
                                   &quot;&#x5B;$timestamp] $paddedLevel &#x5B;$($this.ServerName)] $Message&quot;
                              }

          $targetFile = $this.LogTargets&#x5B;$Target]
          if ( $targetFile ) {
               try {
                    Add-Content -Path $targetFile -Value $logEntry -Encoding UTF8

                    $verboseFile = $this.LogTargets&#x5B;&#039;Verbose&#039;]
                    if ( $verboseFile -and $Level -ne &#039;VERBOSE&#039; ) {
                         Add-Content -Path $verboseFile -Value $logEntry -Encoding UTF8 # for unbroken verbose stream
                    }

               } catch {
                    Invoke-ScriptError $_
               }
          }

          if ( $this.ConsoleOutput ) {
               switch ( $Level ) {
                    &#039;ERROR&#039;        { Write-Host $logEntry -ForegroundColor Red }
                    &#039;WARNING&#039;      { Write-Host $logEntry -ForegroundColor Yellow }
                    &#039;INFO&#039;         { Write-Host $logEntry -ForegroundColor Green }
                    &#039;BLANK&#039;        { Write-Host $logEntry}
                    &#039;VERBOSE&#039;      {
                         if ( $this.VerbosePreference -ne &#039;SilentlyContinue&#039; ) {
                              Write-Host $logEntry -ForegroundColor Cyan
                         }
                    }
                    &#039;DEBUG&#039;        {
                         if ( $this.DebugPreference -ne &#039;SilentlyContinue&#039; ) {
                              Write-Host $logEntry -ForegroundColor Magenta
                         }
                    }
               }
          }

          # PowerShell streams for integration - only if explicitly enabled
          if ( $this.StreamOutput ) {
               switch ($Level) {
                    &#039;ERROR&#039;   { Write-Error       $Message -ErrorAction Continue }
                    &#039;WARNING&#039; { Write-Warning     $Message }
                    &#039;VERBOSE&#039; { Write-Verbose     $Message }
                    &#039;DEBUG&#039;   { Write-Debug       $Message }
               }
          }

          # Return object only when requested
          if ( $ReturnObject ) {
               return @{
                    HasError    = $Level -eq &#039;ERROR&#039;
                    HasWarning  = $Level -eq &#039;WARNING&#039;
                    MessageCode = if ( $MessageCode ) { $MessageCode } else { $null }
                    Message     = $Message
                    Severity    = $Severity
                    Level       = $Level
                    Target      = $Target
               }
          }

          return $null
     }

     # BLANK Line
     &#x5B;void] BlankLine() {
          $this.WriteLog(&#039;BLANK&#039;, &#039;&#039;, $null, 0, &#039;Main&#039;, $false)
     }

     # INFO Methods - standard return hashtable
     &#x5B;hashtable] Info(&#x5B;string]$Message) {
          return $this.WriteLog(&#039;INFO&#039;, $Message, $null, 0, &#039;Main&#039;, $true)
     }

     &#x5B;hashtable] Info(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          return $this.WriteLog(&#039;INFO&#039;, $Message, $MessageCode, 0, &#039;Main&#039;, $true)
     }

     # INFO NoReturn
     &#x5B;void] InfoNoReturn(&#x5B;string]$Message) {
          $this.WriteLog(&#039;INFO&#039;, $Message, $null, 0, &#039;Main&#039;, $false)
     }

     &#x5B;void] InfoNoReturn(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          $this.WriteLog(&#039;INFO&#039;, $Message, $MessageCode, 0, &#039;Main&#039;, $false)
     }

     # WARNING Methods - standard return hashtable
     &#x5B;hashtable] Warning(&#x5B;string]$Message) {
          return $this.WriteLog(&#039;WARNING&#039;, $Message, $null, 1, &#039;Main&#039;, $true)
     }

     &#x5B;hashtable] Warning(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          return $this.WriteLog(&#039;WARNING&#039;, $Message, $MessageCode, 1, &#039;Main&#039;, $true)
     }

     # WARNING NoReturn
     &#x5B;void] WarningNoReturn(&#x5B;string]$Message) {
          $this.WriteLog(&#039;WARNING&#039;, $Message, $null, 1, &#039;Main&#039;, $false)
     }

     &#x5B;void] WarningNoReturn(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          $this.WriteLog(&#039;WARNING&#039;, $Message, $MessageCode, 1, &#039;Main&#039;, $false)
     }

     # ERROR Methods - standard return hashtable
     &#x5B;hashtable] Error(&#x5B;string]$Message) {
          return $this.WriteLog(&#039;ERROR&#039;, $Message, $null, 2, &#039;Error&#039;, $true)
     }

     &#x5B;hashtable] Error(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          return $this.WriteLog(&#039;ERROR&#039;, $Message, $MessageCode, 2, &#039;Error&#039;, $true)
     }

     # ERROR NoReturn
     &#x5B;void] ErrorNoReturn(&#x5B;string]$Message) {
          $this.WriteLog(&#039;ERROR&#039;, $Message, $null, 2, &#039;Error&#039;, $false)
     }

     &#x5B;void] ErrorNoReturn(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          $this.WriteLog(&#039;ERROR&#039;, $Message, $MessageCode, 2, &#039;Error&#039;, $false)
     }

     # VERBOSE &amp; DEBUG - NoReturn
     &#x5B;void] Verbose(&#x5B;string]$Message) {
          $this.WriteLog(&#039;VERBOSE&#039;, $Message, $null, 0, &#039;Verbose&#039;, $false)
     }

     &#x5B;void] Debug(&#x5B;string]$Message) {
          $this.WriteLog(&#039;DEBUG&#039;, $Message, $null, 0, &#039;Debug&#039;, $false)
     }

     # Step/SQL/AG Methods - NoReturn
     &#x5B;void] StepStart(&#x5B;int]$Step, &#x5B;string]$StepName) {
          $this.BlankLine()
          $message = &quot;========================= STEP $Step START: $StepName =========================&quot;
          $this.WriteLog(&#039;INFO&#039;, $message, $null, 9999, &#039;Main&#039;, $false)
     }

     &#x5B;void] StepEnd(&#x5B;int]$Step, &#x5B;string]$StepName, &#x5B;bool]$Success) {
          $status   = if ( $Success ) { &quot;SUCCESS&quot; } else { &quot;FAILED&quot; }
          $message  = &quot;========================= STEP $Step END: $StepName - $status =========================&quot;
          $this.WriteLog(&#039;INFO&#039;, $message, $null, 9999, &#039;Main&#039;, $false)
          $this.BlankLine()
     }

}
</pre></div></details>



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



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



<p>PowerShell classes revolutionize how you structure larger projects. Available since PowerShell 5.0, they offer object-oriented programming with properties, methods, constructors, and method overloading. The initial extra effort pays off through clean, maintainable code &#8211; especially for modules and more complex function collections.</p>



<p><strong>The most important advantages at a glance:</strong></p>



<ul class="wp-block-list">
<li>Strongly typed properties with validation</li>



<li>Encapsulated functionality through methods</li>



<li>Elegant overloading instead of complex parameter logic and a structure that remains understandable even after months</li>
</ul>



<p>For daily-doing scripts, the classic approach remains more practical, but as soon as reusability and structure become important, there&#8217;s no way around classes for me anymore. 🫡</p>



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


<figure style="width:250px;height:250px;" class="wp-block-post-featured-image"><a href="https://dbavonnebenan.de/powershell-classes-for-beginner-en/" target="_self"  style="height:250px"><img loading="lazy" decoding="async" width="256" height="256" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/logo-powershell-meets-classes.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="PowerShell Classes for Beginners &#8211; Structured Code Instead of Function Chaos" style="height:250px;object-fit:cover;" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/logo-powershell-meets-classes.png 256w, https://dbavonnebenan.de/wp-content/uploads/2025/06/logo-powershell-meets-classes-150x150.png 150w" sizes="auto, (max-width: 256px) 100vw, 256px" /></a></figure><p>The post <a href="https://dbavonnebenan.de/powershell-classes-for-beginner-en/">PowerShell Classes for Beginners – Structured Code Instead of Function Chaos</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/powershell-classes-for-beginner-en/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PowerShell Klassen für Anfänger &#8211; Strukturierter Code statt Funktions-Chaos</title>
		<link>https://dbavonnebenan.de/powershell-classes-for-beginner-de/</link>
					<comments>https://dbavonnebenan.de/powershell-classes-for-beginner-de/#respond</comments>
		
		<dc:creator><![CDATA[Gabriel]]></dc:creator>
		<pubDate>Sat, 14 Jun 2025 18:33:32 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Classes]]></category>
		<category><![CDATA[DE]]></category>
		<category><![CDATA[Klassen]]></category>
		<category><![CDATA[TUTORIAL]]></category>
		<guid isPermaLink="false">https://dbavonnebenan.de/?p=511</guid>

					<description><![CDATA[<p>Intro Seit eh und je nutze ich PowerShell nach Schema F, so ungefähr war auch mein Lernpfad entsprechend PowerShell Best Practices. Auf den letzten beiden Ebenen habe ich mich nun sehr lange bewegt, natürlich immer effizienter und allgemein wurde das PowerShell Wissen breiter. Während dieser Entwicklung merkte ich jedoch ein Problem: Ich bin ein sehr [&#8230;]</p>
<p>The post <a href="https://dbavonnebenan.de/powershell-classes-for-beginner-de/">PowerShell Klassen für Anfänger – Strukturierter Code statt Funktions-Chaos</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading" style="margin-top:0;margin-bottom:var(--wp--preset--spacing--50)">Intro</h2>



<p>Seit eh und je nutze ich PowerShell nach Schema F, so ungefähr war auch mein Lernpfad entsprechend PowerShell Best Practices.</p>



<ul class="wp-block-list">
<li>Quick and Dirty Einzeiler in der Konsole, mittlerweile Terminal</li>



<li>Nach und nach wurden aus den Einzeilern PowerShell Scripte mit besser organisierten Einzeilern</li>



<li>Es kamen Variablen, dann Funktionen, die Wiederverwendbarkeit stieg</li>



<li>Aus Funktionen wurden Module, persistente Datenhalden in Json und technologisch war das erstmal das Ende</li>



<li>Das letzte HighLight war Threading und Runspaces</li>
</ul>



<p>Auf den letzten beiden Ebenen habe ich mich nun sehr lange bewegt, natürlich immer effizienter und allgemein wurde das PowerShell Wissen breiter.</p>



<p>Während dieser Entwicklung merkte ich jedoch ein Problem: Ich bin ein sehr organisierter Mensch, zumindestens im beruflichen Umfeld 😉, und so soll auch mein Code sein, strukturiert. Von Clean Code halte ich nichts, Kommentare sind einfach punktuell wichtig, für mich, für andere, für meine Kunden. Neben Kommentaren ist aber auch die Struktur wichtig, was bringen mir Kommentare an einem &#8218;Bucket of Chars&#8216; ? Ebenfalls liebe ich symmetrischen Code, ja lacht ruhig, aber es macht sofort ersichtlich, was ist eine Variable, was eine Zusweisung und was der Value. Wenn ich sowas sehe&#8230;</p>



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



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%"><div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
$userInfo = @{
   Name = $varSurename
   Address = $varStreet
   Data = $varRandomLongVar
}

$configSettings = @{
   ServerName = &#039;localhost&#039;
   Port = 5432
   Database = &#039;mydb&#039;
   Timeout = 30
}

$employee = @{
   Personal = @{
       FirstName = $varSurename
       LastName = &#039;Doe&#039;
       Street = $varStreet
   }
   Work = @{
       Department = &#039;IT&#039;
       Position = &#039;Developer&#039;
   }
}
</pre></div></div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<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:229px;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:25px" aria-hidden="true" class="wp-block-spacer"></div>



<p style="margin-top:0;margin-bottom:0">&#8230; da kehrt sich mein Innerstes nach Außen 🤣 Ist vielleicht auch eine Krankheit. Dies ist eine normale Schreibweise, die als sauber gilt, ich weiß, aber das sollte doch so aussehen..</p>



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



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%"><div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
$userInfo = @{
   Name 	= $varSurename
   Address 	= $varStreet
   Data 	= $varRandomLongVar
}

$configSettings = @{
   ServerName 	= &#039;localhost&#039;
   Port 		= 5432
   Database 	= &#039;mydb&#039;
   Timeout 		= 30
}

$employee = @{
   Personal = @{
       FirstName 	= $varSurename
       LastName 	= &#039;Doe&#039;
       Street 		= $varStreet
   }
   Work 	= @{
       Department 	= &#039;IT&#039;
       Position 	= &#039;Developer&#039;
   }
}

$users = @(
   @{ Name = &#039;Alice&#039;; 		Role = &#039;Admin&#039; }
   @{ Name = $varSurename; 	Role = &#039;User&#039; }
)
</pre></div></div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="251" height="330" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-5.png" alt="" class="wp-image-515" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-5.png 251w, https://dbavonnebenan.de/wp-content/uploads/2025/06/emote-5-228x300.png 228w" sizes="auto, (max-width: 251px) 100vw, 251px" /></figure>
</div>
</div>



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



<p style="margin-top:0;margin-bottom:0">Wie auch immer, darum solls hier nicht gehen. Es ist grundsätzlich so, dass die Struktur und Ordnung bei größeren Projekten nach und nach abnimmt und Klassen genau auf dieses Thema einspielen. Aber warum jetzt erst? Klassen gibt es seit PowerShell 5.0 .</p>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--40)">AI Assisted Coding</h2>



<p>Natürlich war ich early Adopter der ganzen KI Chatbots und war erstaunt, was ChatGPT vor 2 Jahren schon konnte. Natürlich war der Code, egal welche Sprache, unbrauchbar, aber für Wissenserzeugung allemal nützlich. So wurde mit fortlaufender Qualität der Code besser und auch die Lösungswege wurden immer interessanter. </p>



<p>Irgendwann sind in den Vorschlägen Klassen aufgetaucht und ich habe es konsequent ignoriert 😝. Durch meine C# Reisen wusste ich, dass Klassen einfach der Standard sind, man aber schon grundlegend Wissen sollte, was ich damit machen will im Projekt, um diese sauber zu entwerfen. Und diesen Aufwand wollte ich mir nicht machen.</p>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--40)">Das neue Projekt</h2>



<p>Es war an der Zeit, eine 4 Jahre alte Lösung an neue Anforderungen anzupassen, wie das halt manchmal so der Fall ist. Da mein Wissen ja auch nicht stehen bleibt, habe ich nach kurzem überfliegen des Codes entschieden:</p>



<p class="has-text-align-center" style="margin-top:var(--wp--preset--spacing--50);margin-bottom:var(--wp--preset--spacing--50)"><strong>DAS FASSE ICH NICHT MEHR AN</strong>, <strong>DAS MUSS ALLES NEU!!</strong></p>



<p>Nun war ich in der entspannten Lage, dass für die Lösung alles vorhanden war</p>



<ul class="wp-block-list">
<li>Programmablaufplan (PAP)</li>



<li>Funktionsbeschreibungen</li>



<li>Programmatische Lösung der benötigten Funktionen auf unterster Ebene</li>



<li>4 Jahre Lessons learned</li>
</ul>



<p>Somit musste ich mich nur um die Orchestrierung aller Schritte kümmern und habe entschieden, dass ich den Klassen mal eine Chance geben werde. In der Theorie ist dies nämlich die sauberste und strukturierteste Möglichkeit zu Coden.</p>



<p>Das Ergebnis hat meine Art zu Coden nicht völlig, aber nachhaltig verändert &#8211; aber dazu später mehr.</p>



<h2 class="wp-block-heading" id="powershell-classes-conclusion" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Fazit nach 5 Wochen im Projekt</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<figure class="wp-block-image size-full has-custom-border"><img loading="lazy" decoding="async" width="532" height="500" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/class-perfection.jpg" alt="I SAID PERFECTION" class="has-border-color has-contrast-border-color wp-image-518" style="border-width:1px" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/class-perfection.jpg 532w, https://dbavonnebenan.de/wp-content/uploads/2025/06/class-perfection-300x282.jpg 300w" sizes="auto, (max-width: 532px) 100vw, 532px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:50%">
<p>Klassen in PowerShell sind so unglaublich simpel, so strukturiert, so wunderschön❤️. Natürlich muss der UseCase passen, da die Implementierung initial mehr Struktur verlangt, aber wenn dieser gegeben ist, wird für mich kein Weg mehr an Klassen vorbei führen. </p>
</div>
</div>



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--70);margin-bottom:var(--wp--preset--spacing--50)">Warum dieser Artikel, gibt doch genug?</h2>



<p>Es gibt einige Artikel über Klassen in PowerShell und Objektorientierung aber trotzdem wird dieses Thema kaum in einem klassischen Tutorial behandelt. Es sind immer die Funktionen und man muss um dieses Thema wissen um es zu finden. Somit schreibe ich einfach noch einen Artikel, auch mal in deutsch, um vielleicht doch den ein oder anderen zusätzlich zu erreichen, weil&#8230;</p>



<figure class="wp-block-image aligncenter size-large is-resized" style="margin-top:var(--wp--preset--spacing--80);margin-bottom:var(--wp--preset--spacing--80)"><img loading="lazy" decoding="async" width="1024" height="191" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-1024x191.png" alt="" class="wp-image-517" style="width:493px;height:auto" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-1024x191.png 1024w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-300x56.png 300w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw-768x143.png 768w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell-classes-ftw.png 1153w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



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



<h2 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--60);margin-right:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--60)">Hintergrundinfos zu PowerShell Klassen &#8211; OOP seit Version 5.0</h2>



<p style="margin-bottom:var(--wp--preset--spacing--30)">Klassen gibt es in PowerShell seit PowerShell 5.0 also 2016&#8230; und ich habe vor einem Jahr erst davon erfahren 🤦‍♂️. PowerShell Klassen bringen objektorientierte Programmierkonzepte in PowerShell und haben somit auch haben alle grundlegenden Features einer Klasse.</p>



<ul class="wp-block-list">
<li><strong>Eigenschaften (Properties)</strong>: Eigenschaften sind stark typisiert und unterstützen die meisten Validierungsattribute wie [ValidateNotNull()], [ValidateRange()] etc. </li>



<li><strong>Methoden</strong>: Methoden sind Funktionen, die an ein Objekt gebunden sind und explizit den Rückgabetyp definieren müssen</li>



<li><strong>Konstruktoren</strong>: Ermöglichen die Initialisierung von Objekten mit spezifischen Werten </li>



<li><strong>Vererbung</strong>: Erlaubt es, neue Klassen von bestehenden Klassen zu erstellen und deren Funktionalität zu erweitern</li>
</ul>



<p style="margin-top:var(--wp--preset--spacing--30)">Eine Klasse ist nach dem Laden ein eigener Datentyp, später mehr dazu.</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--70);margin-right:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--50)">Und wie funktioniert das jetzt?</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-28f84493 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-top 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="307" height="328" src="https://dbavonnebenan.de/wp-content/uploads/2025/05/emotes_2.png" alt="Explanation incoming" class="wp-image-345" style="width:143px;height:auto" 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>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:80%">
<p>Ich weiß noch, wie ich mich vor vielen Jahren mit OOP schwer tat und allgemein davon auszugehen ist, dass sich doch eher Admins als vollblut Software Entwickler initial mit PowerShell auseinander setzen. Somit versuche ich es mal total simpel.</p>
</div>
</div>



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



<p>Ich nehme mal ein fiktives Modul, welche per Remoting Serverproperties abfragt und lokal auswertet, ein klassischer AdminTask. </p>



<p><strong>ACHTUNG:</strong> Natürlich ist dieses Beispiel sehr konstruiert und nicht zwingend praktikabel aber es zeigt meiner Meinung nach die Zusammenhänge recht gut.</p>



<p>Dieses PowerShell Klassen Tutorial zeigt dir die wichtigsten Konzepte für objektorientierte Programmierung mit PowerShell.</p>



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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Eigenschaften (Properties)</h3>



<p style="margin-top:0">Eine Klasse hat zu jeder Zeit ein fest definierten Satz an Eigenschaften. Dieser kann zur Laufzeit nicht geändert werden, sondern muss in der Definition der Klasse beschrieben werden.</p>



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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Die Klasse</h3>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
# All Possible properties for the Server class
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem
# -------------------------------------------
}
</pre></div>


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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Konstruktoren</h3>



<p style="margin-bottom:var(--wp--preset--spacing--50)">Ein Konstruktor erzeugt die Instanz einer Klasse. Dabei kann die Klasse default Values erhalten, oder der Konstruktor erwartet Parameter. In unserem Fall ist ein Servername sinnvoll. Somit gebe ich der Property <strong>ServerName </strong>direkt beim Laden einen Wert.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
# All Possible properties for the Server class
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem
# -------------------------------------------

    # Constructor
    Server(&#x5B;string]$name) {
        $this.ServerName = $name
    }
}
</pre></div>


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



<p>Nun haben wir zwar ein Klasse aber wie bekommen wir nun einen Server da rein? Indem wir die Klasse in eine Variable laden und am besten auch noch dynamisch für alle Server.</p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
# All Possible properties for the Server class
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem
# -------------------------------------------

    # Constructor
    Server(&#x5B;string]$name) {
        $this.ServerName = $name
    }
}

$serverlist = @(&#039;Server1&#039;,&#039;Server2&#039;,&#039;Server3&#039;)

foreach ( $server in $serverlist ) {
    
    # Create a new Server object for each server name
    New-Variable -Name &quot;obj_$server&quot; -Value (&#x5B;Server]::new($server)) -Force

}
</pre></div>


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



<h3 class="wp-block-heading" style="margin-top:var(--wp--preset--spacing--40);margin-right:var(--wp--preset--spacing--20);margin-bottom:var(--wp--preset--spacing--40);margin-left:var(--wp--preset--spacing--20)">Methoden</h3>



<p>Methoden machen meiner Meinung nach die Klassen erst richtig interessant. Methoden sind die Funktionen mit denen ich Eigenschaften der Klassen manipulieren kann oder auf Basis von Argumenten, welche ich dem Aufruf hinzufüge, RETURNS erzeugen kann. Hierbei gebe ich bereits in der Methodendefintion den Typ der Rückgabe an. <strong>VOID</strong> erzeugt somit logischerweise keine Rückgabe.</p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class Server {
    &#x5B;string]        $ServerName
    &#x5B;string]        $Status
    &#x5B;ipaddress]     $IP 
    &#x5B;string]        $Location
    &#x5B;datetime]      $LastBootTime
    &#x5B;string]        $OperatingSystem

    Server(&#x5B;string]$name) {
        $this.ServerName = $name
    }

    &#x5B;void] GetServerInfo() {

        try {

            $osInfo = Invoke-Command -ComputerName $this.ServerName -ScriptBlock {
                Get-CimInstance Win32_OperatingSystem | Select-Object Caption, LastBootUpTime
            } -ErrorAction Stop

            $this.IP = Invoke-Command -ComputerName $this.ServerName -ScriptBlock {
                (Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -notlike &#039;169.*&#039;} | Select-Object -First 1).IPAddress
            } -ErrorAction Stop

            $this.OperatingSystem = $osInfo.Caption
            $this.LastBootTime    = $osInfo.LastBootUpTime
            $this.Status          = &quot;Online&quot;

        } catch {

            $this.Status = &quot;Offline&quot;

        }
    }
}

$serverlist = @(&#039;Server1&#039;,&#039;Server2&#039;,&#039;Server3&#039;)

foreach ($server in $serverlist) {
    New-Variable -Name &quot;obj_$server&quot; -Value (&#x5B;Server]::new($server)) -Force
}

$obj_Server1.GetServerInfo()
$obj_Server2.GetServerInfo()
$obj_Server3.GetServerInfo()
</pre></div>


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



<p>Hier habe ich die Methode <strong>GetServerInfo()</strong> eingefügt, die nun die Informationen zum Server sammelt. Dabei muss ich weder ein Argument mitgeben oder ein Cmdlet starten, da die Instanz (Servername) der Klasse (Server) alles vererbt bekommen hat. Ich brauche keine externen Funktionen, Variablen oder sonst was, alles in der Klasse vorhanden. ❤️ Folgend ein Beispiel aus dem LAB</p>



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



<figure class="wp-block-image aligncenter size-full" style="margin-top:var(--wp--preset--spacing--30);margin-bottom:var(--wp--preset--spacing--30)"><img loading="lazy" decoding="async" width="542" height="283" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell_classes_lab.png" alt="LAB Result of simple powershell class" class="wp-image-532" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell_classes_lab.png 542w, https://dbavonnebenan.de/wp-content/uploads/2025/06/powershell_classes_lab-300x157.png 300w" sizes="auto, (max-width: 542px) 100vw, 542px" /><figcaption class="wp-element-caption">LAB Results</figcaption></figure>



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



<h2 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">Und jetzt, wo ist der Nutzen?</h2>



<p>Natürlich ist das nicht der optimalste Use Case, dafür verständlich. Eine Möglichkeit wäre, eine LoggingKlasse zu erstellen. Anbei aus meinem Projekt:</p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class PatchLogger {
     &#x5B;string]        $ServerName
     &#x5B;string]        $LogPathServer
     &#x5B;string]        $LogLevel = &#039;INFO&#039;
     &#x5B;hashtable]     $LogTargets
     &#x5B;bool]          $ConsoleOutput
     &#x5B;bool]          $StreamOutput
     &#x5B;string]        $VerbosePreference
     &#x5B;string]        $DebugPreference

     # Constructor
     PatchLogger(	&#x5B;string]$LogPathServer,
					&#x5B;string]$ServerName,
					&#x5B;string]$MessageFile,
					&#x5B;string]$ErrorFile,
					&#x5B;string]$VerboseFile,
					&#x5B;string]$DebugFile,
					&#x5B;string]$SqlServerFile,
					&#x5B;bool]$ConsoleOutput 	= $true,
					&#x5B;bool]$StreamOutput 	= $false) {
					
          $this.LogPathServer   = $LogPathServer
          $this.ServerName      = $ServerName
          $this.ConsoleOutput   = $ConsoleOutput
          $this.StreamOutput    = $StreamOutput
          $this.LogTargets      = @{
               Main           = $MessageFile
               Error          = $ErrorFile
               Verbose        = $VerboseFile
               Debug          = $DebugFile
               SqlServer      = $SqlServerFile
          }

          $this.VerbosePreference = $Global:VerbosePreference
          $this.DebugPreference   = $Global:DebugPreference

          if ( -not (Test-Path $this.LogPathServer) ) {
               New-Item -Path $this.LogPathServer -ItemType Directory -Force | Out-Null
          }
    }
	
}
</pre></div>


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



<p>Eine Instanz der Klasse wird direkt beim Laden des Moduls in die Variable <strong>$PatchLogger </strong>geladen und ab jetzt kann ich mit <strong>$PatchLogger.Info($message)</strong> schon direkt loslegen. Wie? So ein kurzer Befehl bei einer so komplexen Klasse? Kommen wir zum letzten, was meiner Meinung nach der Vorteil schlechthin ist: <strong>Überladung</strong>.</p>



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



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



<p>Überladung heisst nichts anderes als die Anzahl der Argumente, die ich einer Methode übergebe. Anhand der Anzahl kann die Engine unterscheiden, welche Methode genutzt wird, da ich mehrer mit den gleichen Namen haben kann. Der Fachbegriff wäre Method Overloading.</p>



<p>Der Mehrwert liegt darin, dass ich nicht wie bei Funktionen mit BoundParams, Switch oder IF SChleifen arbeiten muss. Wenn eine Helfer Methode mit nur einem Argument aufgerufen wird, werden intern die fehlenden Argumente aufgefüllt und die Hauptmethode aufgerufen.</p>



<p>Nehmen wir das Beispiel <strong>$PatchLogger.Info($message)</strong> </p>



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


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
# Hauptmethode
&#x5B;hashtable] WriteLog(&#x5B;string]$Level, &#x5B;string]$Message, &#x5B;string]$MessageCode, &#x5B;int]$Severity, &#x5B;string]$Target, &#x5B;bool]$ReturnObject) {...}

# Helfermethode
&#x5B;hashtable] Info(&#x5B;string]$Message) {
      return $this.WriteLog(&#039;INFO&#039;, $Message, $null, 0, &#039;Main&#039;, $true)
}

# Helfermethode 2
&#x5B;hashtable] Info(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
      return $this.WriteLog(&#039;INFO&#039;, $Message, $MessageCode, 0, &#039;Main&#039;, $true)
}
</pre></div>


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



<p>Was wird das meiste sein, was ich ich einem großen Modul benötige? Eine einfache Message ins Main Log, ohne Messagecode und SchnickSchnack. Somit ruft die Helfermethode die Hauptmethode mit den Defaultwerten auf, die genau das bewirken.</p>



<p>Schauen wir uns Helfermethode 2 an. Diese erwartet 2 Argumente, nämlich einen MessageCode. Schon kann ich mit <strong>$PatchLogger.Info(&#8222;Prozess XY abgeschlossen&#8220;,&#8220;I0002&#8243;)</strong> eine registrierte Message schreiben. </p>



<p>Natürlich kann ich das auch alles mit Funktionen realisieren aber ich denke nicht so strukturiert und hübsch. </p>



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



<details class="wp-block-details is-layout-flow wp-block-details-is-layout-flow"><summary>Gesamte PatchLogger Klasse</summary><div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
class PatchLogger {
     &#x5B;string]        $ServerName
     &#x5B;string]        $LogPathServer
     &#x5B;string]        $LogLevel = &#039;INFO&#039;
     &#x5B;hashtable]     $LogTargets
     &#x5B;bool]          $ConsoleOutput
     &#x5B;bool]          $StreamOutput
     &#x5B;string]        $VerbosePreference
     &#x5B;string]        $DebugPreference

     # Constructor
     PatchLogger(&#x5B;string]$LogPathServer, &#x5B;string]$ServerName, &#x5B;string]$MessageFile, &#x5B;string]$ErrorFile, &#x5B;string]$VerboseFile, &#x5B;string]$DebugFile, &#x5B;string]$SqlServerFile, &#x5B;bool]$ConsoleOutput = $true, &#x5B;bool]$StreamOutput = $false) {
          $this.LogPathServer   = $LogPathServer
          $this.ServerName      = $ServerName
          $this.ConsoleOutput   = $ConsoleOutput
          $this.StreamOutput    = $StreamOutput
          $this.LogTargets      = @{
               Main           = $MessageFile
               Error          = $ErrorFile
               Verbose        = $VerboseFile
               Debug          = $DebugFile
               SqlServer      = $SqlServerFile
          }

          $this.VerbosePreference = $Global:VerbosePreference
          $this.DebugPreference   = $Global:DebugPreference

          if ( -not (Test-Path $this.LogPathServer) ) {
               New-Item -Path $this.LogPathServer -ItemType Directory -Force | Out-Null
          }
     }

     &#x5B;void] UpdatePreferences(&#x5B;string]$VerbosePreference, &#x5B;string]$DebugPreference) {
          $this.VerbosePreference = $VerbosePreference
          $this.DebugPreference   = $DebugPreference
     }

     # Central WriteLog method - all other methods call this one
     &#x5B;object] WriteLog(&#x5B;string]$Level, &#x5B;string]$Message, &#x5B;string]$MessageCode, &#x5B;int]$Severity, &#x5B;string]$Target, &#x5B;bool]$ReturnObject) {

          $timestamp          = Get-Date -Format &quot;yyyy-MM-dd HH:mm:ss&quot;
          $severityText       = if ($Severity -ne 9999) { &quot;S$Severity&quot; } else { &quot;&quot; }
          $messageCodeText    = if ($MessageCode) { &quot; $MessageCode&quot; } else { &quot;&quot; }

          $paddedLevel        = &quot;{0,-9}&quot; -f &quot;&#x5B;$Level]&quot;

          $additionalInfo     = &quot;$severityText$messageCodeText&quot;
          $logEntry           = if ( $level -eq &#039;BLANK&#039; ) {
                                   &quot;&quot;
                                } elseif ( $Level -notin @(&#039;VERBOSE&#039;,&#039;DEBUG&#039;) -and -not &#x5B;string]::IsNullOrEmpty($additionalInfo) ) {
                                   &quot;&#x5B;$timestamp] $paddedLevel &#x5B;$($this.ServerName)] $Message ($additionalInfo)&quot;
                                } else {
                                   &quot;&#x5B;$timestamp] $paddedLevel &#x5B;$($this.ServerName)] $Message&quot;
                              }

          $targetFile = $this.LogTargets&#x5B;$Target]
          if ( $targetFile ) {
               try {
                    Add-Content -Path $targetFile -Value $logEntry -Encoding UTF8

                    $verboseFile = $this.LogTargets&#x5B;&#039;Verbose&#039;]
                    if ( $verboseFile -and $Level -ne &#039;VERBOSE&#039; ) {
                         Add-Content -Path $verboseFile -Value $logEntry -Encoding UTF8 # for unbroken verbose stream
                    }

               } catch {
                    Invoke-ScriptError $_
               }
          }

          if ( $this.ConsoleOutput ) {
               switch ( $Level ) {
                    &#039;ERROR&#039;        { Write-Host $logEntry -ForegroundColor Red }
                    &#039;WARNING&#039;      { Write-Host $logEntry -ForegroundColor Yellow }
                    &#039;INFO&#039;         { Write-Host $logEntry -ForegroundColor Green }
                    &#039;BLANK&#039;        { Write-Host $logEntry}
                    &#039;VERBOSE&#039;      {
                         if ( $this.VerbosePreference -ne &#039;SilentlyContinue&#039; ) {
                              Write-Host $logEntry -ForegroundColor Cyan
                         }
                    }
                    &#039;DEBUG&#039;        {
                         if ( $this.DebugPreference -ne &#039;SilentlyContinue&#039; ) {
                              Write-Host $logEntry -ForegroundColor Magenta
                         }
                    }
               }
          }

          # PowerShell streams for integration - only if explicitly enabled
          if ( $this.StreamOutput ) {
               switch ($Level) {
                    &#039;ERROR&#039;   { Write-Error       $Message -ErrorAction Continue }
                    &#039;WARNING&#039; { Write-Warning     $Message }
                    &#039;VERBOSE&#039; { Write-Verbose     $Message }
                    &#039;DEBUG&#039;   { Write-Debug       $Message }
               }
          }

          # Return object only when requested
          if ( $ReturnObject ) {
               return @{
                    HasError    = $Level -eq &#039;ERROR&#039;
                    HasWarning  = $Level -eq &#039;WARNING&#039;
                    MessageCode = if ( $MessageCode ) { $MessageCode } else { $null }
                    Message     = $Message
                    Severity    = $Severity
                    Level       = $Level
                    Target      = $Target
               }
          }

          return $null
     }

     # BLANK Line
     &#x5B;void] BlankLine() {
          $this.WriteLog(&#039;BLANK&#039;, &#039;&#039;, $null, 0, &#039;Main&#039;, $false)
     }

     # INFO Methods - standard return hashtable
     &#x5B;hashtable] Info(&#x5B;string]$Message) {
          return $this.WriteLog(&#039;INFO&#039;, $Message, $null, 0, &#039;Main&#039;, $true)
     }

     &#x5B;hashtable] Info(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          return $this.WriteLog(&#039;INFO&#039;, $Message, $MessageCode, 0, &#039;Main&#039;, $true)
     }

     # INFO NoReturn
     &#x5B;void] InfoNoReturn(&#x5B;string]$Message) {
          $this.WriteLog(&#039;INFO&#039;, $Message, $null, 0, &#039;Main&#039;, $false)
     }

     &#x5B;void] InfoNoReturn(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          $this.WriteLog(&#039;INFO&#039;, $Message, $MessageCode, 0, &#039;Main&#039;, $false)
     }

     # WARNING Methods - standard return hashtable
     &#x5B;hashtable] Warning(&#x5B;string]$Message) {
          return $this.WriteLog(&#039;WARNING&#039;, $Message, $null, 1, &#039;Main&#039;, $true)
     }

     &#x5B;hashtable] Warning(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          return $this.WriteLog(&#039;WARNING&#039;, $Message, $MessageCode, 1, &#039;Main&#039;, $true)
     }

     # WARNING NoReturn
     &#x5B;void] WarningNoReturn(&#x5B;string]$Message) {
          $this.WriteLog(&#039;WARNING&#039;, $Message, $null, 1, &#039;Main&#039;, $false)
     }

     &#x5B;void] WarningNoReturn(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          $this.WriteLog(&#039;WARNING&#039;, $Message, $MessageCode, 1, &#039;Main&#039;, $false)
     }

     # ERROR Methods - standard return hashtable
     &#x5B;hashtable] Error(&#x5B;string]$Message) {
          return $this.WriteLog(&#039;ERROR&#039;, $Message, $null, 2, &#039;Error&#039;, $true)
     }

     &#x5B;hashtable] Error(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          return $this.WriteLog(&#039;ERROR&#039;, $Message, $MessageCode, 2, &#039;Error&#039;, $true)
     }

     # ERROR NoReturn
     &#x5B;void] ErrorNoReturn(&#x5B;string]$Message) {
          $this.WriteLog(&#039;ERROR&#039;, $Message, $null, 2, &#039;Error&#039;, $false)
     }

     &#x5B;void] ErrorNoReturn(&#x5B;string]$Message, &#x5B;string]$MessageCode) {
          $this.WriteLog(&#039;ERROR&#039;, $Message, $MessageCode, 2, &#039;Error&#039;, $false)
     }

     # VERBOSE &amp; DEBUG - NoReturn
     &#x5B;void] Verbose(&#x5B;string]$Message) {
          $this.WriteLog(&#039;VERBOSE&#039;, $Message, $null, 0, &#039;Verbose&#039;, $false)
     }

     &#x5B;void] Debug(&#x5B;string]$Message) {
          $this.WriteLog(&#039;DEBUG&#039;, $Message, $null, 0, &#039;Debug&#039;, $false)
     }

     # Step/SQL/AG Methods - NoReturn
     &#x5B;void] StepStart(&#x5B;int]$Step, &#x5B;string]$StepName) {
          $this.BlankLine()
          $message = &quot;========================= STEP $Step START: $StepName =========================&quot;
          $this.WriteLog(&#039;INFO&#039;, $message, $null, 9999, &#039;Main&#039;, $false)
     }

     &#x5B;void] StepEnd(&#x5B;int]$Step, &#x5B;string]$StepName, &#x5B;bool]$Success) {
          $status   = if ( $Success ) { &quot;SUCCESS&quot; } else { &quot;FAILED&quot; }
          $message  = &quot;========================= STEP $Step END: $StepName - $status =========================&quot;
          $this.WriteLog(&#039;INFO&#039;, $message, $null, 9999, &#039;Main&#039;, $false)
          $this.BlankLine()
     }

}
</pre></div></details>



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



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



<p>PowerShell Klassen revolutionieren die Art, wie du größere Projekte strukturierst. Seit PowerShell 5.0 verfügbar, bieten sie objektorientierte Programmierung mit Eigenschaften, Methoden, Konstruktoren und Method Overloading. Der anfängliche Mehraufwand zahlt sich durch sauberen, wartbaren Code aus &#8211; besonders bei Modulen und komplexeren Funktionssammlungen.</p>



<p><strong>Die wichtigsten Vorteile auf einen Blick</strong></p>



<ul class="wp-block-list">
<li>Stark typisierte Properties mit Validierung</li>



<li>gekapselte Funktionalität durch Methoden</li>



<li>elegante Überladung statt komplexer Parameter-Logik und eine Struktur, die auch nach Monaten noch verständlich bleibt</li>
</ul>



<p>Für Daily-Doing-Scripts bleibt der klassische Ansatz praktischer, aber sobald Wiederverwendbarkeit und Struktur wichtig werden, führt für mich kein Weg mehr an Klassen vorbei. 🫡</p>



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


<figure style="width:500px;height:500px;" class="wp-block-post-featured-image"><img loading="lazy" decoding="async" width="256" height="256" src="https://dbavonnebenan.de/wp-content/uploads/2025/06/logo-powershell-meets-classes.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="PowerShell meets Classes" style="height:500px;object-fit:cover;" srcset="https://dbavonnebenan.de/wp-content/uploads/2025/06/logo-powershell-meets-classes.png 256w, https://dbavonnebenan.de/wp-content/uploads/2025/06/logo-powershell-meets-classes-150x150.png 150w" sizes="auto, (max-width: 256px) 100vw, 256px" /></figure><p>The post <a href="https://dbavonnebenan.de/powershell-classes-for-beginner-de/">PowerShell Klassen für Anfänger – Strukturierter Code statt Funktions-Chaos</a> first appeared on <a href="https://dbavonnebenan.de">DBA von Nebenan</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://dbavonnebenan.de/powershell-classes-for-beginner-de/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
