Objects: .NET, WMI, and COM

PowerShell is an object-oriented product—all the language features and constructs are based on objects: cmdlets emit objects, variables are objects, and language constructs allow you to manipulate objects. You can use the properties of an object and can call methods an object contains. While some PowerShell users may not make much direct use of this object orientation, PowerShell is able to make use of .NET and WMI objects, both at the command line and in scripts. Like most of PowerShell's features, we could devote an entire book to the subject of objects in PowerShell.

PowerShell is built on the .NET Framework and enables you to access and use most of the classes within the framework. A restriction of PowerShell version 1 is that the asynchronous classes and methods are not supported.

Using .NET objects is pretty easy since much of it happens by default. You can either let PowerShell determine the .NET classes by default—for example, typing LS or DIR in a filesystem drive produces a set of file and directory objects. You can see this by piping the output of a command to the Get-Member cmdlet, as shown here:

PSH [D:\foo]:ls

    Directory: Microsoft.PowerShell.Core\FileSystem::D:\foo


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----        14/10/2007     12:04            bar
-a---        09/09/2007     12:30          3 foo.txt
-a---        14/10/2007     19:42         13 helloworld.ps1
PSH [D:\foo]: dir | Get-Member


   TypeName: System.IO.DirectoryInfo

Name                      MemberType     Definition
----                      ----------     ----------
Create                    Method         System.Void Create(  ), System.Void
Create(DirectorySecurity
CreateObjRef              Method         System.Runtime.Remoting.ObjRef
CreateObjRef(Type requested

... output snipped for brevity

   TypeName: System.IO.FileInfo

Name                      MemberType     Definition
----                      ----------     ----------
AppendText                Method         System.IO.StreamWriter AppendText(  )
CopyTo                    Method         System.IO.FileInfo CopyTo(String dest
Create                    Method         System.IO.FileStream Create(  )
CreateObjRef              Method         System.Runtime.Remoting.ObjRef Create
CreateText                Method         System.IO.StreamWriter CreateText(  )
Decrypt                   Method         System.Void Decrypt(  )
Delete                    Method         System.Void Delete(  )
Encrypt                   Method         System.Void Encrypt(  )
Equals                    Method         System.Boolean Equals(Object obj)
... output snipped for brevity

In the above example, the LS command emitted System.IO.DirectoryInfo and System.IO.FileInfo objects. To many Windows admins not familiar with the .NET, this looks quite complex, but it does become second nature with a bit of practice. For more information on System.IO.DirectoryInfo objects, see http://msdn2.microsoft.com/en-us/library/system.io.directoryinfo.aspx and for more information on System.IO.FileInfo objects, see http://msdn2.microsoft.com/en-us/library/system.io.fileinfo.aspx.

You can also directly create .NET objects. For example, you could use the New-Object cmdlet as shown here to access .NET's random number class System.Random:

PSH [D:\foo]:$rand = New-Object  System.Random
PSH [D:\foo]: $rand.next(  )
92298896
PSH [D:\foo]: $rand.next(  )
1722419986
PSH [D:\foo]: $rand2 = New-Object System.Random
PSH [D:\foo]: $rand2.NextDouble(  )
0.370553521611986
PSH [D:\foo]: $rand2.nextdouble(  )
0.561135980561905

If you want to create random numbers that are between two other numbers (e.g., a random number between 1 and 10, or between 4 and 16), you can specify a bottom and top range in a call to .NEXT( ), as shown here:

PSH [D:\foo]: $rand = New-Object System.Random
PSH [D:\foo]: $rand.next(1,10)
7
PSH [D:\foo]: $rand.next(4,16)
14

WMI objects are created using the Get-WMIObject cmdlet. Like .NET objects, WMI objects have properties and methods you can call. Unlike normal .NET objects, you can access WMI objects remotely. There are a very large number of WMI classes, as shown at http://msdn2.microsoft.com/en-us/library/aa394554.aspx.

PowerShell can also access COM objects, which is useful for accessing legacy applications that expose them. An example of this is using WMI to examine the Vista Firewall:

With PowerShell, you can use the firewall COM object to obtain details of the Windows Firewall. Here's a simple example that shows how to get the Firewall COM object and the related Firewall profile, which you can then manipulate:

PSH [D:\foo]: $fw = new-object -com HNetCfg.FwMgr
PSH [D:\foo]: $profile = $fw.LocalPolicy.CurrentProfile

Once you get this object created, you can examine it and determine your firewall setup as follows:

PSH [D:\foo]:# determine global open ports (NB there aren't any!)
PSH [D:\foo]: $profile.GloballyOpenPorts | ft name, port
PSH [D:\foo]: # determine authorized applications
PSH [D:\foo]: $profile.AuthorizedApplications | ? {$_.Enabled} | ft name

Name
----
localsrv
SMTPServer
Virtual PC 2007
WS_FTP 95
iTunes
Microsoft Office OneNote
Microsoft Office Groove
PSH [D:\foo]: # determine enabled services
PSH [D:\foo]: $profile.Services | ? {$_.Enabled} | ft name
Name
----
File and Printer Sharing
Network Discovery

PSH [D:\foo]: # determine enabled services (ports)
PSH [D:\foo]: $profile.Services | ? {$_.Enabled} | select -expand GloballyOpenPorts
Name : File and Printer Sharing (NB-Session-In)
IpVersion : 2
Protocol : 6
Port : 139
Scope : 1
RemoteAddresses : LocalSubnet
Enabled : True
BuiltIn : True
Name : File and Printer Sharing (SMB-In)
IpVersion : 2
Protocol : 6
Port : 445
Scope : 1
RemoteAddresses : LocalSubnet
Enabled : True
BuiltIn : True
{remainder of output snipped}