Skip to the main content.

Unlocking the Power of PowerShell: Tips for Success

Using .NET Libraries in PowerShell - Libraries and Types

In part 1, we began exploring how cmdlets internally rely on .NET libraries and how you can access these libraries directly. As we discovered, most libraries offer much more functionality than what is exposed by cmdlets.

In this part, we’ll explore the differences between types and libraries, and examine "overloads"—what they are and why they provide you with greater control. As always, we’ll use a practical example that is required in many scripts: mathematical operations and rounding.

 

Libraries and Types

Let’s first clarify the terminology. In part 1, we discussed .NET libraries. However, when you examine code—such as [System.IO.Path]—these libraries appear to be types. So, what are they? Libraries or types?

The answer is: both. In essence, they are classes. Each class can function as a type (for data storage), or as a library (for providing additional commands).

 

Well-Known Types

[int] is a well-known type and represents numbers:


PS C:\> [int]$a = 12.564

PS C:\> $a
13

 

As you can see, the number is stored, and the type ensures that the data is stored in a specific form. In this case, the floating-point number 12.564 was rounded by [int] to a whole number.

[int] can also be viewed as a library and supports the same tricks you saw in part 1, so you can access its properties and methods using a double colon:


PS C:\> [int]::MaxValue
2147483647

PS C:\> [int]::MinValue
-2147483648

 

Its properties, MaxValue and MinValue, conveniently help you look up the value range supported by this type, but the type doesn’t provide much else. It is designed for data storage.

 

More Control with Libraries

Other types cannot store data. Instead, they provide commands (called methods) for a given task. [Math], for example, provides all the sophisticated mathematical methods you may require. The [Math] type acts more like a library of commands. You can use the trick from part 1 to list all the mathematical methods found in this library:


PS C:\> [Math] | Get-Member -Static


   TypeName: System.Math

