Going beyond PowerShell's limits: access the .NET framework directly, automate desktop applications like Excel through COM objects, and add custom logic with inline C# code via Add-Type.

In episode 16 you accessed the system information repository via CIM. But data outside the operating system — files, network, dates, encryption, even desktop applications — can also be reached. The secret: PowerShell is built on .NET, and every line of code you write actually stands on that foundation.
Episode 17 opens two doors: .NET integration — calling .NET types and methods directly, from System.IO to System.Security.Cryptography — and COM objects — automating desktop applications like Excel and Word. At the end, you'll inject your own C# code with Add-Type.
PowerShell is built on .NET — every string, number, or object you hold is a .NET object. Access to .NET uses type literals: the type name inside square brackets, for example [System.Math], [System.IO.File], or [System.DateTime].
The basic pattern: static methods are called with two colons after the type name. Static methods don't need an instance — they're called directly from the type:
[System.Math]::Max(5, 10)
[System.DateTime]::Now
[System.Math]::Round(3.14159, 2)[System.DateTime]::Now returns the current time; [System.Math]::Round rounds a number. Both are called directly from the type without creating an object. This differs from instance methods, which operate on an object:
$tanggal = [System.DateTime]::Now
$tanggal.AddDays(7)$tanggal is an instance; AddDays is a method operating on that instance. These two patterns are the foundation of all .NET integration: static for utilities, instance for objects.
.NET is organized into namespaces — conceptual folders containing related types. Some of the most used:
| Namespace | Function |
|---|---|
| System.IO | Files, folders, streams |
| System.DateTime | Dates and times |
| System.Net | Networking, HTTP |
| System.Security.Cryptography | Encryption and hashing |
| System.Text.RegularExpressions | Advanced regex |
A quick practice per namespace:
[System.IO.File]::ReadAllText("/etc/hosts")
[System.IO.File]::WriteAllText("/tmp/hello.txt", "Halo dari PowerShell")[System.Net.WebClient]::new().DownloadString("https://contoh.com/data")Note the [System.Net.WebClient]::new() pattern — PowerShell's way to call a .NET constructor. For types constructed with parameters, add the arguments inside the parentheses.
Most .NET types must be instantiated before use. There are two ways: the constructor with ::new() (PowerShell 5+), or the New-Object cmdlet:
$hasil1 = [System.Text.StringBuilder]::new()
$hasil2 = New-Object System.Text.StringBuilderStringBuilder is an object for efficiently assembling strings — an analogy is sticking labels one by one onto a notebook, rather than rewriting the entire notebook every time. Compare the speed of joining thousands of strings with the += operator versus StringBuilder; the difference is drastic.
COM (Component Object Model) is a Windows technology that lets scripts "drive" applications: Excel, Word, Outlook. Through New-Object -ComObject, you create an application instance and control it from PowerShell.
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$buku = $excel.Workbooks.Add()
$sheet = $buku.Worksheets.Item(1)
$sheet.Cells.Item(1,1) = "Nama"
$sheet.Cells.Item(1,2) = "Skor"
$sheet.Cells.Item(2,1) = "Arman"
$sheet.Cells.Item(2,2) = 95
$buku.SaveAs("C:\tmp\laporan.xlsx")
$buku.Close()This works because Excel exposes COM interfaces. $excel.Visible = $false makes the application run without showing a window — a common automation mode for generating reports. For Word, the pattern is similar: New-Object -ComObject Word.Application then $word.Documents.Add().
COM objects are resources that must be released — like borrowing a company car: once done you must return it, or fines pile up (here: application processes hanging in memory).
$excel = New-Object -ComObject Excel.Application
try {
$buku = $excel.Workbooks.Add()
$buku.SaveAs("C:\tmp\laporan.xlsx")
$buku.Close()
}
finally {
$excel.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}Marshal.ReleaseComObject decrements the COM reference counter; when it reaches zero, the object is freed. The [GC]::Collect and [GC]::WaitForPendingFinalizers calls ensure resources are truly returned to the system. This finally pattern is exactly the lesson from episode 12: cleanup is guaranteed to run no matter what happens.
Warning
Forgetting to release COM objects leaves application processes hanging in memory. An Excel created via script and not released will remain as an EXCEL.EXE process in Task Manager — and pile up with every script execution. Always release in a finally block and call $app.Quit() when available.
PowerShell has the -match operator, but for advanced regex work — global matching, named groups, complex replacements — [System.Text.RegularExpressions.Regex] is far more powerful:
$pola = [System.Text.RegularExpressions.Regex]::Match(
"IP server: 10.0.0.42",
"(\d+\.){3}\d+"
)
$pola.ValueFor cryptography, [System.Security.Cryptography] provides built-in hash and encryption functions. An example computing the SHA256 hash of a file:
$sha = [System.Security.Cryptography.SHA256]::Create()
$stream = [System.IO.File]::OpenRead("/etc/hosts")
$hash = $sha.ComputeHash($stream)
$stream.Close()
($hash | ForEach-Object { $_.ToString("x2") }) -join ""A hash is a file's digital fingerprint: two identical files produce exactly the same hash. Verifying download checksums or auditing file integrity are the most common uses of this pattern.
If built-in .NET isn't enough, Add-Type -TypeDefinition injects C# code directly into the session. Once compiled, that code can be called like any other .NET type:
Add-Type -TypeDefinition @"
using System;
public class Kalkulator {
public static int Kali(int a, int b) {
return a * b;
}
}
"@
[Kalkulator]::Kali(6, 7)Add-Type accepts a here-string of C# code, compiles it on the spot, and registers the type in the session. [Kalkulator]::Kali calls the static C# method exactly like a native .NET type. This is useful when the logic requires C# features that are awkward in PowerShell — for example high-performance algorithms or complex data structures.
Tip
Start with built-in .NET types before writing your own C#. Needs that look complex — date parsing, file hashing, JSON manipulation — are often already answered by [System.DateTime], [System.Security.Cryptography], or [System.Text.Json]. Write custom C# only when a built-in solution truly doesn't exist or is too slow.
This episode removes the language's limits: you now call .NET static and instance methods via type literals, know the core namespaces from System.IO to System.Security.Cryptography, create object instances with ::new() and New-Object, automate Excel and Word through COM with disciplined resource release, and add custom logic with Add-Type and inline C# code.
Key takeaways:
[Type]::Method for static; ::new() or New-Object for instances.System.IO, System.Net, System.Security.Cryptography, and others.Marshal.ReleaseComObject inside finally.Add-Type -TypeDefinition injects C# code into the session.With .NET and COM, PowerShell has almost no limits — whatever a Windows application can do, can be done from a script. Episode 18 applies all the foundations you've built to the most important domain in the Windows enterprise world: Active Directory Management — Get-ADUser, New-ADUser, managing groups, and writing directory reports. See you in episode 18!