Use PowerShell to Work with the .NET Framework Classes

Use PowerShell to Work with the .NET Framework Classes

  • Comments 2
  • Likes

 

Summary: Learn how to use Windows PowerShell to work with the .NET Framework classes and assemblies.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I want to be able to find information about services that are related to device drivers but I cannot find a Windows PowerShell cmdlet that provides that information. Is there something in the .NET Framework that can help me?

-- AG

 

Hey, Scripting Guy! AnswerHello AG, Microsoft Scripting Guy Ed Wilson here. One of the really cool things about the TechNet Script Center is the Scripting Guys Script Repository. It has come a long way since it debuted last year. Quarterly updates keep adding new features, such as the ability to select from multiple templates when you upload your script and the ability to go back in and edit the script after it is published. My favorite feature is the ability to upload a picture or even a video file to show and explain what is happening with the script. I decided to create a video to explain the script that is seen at the end of this post.

AG, before I discuss services related to device drivers, we have to first examine .NET Framework assemblies and see whether they are loaded. When it comes to seeing whether a particular .NET Framework assembly is loaded, it is easiest to use the Add-Type Windows PowerShell cmdlet, and try to load the assembly. Nothing will occur if the Add-Type cmdlet tries to load an assembly multiple times, because .NET Framework assemblies only load once. As seen in the code here, I call the Add-Type Windows PowerShell cmdlet three times, and nothing is displayed ... neither a confirmation, nor an error. This is shown here.

PS C:\> Add-Type -AssemblyName System.ServiceProcess
PS C:\> Add-Type -AssemblyName System.ServiceProcess
PS C:\> Add-Type -AssemblyName System.ServiceProcess
PS C:\>

 

Because no confirmation is supplied from the Add-Type cmdlet, I sometimes wonder if the assembly loaded correctly. To check this, I generally put the .NET Framework class name (together with the .NET Framework namespace the class resides in) into a pair of square brackets. This command is seen here.

PS C:\> [System.ServiceProcess.ServiceController]

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    ServiceController                        System.ComponentModel....


PS C:\>

 

Another way to make sure that a .NET Framework class is available is to use the GetAssembly static method from the System.Reflection.Assembly .NET Framework class. The namespace is System.Reflection, and the class name is Assembly. Static methods are always available from the class. The GetAssembly static method requires an input object that is a type. One way to obtain a type is to cast a string into a type. This is seen here, where I store the type inside the $sc variable, and then pass the $sc variable to the GetAssembly method.

PS C:\> $sc = $sc = "System.ServiceProcess.ServiceController" -as [type]
PS C:\> [reflection.assembly]::GetAssembly($sc)

GAC    Version        Location
---    -------        --------
True   v2.0.50727     C:\Windows\assembly\GAC_MSIL\System.ServiceProcess\2.0.0.0_...

 

The GetAssembly method returns the loaded assembly as an instance of the System.Reflection.Assembly class. This means that you can pass it to the Get-Member Windows PowerShell cmdlet and see what methods, properties and events are available. This is seen here.

PS C:\> [reflection.assembly]::GetAssembly($sc) | Get-Member

 

 

   TypeName: System.Reflection.Assembly

 

Name                      MemberType Definition

----                      ---------- ----------

ModuleResolve             Event      System.Reflection.ModuleResolveEventHandler ...

