Most PowerShell cmdlets are simply wrappers around underlying .NET libraries. In this series, well take a closer look at how these .NET libraries work and how you can access their functionality directly.
This can be very helpful because cmdlets often expose only a fraction of what the underlying .NET library can do. Additionally, there are many useful .NET libraries that are not exposed by any cmdlet at all.
Best Practice
Cmdlets are PowerShells way of standardizing commands. They provide help, error handling, and serve as a "civilized" wrapper around .NET, making PowerShell code both powerful and concise.
If a cmdlet exists for the task you need, use it. Avoid replacing it with raw .NET code, as this makes your PowerShell script unnecessarily difficult to read.
That said, if no cmdlet is available for the task, using .NET libraries directly is the best alternative.
Path Management
Lets take a practical example to explore the relationship between .NET libraries and cmdlets: managing paths is a common task in many scripts.
Thats why PowerShell includes a cmdlet named Split-Path.
$path = "c:\logs\server12.csv"
Split-Path -Path $path # parent folder
Split-Path -Path $path -Leaf # file name
Split-Path -Path $path -Qualifier # drive letter
# new in PowerShell 7
Split-Path -Path $path -LeafBase # file name without extension
Split-Path -Path $path -Extension # file extension
Initially, the cmdlet could not extract the base file name or file extension. In PowerShell 7, it was enhanced with additional parameters. While this is useful, it affects backward compatibility: if you use the new parameters, your script will no longer run in Windows PowerShell.
Visiting .NET
Like most cmdlets, Split-Path is merely a thin wrapper around an underlying .NET library that performs the actual work:
$path = "c:\logs\server12.csv"
[System.IO.Path]::GetDirectoryName($path) # parent folder
[System.IO.Path]::GetFileName($path) # file name
[System.IO.Path]::GetPathRoot($path) # drive letter
[System.IO.Path]::GetFileNameWithoutExtension($path) # file name without extension
[System.IO.Path]::GetExtension($path) # file extension
By using the underlying .NET library directly, you gain access to all the information, regardless of the PowerShell version you are using. PowerShell 7 simply added parameters to expose additional .NET functionality that had always been there, even in Windows PowerShell.
Quick Start: Accessing (Any) .NET Library
The hardest part of using .NET libraries is knowing their names. Once you know a library's namesuch as System.IO.Path in the example aboveyou can easily discover the methods (commands) it offers:
- In your favorite IDE, enclose the library name in square brackets and add two colons: [System.IO.Path]::. IntelliSense will now show the available properties and methods. You may need to press CTRL+SPACE to invoke IntelliSense.
- Once you have selected a method, execute it without parentheses. This will display the method overloads (its help).
PS C:\> [System.IO.Path]::GetExtension
OverloadDefinitions
-------------------
static string GetExtension(string path)
Here is how to decipher an overload definition:
static string GetExtension(string path)
- Each method call starts with static, indicating that it is implemented directly in the library.
- Next, you see the data type of the return value. GetExtension() returns a string.
- Then comes the method name: GetExtension in this case.
- Inside parentheses, you see the comma-separated list of arguments that the method requires. Each argument is described by two words: first, the data type of the argument, and second, its name or description. For GetExtension, the method requires one argument, which must be a string representing the path you want to examine.
To list all the properties and methods in a .NET library, use Get-Member with the -Static parameter:
PS C:\> [System.Io.Path] | Get-Member -Static
TypeName: System.IO.Path
Name MemberType Definition
---- ---------- ----------
ChangeExtension Method static string ChangeExtension(string path, string extension)
Combine Method static string Combine(Params string[] paths), static string Combine(string path1, string path2, string path3), static string Combine(str...
Equals Method static bool Equals(System.Object objA, System.Object objB)
GetDirectoryName Method static string GetDirectoryName(string path)
GetExtension Method static string GetExtension(string path)
GetFileName Method static string GetFileName(string path)
GetFileNameWithoutExtension Method static string GetFileNameWithoutExtension(string path)
GetFullPath Method static string GetFullPath(string path)
GetInvalidFileNameChars Method static char[] GetInvalidFileNameChars()
GetInvalidPathChars Method static char[] GetInvalidPathChars()
GetPathRoot Method static string GetPathRoot(string path)
GetRandomFileName Method static string GetRandomFileName()
GetTempFileName Method static string GetTempFileName()
GetTempPath Method static string GetTempPath()
HasExtension Method static bool HasExtension(string path)
IsPathRooted Method static bool IsPathRooted(string path)
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, System.Object objB)
AltDirectorySeparatorChar Property static char AltDirectorySeparatorChar {get;}
DirectorySeparatorChar Property static char DirectorySeparatorChar {get;}
InvalidPathChars Property static char[] InvalidPathChars {get;}
PathSeparator Property static char PathSeparator {get;}
VolumeSeparatorChar Property static char VolumeSeparatorChar {get;}
As you see, even the Split-Path cmdlet found in the latest PowerShell version still exposes only a portion of what this .NET library can do. For example, if you need to generate a new filename with a different extensionwhether to create a backup or convert a file typeChangeExtension() can do the heavy lifting:
$path = "c:\logs\server12.csv"
# create a backup file name
[System.Io.Path]::ChangeExtension($path, 'bak')
$path = "c:\music\song1.wav"
# create a new file name for a media converter
[System.Io.Path]::ChangeExtension($path, 'mp3')
Or, if you want to determine the true path separator on the operating system where your PowerShell instance is running, .NET has the answer:
[System.Io.Path]::PathSeparator
[System.Io.Path]::VolumeSeparatorChar
On Windows, the path separator is a backslash, while on Linux, it is a forward slash. This allows you to dynamically construct valid paths in heterogeneous environments. This is how Join-Path works in the background.
Your ultimate PowerShell Cheat Sheet
Unleash the full potential of PowerShell with our handy poster. Whether you're a beginner or a seasoned pro, this cheat sheet is designed to be your go-to resource for the most important and commonly used cmdlets.The poster is available for download and in paper form.
Related links
- ScriptRunner ActionPacks provide ready-to-use PowerShell scripts.
- Try out ScriptRunner here
- ScriptRunner: Book a demo with our product experts