Tuesday, November 26, 2024
Google search engine
HomeGuest BlogsWorking with .NET as a PowerShell Developer

Working with .NET as a PowerShell Developer

.tdi_3.td-a-rec{text-align:center}.tdi_3 .td-element-style{z-index:-1}.tdi_3.td-a-rec-img{text-align:left}.tdi_3.td-a-rec-img img{margin:0 auto 0 0}@media(max-width:767px){.tdi_3.td-a-rec-img{text-align:center}}

Working directly with .NET is important because as a PowerShell developer you do not want to be limited to the things that have been turned into neat little commands. Being able to directly use these types opens the possibility of using third-party assemblies, such as those on nuget.org:

This article is a small section from the book Mastering Powershell Scripting, Fourth Edition by Chris Dent. This extensively revised edition helps you navigate through PowerShell’s capabilities and includes new chapters on debugging and troubleshooting and creating GUIs (online chapter). 

Mastering PowerShell Scripting: Automate and manage your environment using PowerShell 7.1, 4th Edition

Mastering PowerShell Scripting: Automate and manage your environment using PowerShell 7.1, 4th Edition

$54.99
$44.19

 in stock
11 new from $44.19
6 used from $63.73

Free shipping

Amazon.com

as of August 10, 2023 10:43 pm

It is important to understand that .NET is vast; it is not possible to cover everything about .NET in a single article. This article aims to show how .NET may be used within PowerShell based on the Microsoft Docs references: 

.tdi_2.td-a-rec{text-align:center}.tdi_2 .td-element-style{z-index:-1}.tdi_2.td-a-rec-img{text-align:left}.tdi_2.td-a-rec-img img{margin:0 auto 0 0}@media(max-width:767px){.tdi_2.td-a-rec-img{text-align:center}}

The goal is therefore not to learn everything about .NET, but to learn enough know-how to learn more.

Following are some of the crucial topics that you should be well-versed in to be able to increase your flexibility in PowerShell with .NET

  • Assemblies
  • Types
  • Enumerations
  • Classes
  • Namespaces
  • The using keyword
  • Type accelerators
  • Members
  • Fluent interfaces
  • Reflection in PowerShell

In this article, we will just cover the first six topics till using keywords. The book, however, covers the entire spectrum of concepts along with a lot more to make you proficient in leveraging PowerShell.

Assemblies are the starting point; they contain the types that can be used in PowerShell. 

Assemblies

An assembly is a collection of types and any other supporting resources. .NET objects are implemented within assemblies. An assembly may be static (based on a file) or dynamic (created in memory).

The assembly type load locations can be seen by exploring the Assembly property of the type. For example, the String type is loaded from System.Private.CoreLib.dll in PowerShell 7:

PS> [System.String].Assembly.Location
C:\Program Files\PowerShell\7\System.Private.CoreLib.dll

In PowerShell 7, the assemblies that are loaded by default or those that can be loaded by name are in the $PSHome directory.

You can view the list of currently loaded assemblies in a PowerShell session using the following statement:

[System.AppDomain]::CurrentDomain.GetAssemblies() 

The list can be quite extensive and can grow as different modules (which might depend on other .NET types) are loaded. The first few lines are shown here:

GAC    Version     Location
---    -------     --------
False  v4.0.30319  C:\Program Files\PowerShell\7\System.Private.CoreLib.dll
False  v4.0.30319  C:\Program Files\PowerShell\7\pwsh.dll
False  v4.0.30319  C:\Program Files\PowerShell\7\System.Runtime.dll
False  v4.0.30319  C:\Program Files\PowerShell\7\Microsoft.PowerShell.Co...
False  v4.0.30319  C:\Program Files\PowerShell\7\System.Management.Autom...
False  v4.0.30319  C:\Program Files\PowerShell\7\System.Threading.Thread...
False  v4.0.30319  C:\Program Files\PowerShell\7\System.Runtime.InteropS...
False  v4.0.30319  C:\Program Files\PowerShell\7\System.Threading.dll

