When writing a Powershell script, two options are available:
- Call a cmdlet
- Use the .NET Framework Class library
TBH, I think this is a gross over-simplification of what PowerShell is.
First thing worth pointing out is that PowerShell (the API and the powershell.exe
host application) is implemented in .NET in the first place, so by definition everything in PowerShell is "using .NET".
A cmdlet, as an example, is actually a .NET object - take a look at the CmdletInfo object returned by Get-Command
:
PS C:\> (Get-Command Get-Command) |Format-List Name,CommandType,DLL,ImplementingType
Name : Get-Command
CommandType : Cmdlet
DLL : C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856ad36
4e35\System.Management.Automation.dll
ImplementingType : Microsoft.PowerShell.Commands.GetCommandCommand
Have a look at the implementing type Microsoft.PowerShell.Commands.GetCommandCommand
- it's just a regular .NET class - when you issue the command Get-Command
, powershell creates an instance of this class, calls some well-defined methods, that then in turn calls the .NET methods that carry out the actual work.
The entire philosophy behind PowerShell (or Monad, as it was originally called), is that development time is better spent focusing on small self-contained units/functions that do one thing well (a monad in the original conception), much like the original philosophy behind UNIX utilities.
The idea is that once you have a framework in place for coupling these units together, you can virtually compose any program by way of connecting the simpler units.
The materialization of this idea is the cmdlet - it has some well defined behaviors for input binding that allows you to compose pipelines:
Get-AThing | Filter-TheThing | Write-ToAFile C:\path\to\file\name.ext
In my humble opinion, a pipeline like the above is way more readable than for example:
[System.IO.File]::WriteAllText('C:\path\to\file\name.ext', [System.Linq.Enumerable]::Select([Thing]::EnumerateThings(),{param([thing]$in) $in -eq $someCriteria}))
That's subjective, but what I'm trying to get at, is that you're cheating yourself out of taking advantage of some core functionality that PowerShell provides for free out of the box if you ditch cmdlet's by the way-side
Now, for the actual question: yes, calling a single .NET method directly is faster and incurs less overhead than calling a cmdlet which in turn makes PowerShell run some additional code to eventually just wrap the same .NET method call.
That being said, if you're running a newer version of PowerShell (4.0,5.0,5.1 or 6.0), the overhead will be negligible in many cases.
For example, reading a file from disk is orders of magnitudes slower than resolving a chain of .NET method calls that are already in memory (which is what PowerShell is doing transparently to you), simply because moving electrons from a spinning disk through a disk controller and a memory bus into memory is an operation bounded by the speed of light.
My personal strategy for optimizing for performance is to review the algorithms/routines and data structures I use, long before I start considering cmdlet vs. direct method call.
If I'm doing something stupid that makes my script require 10x as many CPU cycles to calculate then it won't help trying to chase marginal overhead.
If you've reached the limit with that tactic, consider writing your cmdlet's in C# or VB.NET - compiled code is (almost) always faster than interpreted code :-)