Creating .NET and COM objects

This sample only runs on Windows platforms.

There are software components with .NET Framework and COM interfaces that enable you to perform many system administration tasks. PowerShell lets you use these components, so you aren't limited to the tasks that can be performed by using cmdlets. Many of the cmdlets in the initial release of PowerShell don't work against remote computers. We will demonstrate how to get around this limitation when managing event logs by using the .NET Framework System.Diagnostics.EventLog class directly from PowerShell.

Using New-Object for event log access

The .NET Framework Class Library includes a class named System.Diagnostics.EventLog that can be used to manage event logs. You can create a new instance of a .NET Framework class by using the New-Object cmdlet with the TypeName parameter. For example, the following command creates an event log reference:

New-Object -TypeName System.Diagnostics.EventLog
  Max(K) Retain OverflowAction        Entries Name
  ------ ------ --------------        ------- ----

Although the command has created an instance of the EventLog class, the instance doesn't include any data. that's because we didn't specify a particular event log. How do you get a real event log?

Using constructors with New-Object

To refer to a specific event log, you need to specify the name of the log. New-Object has an ArgumentList parameter. The arguments you pass as values to this parameter are used by a special startup method of the object. The method is called a constructor because it's used to construct the object. For example, to get a reference to the Application log, you specify the string 'Application' as an argument:

New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
Max(K) Retain OverflowAction        Entries Name
------ ------ --------------        ------- ----
16,384      7 OverwriteOlder          2,160 Application

Note

Since most of the .NET classes are contained in the System namespace, PowerShell automatically attempts to find classes you specify in the System namespace if it can't find a match for the typename you specify. This means that you can specify Diagnostics.EventLog instead of System.Diagnostics.EventLog.

Storing Objects in Variables

You might want to store a reference to an object, so you can use it in the current shell. Although PowerShell lets you do a lot of work with pipelines, lessening the need for variables, sometimes storing references to objects in variables makes it more convenient to manipulate those objects.

The output from any valid PowerShell command can be stored in a variable. Variable names always begin with $. If you want to store the Application log reference in a variable named $AppLog, type the name of the variable, followed by an equal sign and then type the command used to create the Application log object:

$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application

If you then type $AppLog, you can see that it contains the Application log:

$AppLog
  Max(K) Retain OverflowAction        Entries Name
  ------ ------ --------------        ------- ----
  16,384      7 OverwriteOlder          2,160 Application

Accessing a remote event log with New-Object

The commands used in the preceding section target the local computer; the Get-EventLog cmdlet can do that. To access the Application log on a remote computer, you must supply both the log name and a computer name (or IP address) as arguments.

$RemoteAppLog = New-Object -TypeName System.Diagnostics.EventLog Application, 192.168.1.81
$RemoteAppLog
  Max(K) Retain OverflowAction        Entries Name
  ------ ------ --------------        ------- ----
     512      7 OverwriteOlder            262 Application

Now that we have a reference to an event log stored in the $RemoteAppLog variable, what tasks can we perform on it?

Clearing an event log with object methods

Objects often have methods that can be called to perform tasks. You can use Get-Member to display the methods associated with an object. The following command and selected output show some the methods of the EventLog class:

$RemoteAppLog | Get-Member -MemberType Method
   TypeName: System.Diagnostics.EventLog