You can use the ClassExplorer module from the PowerShell Gallery to simplify the previous command:

Install-Module ClassExplorer
Get-Assembly

Assemblies can be explicitly loaded with the Add-Type command. PowerShell 7 includes the System.Windows.Forms.dll file in the $PSHome folder but will only load it if told to. The DLL is used to write some graphical user interfaces. You can therefore load it using the name alone (instead of a full path to the DLL):

Add-Type -AssemblyName System.Windows.Forms

Once an assembly, and the types it contains, has been loaded into a session it cannot be unloaded without completely restarting the PowerShell session. This might affect an upgrade to an existing module based on a DLL; PowerShell cannot unload the DLL and load a newer version. When a DLL is in use by an application, it is locked; attempting to delete the DLL file would fail.

Much of PowerShell itself is implemented in the System.Management.Automation DLL. You can view details of the DLL using the following statement:

[System.Management.Automation.PowerShell].Assembly 

In this statement, the PowerShell type is used to get information about the System.Management.Automation assembly. 

Any other type in the same assembly may be used to get the same Assembly property. The PowerShell type could be replaced with any other type implemented as part of PowerShell itself:

[System.Management.Automation.PSCredential].Assembly
[System.Management.Automation.PSObject].Assembly 

In Windows PowerShell, assemblies are often loaded from the Global Assembly Cache (GAC). PowerShell 7 (and other .NET Core applications) cannot use the GAC, which is why the GAC property in each of the assemblies in use by PowerShell 7 is False.

About the Global Assembly Cache

In Windows PowerShell, most types exist in DLL files stored in %SystemRoot%\Assembly. This folder stores what is known as the Global Assembly Cache (GAC). The DLL files registered here can be used by any .NET Framework application on the computer. Each DLL may be used by name, rather than an application needing to know the exact path to a DLL. 

You can use the Gac module, in the PowerShell Gallery, to list assemblies. The versions of an assembly in the GAC will vary depending on the installed versions of the .NET Framework (and any other installed components, such as Software Development Kits or SDKs):

PS> Install-Module Gac -Scope CurrentUser
PS> Get-GacAssembly System.Windows.Forms
 
Name                 Version    Culture PublicKeyToken   PrArch
----                 -------    ------- --------------   ------
System.Windows.Forms 2.0.0.0            b77a5c561934e089 MSIL
System.Windows.Forms 1.0.5000.0         b77a5c561934e089 None
System.Windows.Forms 4.0.0.0            b77a5c561934e089 MSIL 

If a specific version is required, you can use the full name of the assembly as it uniquely identifies the assembly:

Add-Type -AssemblyName 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' 

You can use the Gac module to show the FullName value used in the previous code. The values displayed depend on the installed versions of the .NET Framework:

PS> Get-GacAssembly System.Windows.Forms | Select-Object FullName
 
FullName
--------
System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 

An assembly typically contains several different types.

Types

A type is used to represent the generalized functionality of an object. This description is vague, but a .NET type can be used to describe anything; it is hard to be more specific. To use this book as an example, it could have several types, including the following:

  • PowerShellBook
  • TextBook
  • Book

Each of these types describes how an object can behave. The type does not describe how this book came to be, or whether it will do anything (on its own) to help create one.

In PowerShell, types are written between square brackets. The [System.AppDomain] and [System.Management.Automation.PowerShell] statements, used when discussing previous assemblies, are types.

The type of an object can be revealed by the Get-Member command (the output below is truncated):

PS> 1 | Get-Member
 
   TypeName: System.Int32
 
Name        MemberType Definition
----        ---------- ----------
CompareTo   Method     int CompareTo(System.Object value), int ...
Equals      Method     bool Equals(System.Object obj), bool Equ...
GetHashCode Method     int GetHashCode()

You can also use the GetType method, for example, by using the method on a variable:

PS> $variable = 1
PS> $variable.GetType()
 
