Created
February 14, 2026 17:15
-
-
Save jorgeasaurus/035847545f1f1ddbe9b950315a01e6b2 to your computer and use it in GitHub Desktop.
Using .NET Methods in PowerShell - practical examples you'll actually reuse.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #Requires -Version 7.0 | |
| <# | |
| .SYNOPSIS | |
| Using .NET Methods in PowerShell - practical examples you'll actually reuse. | |
| .DESCRIPTION | |
| Companion script for the blog post. Covers strings, regex, paths, file I/O, | |
| dates, crypto/hashing, parsing/validation, collections, and quality-of-life helpers. | |
| Run the whole file or copy individual sections. Everything targets PowerShell 7+. | |
| #> | |
| # ============================================================================ | |
| # How to call .NET from PowerShell (the 3 patterns) | |
| # ============================================================================ | |
| # 1) Call static methods on a type | |
| [System.Guid]::NewGuid() | |
| [System.Math]::Round(3.14159, 2) | |
| # 2) Create an instance and call instance methods | |
| $sb = [System.Text.StringBuilder]::new() | |
| $sb.Append("hello").Append(" ").Append("world").ToString() | |
| # 3) Use a type accelerator (short alias PowerShell provides) | |
| [datetime]::UtcNow | |
| [regex]::Match("abc123", "\d+").Value | |
| # ============================================================================ | |
| # 1) Strings: faster, cleaner transforms with .NET | |
| # ============================================================================ | |
| # Trim whitespace | |
| $text = " Jorge " | |
| $text.Trim() # "Jorge" | |
| # Case-insensitive comparison | |
| [string]::Equals("A", "a", [System.StringComparison]::OrdinalIgnoreCase) # True | |
| # Null/empty check | |
| [string]::IsNullOrEmpty($text) # False | |
| # Whitespace-only check | |
| [string]::IsNullOrWhiteSpace(" ") # True | |
| # Concatenate without + | |
| [string]::Concat("Hello", " ", "world") | |
| # Join a collection with a delimiter | |
| [string]::Join(", ", @("a", "b", "c")) | |
| # Case-insensitive contains | |
| "Hello".Contains("he", [System.StringComparison]::OrdinalIgnoreCase) # True | |
| # Replace substring | |
| "report-2026".Replace("2026", "2027") | |
| # Starts/ends with comparison rules | |
| "Report.csv".StartsWith("report", [System.StringComparison]::OrdinalIgnoreCase) | |
| "Report.csv".EndsWith(".csv", [System.StringComparison]::OrdinalIgnoreCase) | |
| # Invariant casing for stable comparisons | |
| "i".ToUpperInvariant() | |
| # Split with empty entries removed | |
| "one,,two".Split(@(","), [System.StringSplitOptions]::RemoveEmptyEntries) | |
| # Join with platform-specific newline | |
| [string]::Join([System.Environment]::NewLine, @("a", "b")) | |
| # Format with placeholders | |
| $user = "Jorge" | |
| $count = 42 | |
| [string]::Format("User {0} has {1} items.", $user, $count) | |
| # Build many lines efficiently with StringBuilder | |
| $sb = [System.Text.StringBuilder]::new() | |
| 1..5 | ForEach-Object { [void]$sb.AppendLine("Line $_") } | |
| $sb.ToString() | |
| # ============================================================================ | |
| # 2) Regex: use [regex] for control and readability | |
| # ============================================================================ | |
| # Get all ticket IDs | |
| $text = "Tickets: INC123, INC456, INC789" | |
| [regex]::Matches($text, "INC\d+").Value | |
| # Parse named groups | |
| $log = "user=jorge status=200" | |
| $m = [regex]::Match($log, "user=(?<user>\w+)\s+status=(?<status>\d+)") | |
| $m.Groups["user"].Value | |
| $m.Groups["status"].Value | |
| # Case-insensitive regex match | |
| [regex]::IsMatch("Hello", "^hello$", [System.Text.RegularExpressions.RegexOptions]::IgnoreCase) | |
| # ============================================================================ | |
| # 3) Paths and filenames: stop fighting separators | |
| # ============================================================================ | |
| # Combine paths safely | |
| [System.IO.Path]::Combine($HOME, "logs", "app.log") | |
| # Extract file name and extension | |
| [System.IO.Path]::GetFileName("/tmp/report.csv") # "report.csv" | |
| [System.IO.Path]::GetExtension("/tmp/report.csv") # ".csv" | |
| # Get the per-user app data folder | |
| [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ApplicationData) | |
| # Get temp directory and random name | |
| $tempRoot = [System.IO.Path]::GetTempPath() | |
| $tempName = [System.IO.Path]::GetRandomFileName() | |
| # Change extension without touching the file | |
| [System.IO.Path]::ChangeExtension("/tmp/report.csv", ".json") | |
| # ============================================================================ | |
| # 4) File I/O: predictable encoding, fast reads/writes | |
| # ============================================================================ | |
| # Normalize to a full path | |
| [System.IO.Path]::GetFullPath("./logs/app.log") | |
| # Get the parent directory name | |
| [System.IO.Path]::GetDirectoryName("/tmp/report.csv") | |
| # Create a temp file name | |
| [System.IO.Path]::GetTempFileName() | |
| # Check file/directory existence | |
| [System.IO.File]::Exists("/tmp/report.csv") | |
| [System.IO.Directory]::Exists("/tmp") | |
| # Enumerate subdirectories lazily | |
| [System.IO.Directory]::EnumerateDirectories($HOME) | |
| # Write UTF-8 text explicitly | |
| $path = [System.IO.Path]::Combine($HOME, "demo.txt") | |
| [System.IO.File]::WriteAllText($path, "hello", [System.Text.Encoding]::UTF8) | |
| # Read UTF-8 text explicitly | |
| $content = [System.IO.File]::ReadAllText($path, [System.Text.Encoding]::UTF8) | |
| # Write raw bytes | |
| $bytes = 0..255 | |
| [System.IO.File]::WriteAllBytes($path, $bytes) | |
| # Read raw bytes | |
| $readBytes = [System.IO.File]::ReadAllBytes($path) | |
| $readBytes.Length | |
| # Stream file names without loading all at once (may throw error on .trash or inaccessible dirs) | |
| $root = $HOME | |
| [System.IO.Directory]::EnumerateFiles($root, "*.log", [System.IO.SearchOption]::AllDirectories) | | |
| Select-Object -First 20 | |
| # Read lines lazily (streaming) | |
| [System.IO.File]::ReadLines($path) | Select-Object -First 5 | |
| # Append text without rewriting the file | |
| [System.IO.File]::AppendAllText($path, "more") | |
| # File size via FileInfo | |
| $fileInfo = [System.IO.FileInfo]::new($path) | |
| $fileInfo.Length | |
| # Enumerate files with DirectoryInfo | |
| $dirInfo = [System.IO.DirectoryInfo]::new($HOME) | |
| $dirInfo.EnumerateFiles("*.log") | Select-Object -First 5 | |
| # ============================================================================ | |
| # 5) Dates and time: UTC, ISO 8601, and duration math | |
| # ============================================================================ | |
| # Get current UTC time | |
| [datetime]::UtcNow | |
| # ISO 8601 string | |
| [datetime]::UtcNow.ToString("o") # e.g. 2026-02-13T... | |
| # Parse exact date with invariant culture | |
| [datetime]::ParseExact("2026-02-13", "yyyy-MM-dd", [System.Globalization.CultureInfo]::InvariantCulture) | |
| # Measure elapsed time | |
| $start = [datetime]::UtcNow | |
| Start-Sleep -Milliseconds 250 | |
| $elapsed = [datetime]::UtcNow - $start | |
| $elapsed.TotalMilliseconds | |
| # Use DateTimeOffset for offset-aware timestamps | |
| [System.DateTimeOffset]::UtcNow.ToString("o") | |
| # Convert UTC to local time zone | |
| $localZone = [System.TimeZoneInfo]::Local | |
| [System.TimeZoneInfo]::ConvertTimeFromUtc([datetime]::UtcNow, $localZone) | |
| # Convert Unix epoch seconds to DateTimeOffset | |
| [System.DateTimeOffset]::FromUnixTimeSeconds(1700000000) | |
| # Build a TimeSpan from minutes | |
| [System.TimeSpan]::FromMinutes(5) | |
| # Measure elapsed time with Stopwatch | |
| $sw = [System.Diagnostics.Stopwatch]::StartNew() | |
| Start-Sleep -Milliseconds 120 | |
| $sw.Stop() | |
| $sw.ElapsedMilliseconds | |
| # ============================================================================ | |
| # 6) Hashing and crypto: quick integrity checks | |
| # ============================================================================ | |
| # Open file and compute SHA256 hash | |
| $path = [System.IO.Path]::Combine($HOME, "demo.txt") | |
| $stream = [System.IO.File]::OpenRead($path) | |
| try { | |
| $sha = [System.Security.Cryptography.SHA256]::Create() | |
| $hashBytes = $sha.ComputeHash($stream) | |
| } | |
| finally { | |
| $stream.Dispose() | |
| } | |
| # Convert hash bytes to hex | |
| $hashHex = [System.Convert]::ToHexString($hashBytes).ToLowerInvariant() | |
| $hashHex | |
| # Generate cryptographically strong random bytes | |
| $bytes = [byte[]]::new(32) | |
| [System.Security.Cryptography.RandomNumberGenerator]::Fill($bytes) | |
| # Encode as Base64 for storage or display | |
| [System.Convert]::ToBase64String($bytes) | |
| # Hash a byte array directly (no stream) | |
| $hashBytes2 = [System.Security.Cryptography.SHA256]::HashData( | |
| [System.Text.Encoding]::UTF8.GetBytes("hello") | |
| ) | |
| [System.Convert]::ToHexString($hashBytes2).ToLowerInvariant() | |
| # ============================================================================ | |
| # 7) Parsing and validation helpers | |
| # ============================================================================ | |
| # TryParse for integers | |
| $intValue = 0 | |
| [int]::TryParse("42", [ref]$intValue) | |
| # TryParseExact for dates | |
| $parsedDate = [datetime]::MinValue | |
| [datetime]::TryParseExact( | |
| "2026-02-13", | |
| "yyyy-MM-dd", | |
| [System.Globalization.CultureInfo]::InvariantCulture, | |
| [System.Globalization.DateTimeStyles]::None, | |
| [ref]$parsedDate | |
| ) | |
| # TryParse for GUIDs | |
| $parsedGuid = [guid]::Empty | |
| [guid]::TryParse("5f2a1f7c-3f9a-4a6b-9a2e-1c5c1b2d3e4f", [ref]$parsedGuid) | |
| # TryParse for enums | |
| $day = [System.DayOfWeek]::Sunday | |
| [System.Enum]::TryParse([System.DayOfWeek], "Friday", $true, [ref]$day) | |
| # ============================================================================ | |
| # 8) Small quality-of-life helpers I reuse everywhere | |
| # ============================================================================ | |
| # Create a GUID string | |
| [guid]::NewGuid().ToString() | |
| # Encode and decode Base64 | |
| $text = "hello" | |
| $b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($text)) | |
| $back = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($b64)) | |
| $back | |
| # Compare versions reliably | |
| $v1 = [version]"7.4.1" | |
| $v2 = [version]"7.5.0" | |
| $v2 -gt $v1 | |
| # Platform-specific newline and env var lookup | |
| [System.Environment]::NewLine | |
| [System.Environment]::GetEnvironmentVariable("PATH") | |
| # Empty typed array and LINQ Any | |
| $emptyStrings = [System.Array]::Empty[string]() | |
| [System.Linq.Enumerable]::Any([int[]]@(1, 2, 3)) # True | |
| # Expand environment variables in a string (Windows only, %VAR% syntax is not used on macOS/Linux) | |
| [System.Environment]::ExpandEnvironmentVariables("%TEMP%\demo.txt") | |
| # Read command-line args for the current process | |
| [System.Environment]::GetCommandLineArgs() | |
| # Start a process with arguments and read output | |
| $psi = [System.Diagnostics.ProcessStartInfo]::new( | |
| "pwsh", | |
| "-NoProfile -Command `"Get-Date`"" | |
| ) | |
| $psi.RedirectStandardOutput = $true | |
| $psi.UseShellExecute = $false | |
| $proc = [System.Diagnostics.Process]::Start($psi) | |
| $proc.StandardOutput.ReadToEnd().Trim() | |
| $proc.WaitForExit() | |
| # Use List for ordered data | |
| $list = [System.Collections.Generic.List[string]]::new() | |
| $list.Add("a") | |
| $list.Add("b") | |
| $list | |
| # Use HashSet for fast membership checks | |
| $set = [System.Collections.Generic.HashSet[string]]::new() | |
| $set.Add("a") | |
| $set.Contains("a") | |
| # Use Dictionary with TryGetValue | |
| $dict = [System.Collections.Generic.Dictionary[string, int]]::new() | |
| $dict["a"] = 1 | |
| $value = 0 | |
| $found = $dict.TryGetValue("a", [ref]$value) | |
| # Convert arrays with Array.ConvertAll | |
| $numbers = [int[]]@(1, 2, 3) | |
| $strings = [System.Array]::ConvertAll( | |
| $numbers, | |
| [System.Converter[int, string]]{ param($n) $n.ToString() } | |
| ) | |
| $strings |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment