Summary: Learn how to use Windows PowerShell to work with the .NET Framework classes and assemblies.
Hey, 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
Hello 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
0 comments