IsPublic IsSerial Name                       BaseType
-------- -------- ----                       --------
True     True     Int32                      System.ValueType

You can create types using several different keywords, including enum, struct, interface, and class

Enumerations

An enumeration is a specialized type that is used to express a list of constants. Enumerations are used throughout .NET and PowerShell.

PowerShell itself makes use of enumerations for many purposes. For example, the possible values for the $VerbosePreference variable are described in an enumeration:

PS> $VerbosePreference.GetType()
 
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     ActionPreference                         System.Enum

Notice that the BaseType is System.Enum, indicating that this type is an enumeration.

The possible values for an enumeration can be listed in several different ways. The most convenient of these is to use the GetEnumValues() method on the enumeration type:

PS> $VerbosePreference.GetType().GetEnumValues()
 
SilentlyContinue
Stop
Continue
Inquire
Ignore
Suspend
Break

Enumerations are relatively simple types. They contain a list of constants that you can use in your code. A class is more complex.

Classes

A class is a set of instructions that dictates how a specific instance of an object behaves, including how it can be created and what it can do. A class is, in a sense, a recipe.

In the case of this book, a class might include details of authoring, editorial processes, and publication steps. These steps are, hopefully, invisible to anyone reading this book; they are part of the internal implementation of the class. Following these steps will produce an instance of the PowerShellBook object.

Once a class has been compiled, it is used as a type. The members of the class are used to interact with the object.

Classes (and types) are arranged and categorized into namespaces.

Namespaces

A namespace is used to organize types into a hierarchy, grouping types with related functionality together. A namespace can be considered like a folder in a file system.

PowerShell is for the most part implemented in the System.Management.Automation namespace. This namespace has associated documentation:

Similarly, types used to work with the filesystem are grouped together in the System.IO namespace:

For the following given type name, the namespace is everything before the final label. The namespace value is accessible as a property of the type:

PS> [System.IO.File].Namespace
System.IO

In PowerShell, the System namespace is implicit. The System.AppDomain type was used to show which assemblies PowerShell is currently using. This can be shortened to:

[AppDomain]::CurrentDomain.GetAssemblies() 

The same applies to types with longer names, such as System.Management.Automation.PowerShell, which can be shortened to:

[Management.Automation.PowerShell].Assembly

PowerShell automatically searches the System namespace for these types. The using keyword can be used to look up types in longer namespaces.

The using keyword

The using keyword simplifies the use of namespaces and can be used to load assemblies or PowerShell modules. The using keyword was introduced with PowerShell 5.0. 

You can use the using keyword in a script, a module, or the console. In a script, the using keyword can only be preceded by comments.

The using module statement is used to access PowerShell classes created within a PowerShell module. In the context of working with .NET, namespaces and assemblies are of interest.

Summary

Delving into .NET significantly increases the flexibility of PowerShell over using built-in commands and operators. .NET is made up of hundreds of classes and enumerations, many of which can be easily used in PowerShell.

.NET types are arranged in namespaces, grouping types with similar purposes together. For example, the System.Data.SqlClient namespace contains types for connecting to and querying Microsoft SQL Server instances.

The using keyword, introduced with PowerShell 5.1, allows types to be used by name only, instead of the full name that includes the namespace. Learn more from the book Mastering PowerShell Scripting, Fourth Edition by Chris Dent.

About the Author

Chris Dent is an automation specialist with deep expertise in the PowerShell language. Chris is often found answering questions about PowerShell in both the UK and virtual PowerShell user groups. Chris has been developing in PowerShell since 2007 and has released several modules over the years.

.tdi_4.td-a-rec{text-align:center}.tdi_4 .td-element-style{z-index:-1}.tdi_4.td-a-rec-img{text-align:left}.tdi_4.td-a-rec-img img{margin:0 auto 0 0}@media(max-width:767px){.tdi_4.td-a-rec-img{text-align:center}}

RELATED ARTICLES

Most Popular

Recent Comments