Name                      MemberType Definition
----                      ---------- ----------
...
Clear                     Method     System.Void Clear()
Close                     Method     System.Void Close()
...
GetType                   Method     System.Type GetType()
...
ModifyOverflowPolicy      Method     System.Void ModifyOverflowPolicy(Overfl...
RegisterDisplayName       Method     System.Void RegisterDisplayName(String ...
...
ToString                  Method     System.String ToString()
WriteEntry                Method     System.Void WriteEntry(String message),...
WriteEvent                Method     System.Void WriteEvent(EventInstance in...

The Clear() method can be used to clear the event log. When calling a method, you must always follow the method name by parentheses, even if the method doesn't require arguments. This lets PowerShell distinguish between the method and a potential property with the same name. Type the following to call the Clear method:

$RemoteAppLog.Clear()
$RemoteAppLog
  Max(K) Retain OverflowAction        Entries Name
  ------ ------ --------------        ------- ----
     512      7 OverwriteOlder              0 Application

Notice that the event log was cleared and now has 0 entries instead of 262.

Creating COM objects with New-Object

You can use New-Object to work with Component Object Model (COM) components. Components range from the various libraries included with Windows Script Host (WSH) to ActiveX applications such as Internet Explorer that are installed on most systems.

New-Object uses .NET Framework Runtime-Callable Wrappers to create COM objects, so it has the same limitations that .NET Framework does when calling COM objects. To create a COM object, you need to specify the ComObject parameter with the Programmatic Identifier or ProgId of the COM class you want to use. A complete discussion of the limitations of COM use and determining what ProgIds are available on a system is beyond the scope of this user's guide, but most well-known objects from environments such as WSH can be used within PowerShell.

You can create the WSH objects by specifying these progids: WScript.Shell, WScript.Network, Scripting.Dictionary, and Scripting.FileSystemObject. The following commands create these objects:

New-Object -ComObject WScript.Shell
New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObject

Although most of the functionality of these classes is made available in other ways in Windows PowerShell, a few tasks such as shortcut creation are still easier to do using the WSH classes.

Creating a desktop shortcut with WScript.Shell

One task that can be performed quickly with a COM object is creating a shortcut. Suppose you want to create a shortcut on your desktop that links to the home folder for PowerShell. You first need to create a reference to WScript.Shell, which we will store in a variable named $WshShell:

$WshShell = New-Object -ComObject WScript.Shell

Get-Member works with COM objects, so you can explore the members of the object by typing:

$WshShell | Get-Member
   TypeName: System.__ComObject#{41904400-be18-11d3-a28b-00104bd35090}

Name                     MemberType            Definition
----                     ----------            ----------
AppActivate              Method                bool AppActivate (Variant, Va...
CreateShortcut           Method                IDispatch CreateShortcut (str...
...

Get-Member has an optional InputObject parameter you can use instead of piping to provide input to Get-Member. You would get the same output as shown above if you instead used the command Get-Member -InputObject $WshShell. If you use InputObject, it treats its argument as a single item. This means that if you have several objects in a variable, Get-Member treats them as an array of objects. For example:

$a = 1,2,"three"
Get-Member -InputObject $a
TypeName: System.Object[]
Name               MemberType    Definition
----               ----------    ----------
Count              AliasProperty Count = Length
...

The WScript.Shell CreateShortcut method accepts a single argument, the path to the shortcut file to create. We could type in the full path to the desktop, but there is an easier way. The desktop is normally represented by a folder named Desktop inside the home folder of the current user. Windows PowerShell has a variable $HOME that contains the path to this folder. We can specify the path to the home folder by using this variable, and then add the name of the Desktop folder and the name for the shortcut to create by typing:

$lnk = $WshShell.CreateShortcut("$HOME\Desktop\PSHome.lnk")

When you use something that looks like a variable name inside double-quotes, PowerShell tries to substitute a matching value. If you use single-quotes, PowerShell doesn't try to substitute the variable value. For example, try typing the following commands:

"$HOME\Desktop\PSHome.lnk"
C:\Documents and Settings\aka\Desktop\PSHome.lnk
'$HOME\Desktop\PSHome.lnk'
$HOME\Desktop\PSHome.lnk

We now have a variable named $lnk that contains a new shortcut reference. If you want to see its members, you can pipe it to Get-Member. The output below shows the members we need to use to finish creating our shortcut:

$lnk | Get-Member
TypeName: System.__ComObject#{f935dc23-1cf0-11d0-adb9-00c04fd58a0b}
Name             MemberType   Definition
----             ----------   ----------
...
Save             Method       void Save ()
...
TargetPath       Property     string TargetPath () {get} {set}

We need to specify the TargetPath, which is the application folder for PowerShell, and then save the shortcut by calling the Save method. The PowerShell application folder path is stored in the variable $PSHome, so we can do this by typing:

$lnk.TargetPath = $PSHome
$lnk.Save()

Using Internet Explorer from PowerShell

Many applications, including the Microsoft Office family of applications and Internet Explorer, can be automated by using COM. The following examples illustrate some of the typical techniques and issues involved in working with COM-based applications.

You create an Internet Explorer instance by specifying the Internet Explorer ProgId, InternetExplorer.Application:

$ie = New-Object -ComObject InternetExplorer.Application

This command starts Internet Explorer, but doesn't make it visible. If you type Get-Process, you can see that a process named iexplore is running. In fact, if you exit PowerShell, the process will continue to run. You must reboot the computer or use a tool like Task Manager to end the iexplore process.

Note

COM objects that start as separate processes, commonly called ActiveX executables, may or may not display a user interface window when they start up. If they create a window but don't make it visible, like Internet Explorer, the focus usually moves to the Windows desktop. You must make the window visible to interact with it.

By typing $ie | Get-Member, you can view properties and methods for Internet Explorer. To see the Internet Explorer window, set the Visible property to $true by typing:

$ie.Visible = $true

You can then navigate to a specific Web address using the Navigate method:

$ie.Navigate("https://devblogs.microsoft.com/scripting/")

Using other members of the Internet Explorer object model, it's possible to retrieve text content from the Web page. The following command displays the HTML text in the body of the current Web page:

$ie.Document.Body.InnerText

To close Internet Explorer from within PowerShell, call its Quit() method:

$ie.Quit()

The $ie variable no longer contains a valid reference even though it still appears to be a COM object. If you attempt to use it, PowerShell returns an automation error:

$ie | Get-Member
Get-Member : Exception retrieving the string representation for property "Appli
cation" : "The object invoked has disconnected from its clients. (Exception fro
m HRESULT: 0x80010108 (RPC_E_DISCONNECTED))"
At line:1 char:16
+ $ie | Get-Member <<<<

You can either remove the remaining reference with a command like $ie = $null, or completely remove the variable by typing:

Remove-Variable ie

Note

There is no common standard for whether ActiveX executables exit or continue to run when you remove a reference to one. Depending on circumstances, such as whether the application is visible, whether an edited document is running in it, and even whether PowerShell is still running, the application may or may not exit. For this reason, you should test termination behavior for each ActiveX executable you want to use in PowerShell.

Getting warnings about .NET Framework-wrapped COM objects

In some cases, a COM object might have an associated .NET Framework Runtime-Callable Wrapper (RCW) that's used by New-Object. Since the behavior of the RCW may be different from the behavior of the normal COM object, New-Object has a Strict parameter to warn you about RCW access. If you specify the Strict parameter and then create a COM object that uses an RCW, you get a warning message:

$xl = New-Object -ComObject Excel.Application -Strict
New-Object : The object written to the pipeline is an instance of the type "Mic
rosoft.Office.Interop.Excel.ApplicationClass" from the component's primary interop assembly. If
this type exposes different members than the IDispatch members , scripts written to work with this
object might not work if the primary interop assembly isn't installed. At line:1 char:17 + $xl =
New-Object <<<< -ComObject Excel.Application -Strict

Although the object is still created, you are warned that it isn't a standard COM object.