Name            MemberType Definition                                                                                                                                             
----            ---------- ----------                                                                                                                                             
Abs             Method     static sbyte Abs(sbyte value), static int16 Abs(int16 value), static int Abs(int value), static long Abs(long value), static decimal Abs(decimal val...
Acos            Method     static double Acos(double d)                                                                                                                           
Asin            Method     static double Asin(double d)                                                                                                                           
Atan            Method     static double Atan(double d)                                                                                                                           
Atan2           Method     static double Atan2(double y, double x)                                                                                                                
BigMul          Method     static long BigMul(int a, int b)                                                                                                                       
Ceiling         Method     static decimal Ceiling(decimal d), static double Ceiling(double a)                                                                                     
Cos             Method     static double Cos(double d)                                                                                                                            
Cosh            Method     static double Cosh(double value)                                                                                                                       
DivRem          Method     static int DivRem(int a, int b, [ref] int result), static long DivRem(long a, long b, [ref] long result)                                               
Equals          Method     static bool Equals(System.Object objA, System.Object objB)                                                                                             
Exp             Method     static double Exp(double d)                                                                                                                            
Floor           Method     static decimal Floor(decimal d), static double Floor(double d)                                                                                         
IEEERemainder   Method     static double IEEERemainder(double x, double y)                                                                                                        
Log             Method     static double Log(double a, double newBase), static double Log(double d)                                                                               
Log10           Method     static double Log10(double d)                                                                                                                          
Max             Method     static sbyte Max(sbyte val1, sbyte val2), static byte Max(byte val1, byte val2), static int16 Max(int16 val1, int16 val2), static uint16 Max(uint16 ...
Min             Method     static sbyte Min(sbyte val1, sbyte val2), static byte Min(byte val1, byte val2), static int16 Min(int16 val1, int16 val2), static uint16 Min(uint16 ...
Pow             Method     static double Pow(double x, double y)                                                                                                                  
ReferenceEquals Method     static bool ReferenceEquals(System.Object objA, System.Object objB)                                                                                    
Round           Method     static double Round(double value, int digits), static double Round(double value, System.MidpointRounding mode), static double Round(double value, in...
Sign            Method     static int Sign(sbyte value), static int Sign(int16 value), static int Sign(int value), static int Sign(long value), static int Sign(float value), s...
Sin             Method     static double Sin(double a)                                                                                                                            
Sinh            Method     static double Sinh(double value)                                                                                                                       
Sqrt            Method     static double Sqrt(double d)                                                                                                                           
Tan             Method     static double Tan(double a)                                                                                                                            
Tanh            Method     static double Tanh(double value)                                                                                                                       
Truncate        Method     static decimal Truncate(decimal d), static double Truncate(double d)                                                                                   
E               Property   static double E {get;}                                                                                                                                 
PI              Property   static double PI {get;}
     

 

As always, with this knowledge, you can execute much more granular control. Let’s explore how [Math] can help you round values more effectively:


PS C:\> [int]12.564
13

PS C:\> [Math]::Round(12.564)
13

PS C:\> [Math]::Round(12.564,2)
12,56

Converting a float to an int always rounds to a whole number. After all, that’s what [int] requires, and when you round numbers this way, you are simply (ab)using the nature of [int].

Behind the scenes, [int] is calling a command to round numbers. When you do the same and directly call the rounding method, you initially get the same result (a whole number). However, now you have access to all overloads (alternative rounding methods). By submitting a second argument, you can control the number of digits you want to receive. In the example, the final call rounded to two digits.

 

Understanding Overloads

As in part 1, you can view the overload definitions (alternative method calls) by omitting the parentheses:

  • 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:\> [Math]::Round

OverloadDefinitions                                                                                                                                                               
-------------------                                                                                                                                                               
static double Round(double value, int digits)                                                                                                                                     
static double Round(double value, System.MidpointRounding mode)                                                                                                                   
static double Round(double value, int digits, System.MidpointRounding mode)                                                                                                       
static decimal Round(decimal d)                                                                                                                                                   
static decimal Round(decimal d, int decimals)                                                                                                                                     
static decimal Round(decimal d, System.MidpointRounding mode)                                                                                                                     
static decimal Round(decimal d, int decimals, System.MidpointRounding mode)                                                                                                       
static double Round(double a)  

 

With Round(), you’ll see eight different ways to call the method. Keep in mind that overload definitions are intended for developers, not IT pros, so they often differ only in types. The functionally distinct calls are as follows:


OverloadDefinitions                                                                                                                                                               
-------------------                                                                                                                                                               
static double Round(double value)  
static double Round(double value, int digits)                                                                                                                                     
static double Round(double value, System.MidpointRounding mode)                                                                                                                   
static double Round(double value, int digits, System.MidpointRounding mode)                                                                                                       

 

Here’s how the overload definitions can be deciphered by mere mortals—let’s pick one of the overloads:

static double Round(double value, int digits, System.MidpointRounding mode)

  • static: indicates that the method is directly implemented by the type
  • double: the method Round() returns the data type double (so even if you round with no decimals, you get back a double and not an int)
  • Round: this is the name of the method
  • double value: the first argument, described by two words: the first argument must be a double type and represents the original value that you want to round
  • Comma (“,”): separates the arguments
  • int digits: the second argument, again described by two words: the second argument must be an int type and represents the number of digits you want to receive
  • Comma (“,”): separates the arguments
  • MidpointRounding mode: the third argument, again described by two words: the second argument must be a System.MidpointRounding type and defines where the pivot point for rounding up or down occurs

 

Picking The Best Overload

Overloads exist so you don’t have to use all the possible arguments if you don’t need them. Here, we are using three different overloads, and each additional overload accepts more arguments for more control:


$number = 12.545

[Math]::Round($number)
# -> 13

[Math]::Round($number, 2)
# -> 12.54

[Math]::Round($number, 2, [System.MidpointRounding]::ToEven)
# -> 12.54 

[Math]::Round($number, 2, [System.MidpointRounding]::AwayFromZero)
# -> 12.55 
   

 

Practical Use Case

Let’s assume you want to report the free space on your hard drive(s). Here are a few ways to do it.

Without any knowledge of rounding, this could be your solution:


Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3' |
  ForEach-Object {
    [PSCustomObject]@{
      Drive = $_.DeviceID
      'Size (MB)' = $_.Size/1MB 
      'Free Space (MB)' = $_.FreeSpace/1MB 
      PercentFree = $_.FreeSpace * 100 / $_.Size
    }
  }   

Drive       Size (MB) Free Space (MB)      PercentFree
-----       --------- ---------------      -----------
C:    960550,99609375  55243,57421875 5,75123803352531 

 

By abusing the [int] type, you can round to the whole number:


[Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3' |
  ForEach-Object {
    [PSCustomObject]@{
      Drive = $_.DeviceID
      'Size (MB)' = $_.Size/1MB -as [int]
      'Free Space (MB)' = $_.FreeSpace/1MB -as [int]
      PercentFree = $_.FreeSpace * 100 / $_.Size -as [int]
    }
  } 

Drive Size (MB) Free Space (MB) PercentFree
----- --------- --------------- -----------
C:       960551           55239           6 

With [Math] and Round(), you can specify the number of digits for the result that works best for you:


Get-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3' |
  ForEach-Object {
    [PSCustomObject]@{
      Drive = $_.DeviceID
      'Size (MB)' = [Math]::Round( ($_.Size/1MB), 1)
      'Free Space (MB)' = [Math]::Round( ($_.FreeSpace/1MB), 2)
      PercentFree = [Math]::Round( ($_.FreeSpace * 100 / $_.Size), 1)
    }
  } 

Drive Size (MB) Free Space (MB) PercentFree
----- --------- --------------- -----------
C:       960551        55238,11         5,8 



When you look closely, you’ll see that the total size is reported as a number with no digits, even though we asked for one digit. That’s because Round() always returns numbers, not formatted strings.

If the digit happens to be "0," then PowerShell’s console formatter won’t display it:


PS C:\> 1.0
1

Just for completeness, you could also use the -f operator to round values. Because this operator always returns strings, the digit would now always be visible, even if it happens to be "0."

However, since the values are now strings, this would be useful for reporting purposes only. Anyone receiving the data would have a hard time evaluating the string numbers further:



GGet-CimInstance -ClassName Win32_LogicalDisk -Filter 'DriveType=3' |
  ForEach-Object {
    [PSCustomObject]@{
      Drive = $_.DeviceID
      'Size (MB)' = '{0:n1}' -f ($_.Size/1MB)
      'Free Space (MB)' = '{0:n2}' -f ($_.FreeSpace/1MB)
      PercentFree = '{0:n1}' -f ($_.FreeSpace * 100 / $_.Size)
    }
  } 
Drive Size (MB) Free Space (MB) PercentFree
----- --------- --------------- -----------
C:    960.551,0 55.253,95       5,8  

 

Good2know

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.

PowerShell Poster 2023

Get your poster here!

 

 

Related links 

 

Related posts

4 min read

Bulk Testing PowerShell Scripts with the Tokenizer

In Part 1, we explored the internal PowerShell parser to see how it analyzes code and breaks it down into individual...

3 min read

Mastering PowerShell Tokenization for Efficient Scripting

The internal PowerShell parser processes any code before execution. With full access to this parser, you can analyze...

3 min read

Using .NET Libraries in PowerShell - Functions, Cmdlets and .NET

In part 3, we identified a useful .NET method to display system dialogs and then wrapped it inside a new PowerShell...

About the author: