2015年2月27日金曜日

Use PowerShell to Work with the .NET Framework Classes

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)
}

0 件のコメント:

コメントを投稿