CreateInstance            Method     System.Object CreateInstance(string typeName...

Equals                    Method     bool Equals(System.Object o)

GetCustomAttributes       Method     System.Object[] GetCustomAttributes(bool inh...

GetExportedTypes          Method     type[] GetExportedTypes()

GetFile                   Method     System.IO.FileStream GetFile(string name)

GetFiles                  Method     System.IO.FileStream[] GetFiles(), System.IO...

GetHashCode               Method     int GetHashCode()

GetLoadedModules          Method     System.Reflection.Module[] GetLoadedModules(...

GetManifestResourceInfo   Method     System.Reflection.ManifestResourceInfo GetMa...

GetManifestResourceNames  Method     string[] GetManifestResourceNames()

GetManifestResourceStream Method     System.IO.Stream GetManifestResourceStream(t...

GetModule                 Method     System.Reflection.Module GetModule(string name)

GetModules                Method     System.Reflection.Module[] GetModules(), Sys...

GetName                   Method     System.Reflection.AssemblyName GetName(), Sy...

GetObjectData             Method     System.Void GetObjectData(System.Runtime.Ser...

GetReferencedAssemblies   Method     System.Reflection.AssemblyName[] GetReferenc...

GetSatelliteAssembly      Method     System.Reflection.Assembly GetSatelliteAssem...

GetType                   Method     type GetType(string name), type GetType(stri...

GetTypes                  Method     type[] GetTypes()

IsDefined                 Method     bool IsDefined(type attributeType, bool inhe...

LoadModule                Method     System.Reflection.Module LoadModule(string m...

ToString                  Method     string ToString()

CodeBase                  Property   System.String CodeBase {get;}

EntryPoint                Property   System.Reflection.MethodInfo EntryPoint {get;}

EscapedCodeBase           Property   System.String EscapedCodeBase {get;}

Evidence                  Property   System.Security.Policy.Evidence Evidence {get;}

FullName                  Property   System.String FullName {get;}

GlobalAssemblyCache       Property   System.Boolean GlobalAssemblyCache {get;}

HostContext               Property   System.Int64 HostContext {get;}

ImageRuntimeVersion       Property   System.String ImageRuntimeVersion {get;}

Location                  Property   System.String Location {get;}

ManifestModule            Property   System.Reflection.Module ManifestModule {get;}

ReflectionOnly            Property   System.Boolean ReflectionOnly {get;}

 

It is easy to see the values for the various properties that are shown by the Get-Member cmdlet. All I have to do is to pipeline the object to the Format-List cmdlet as shown here.

PS C:\> $sc = $sc = "System.ServiceProcess.ServiceController" -as [type]

PS C:\> [reflection.assembly]::GetAssembly($sc) | Format-List *

 

 

CodeBase            : file:///C:/Windows/assembly/GAC_MSIL/System.ServiceProcess/2.0

                      .0.0__b03f5f7f11d50a3a/System.ServiceProcess.dll

EscapedCodeBase     : file:///C:/Windows/assembly/GAC_MSIL/System.ServiceProcess/2.0

                      .0.0__b03f5f7f11d50a3a/System.ServiceProcess.dll

FullName            : System.ServiceProcess, Version=2.0.0.0, Culture=neutral, Publi

                      cKeyToken=b03f5f7f11d50a3a

EntryPoint          :

Evidence            : {<System.Security.Policy.Zone version="1">

                      <Zone>MyComputer</Zone>

                      </System.Security.Policy.Zone>

                      , <System.Security.Policy.Url version="1">

                      <Url>file:///C:/Windows/assembly/GAC_MSIL/System.ServiceProces

                      s/2.0.0.0__b03f5f7f11d50a3a/System.ServiceProcess.dll</Url>

                      </System.Security.Policy.Url>

                      , <System.Security.Policy.GacInstalled version="1"/>

                      , <StrongName version="1"

                      Key="002400000480000094000000060200000024000052534131000400000

                      100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C8

                      34C99921EB23BE79AD9D5DCC1DD9AD236132102900B723CF980957FC4E1771

                      08FC607774F29E8320E92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99285

                      D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8A12436518206

                      DC093344D5AD293"

                      Name="System.ServiceProcess"

                      Version="2.0.0.0"/>

                      ...}

ManifestModule      : System.ServiceProcess.dll

ReflectionOnly      : False

Location            : C:\Windows\assembly\GAC_MSIL\System.ServiceProcess\2.0.0.0__b0

                      3f5f7f11d50a3a\System.ServiceProcess.dll

ImageRuntimeVersion : v2.0.50727

GlobalAssemblyCache : True

HostContext         : 0

 

 

 

PS C:\>

 

Most of the time I do not actually need all this information. However, it is useful to see where the information is obtained and to have an idea of what information is available. I decided to use this information, to write the Get-DeviceDriverServices.ps1 script seen here.

Get-DeviceDriverServices.ps1

#Requires -version 2.0
Function Get-DeviceDriverService
{
 Param(
   [string]$computer = "localhost"
 )
 Add-Type -AssemblyName System.ServiceProcess
 [System.ServiceProcess.ServiceController]::GetDevices($computer)
} #end Get-DeviceDriverService

# *** Entry Point to Script ***
$computer = "localhost"
Get-DeviceDriverService -computer $computer |
Select-Object -Property name, displayname, servicetype, status,
  DependentServices, ServicesDependOn |
Out-GridView -Title "Device Driver Services"

 

The Get-DeviceDriverService function follows Windows PowerShell best practices by using an approved verb for its name-Get. The noun for the function name is DeviceDriverService and is not DeviceDriverServices because Windows PowerShell prefers the single version of nouns (example Get-Process). The input parameter, computer, is assigned a default value of localhost  so that the function will operate against the local machine. The Add-Type cmdlet loads the System.ServiceProcess assembly to provide to the static GetDevices ServiceController .NET Framework class. The complete name, System.ServiceProcess.ServiceController is put inside the square brackets followed by two colons to enable calling the static method. The value in the $computer variable is passed as an argument to the method. See yesterday's Hey Scripting Guy! blog for more information about namespaces and static methods.

Function Get-DeviceDriverService
{
 Param(
   [string]$computer = "localhost"
 )
 Add-Type -AssemblyName System.ServiceProcess
 [System.ServiceProcess.ServiceController]::GetDevices($computer)
} #end Get-Devices

 

The entry point to the script assigns a value to the $computer variable, and calls the Get-DeviceDriverService function. The returning ServiceController objects are pipelined to the Select-Object cmdlet to enable selecting the properties to display in the Out-Grid cmdlet. The Out-Grid display pane will receive a title of "Device Driver Services." The entry point code is shown here.

$computer = "localhost"

Get-DeviceDriverService -computer $computer |

Select-Object -Property name, displayname, servicetype, status,

  DependentServices, ServicesDependOn |

Out-GridView -Title "Device Driver Services"

 

When the script runs, the grid seen in the following figure appears.

 

By using the filter feature of the output grid, I can pinpoint just the information I am looking for. Here I choose running driver services that have dependencies, and are KernelDriver service types. This is shown in the following figure.

 

The complete Get-DeviceDriverServices.ps1 script is uploaded to the Scripting Guys Script Repository. I even decided to take advantage of a new feature of the Scripting Guys Script Repository by uploading a video! In the video, I discuss the Get-DeviceDriverServices.ps1 script and demonstrate working with the Out-GridView control. If you use Silverlight to watch the video (instead of downloading and watching offline) remember there is a small multi-directional arrow in the lower-right corner that will let you make the video full-screen and enable you to see the code in the video more easily. The Get-DeviceDriverServices.ps1 script entry on the Scripting Guys Script Repository is seen in the following figure.

 

AG, that is all there is to using the .NET Framework ServiceController class. This concludes .NET Framework week. Join me tomorrow for Quick Hits Friday.

I invite you to follow me on Twitter or Facebook. If you have any questions, send email to me at scripter@microsoft.com or post them on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • It's Pretty Good hint...!

    ThanKs..

  • Is there a way to import an assembly such that the classes it contains are usable without fully qualified namespaces? For instance, I want to compile a C# enum on the fly, but the code uses the DescriptionAttribute. Loading the assembly containing the DescriptionAttribute class doesn't make it available for use unless every use is fully qualified as System.ComponentModel.DescriptionAttribute. That severely limits the code that can be compiled on the fly by Powershell scripts because it's going to be very uncommon for every use of every class to be fully qualified. Is there a way around this limitation? So far I haven't been able to find anything that allows for the use of .NET types (or any others, for that matter) without fully qualifying the class name.