If you've used VBScript, KiXtart, or any similar scripting language for Windows administration, at some point you've almost certainly used a Component Object Model (COM) component. Windows is built on COM, and COM objects provide significant functionality for files, folders, WMI, and much more. Scripting without COM would be almost unthinkable.
However, PowerShell isn't built on COM; instead it's built on the .NET Framework. The Framework replaces much of the functionality you may have used COM for, but not all. As a result, there's often still a need to utilize an old COM component. Sometimes, that need might simply be that you know how to do something using a particular COM component and you don't have time to learn an alternative way in PowerShell.
Fortunately, PowerShell includes an adaptation layer that permits you to utilize COM components.
If you've used VBScript, you may be familiar with syntax like this:
Dim objFSO Set objFSO = CreateObject("Scripting.FileSystemObject")
In VBScript this statement instantiates a COM component having the ProgID Scripting.FileSystemObject. When executed, VBScript asks Windows to instantiate the component. In turn, Windows looks up the ProgID in the registry to locate the actual DLL involved, loads the DLL into memory, and plugs it into the script. The variable objFSO represents the running DLL, providing an interface for working with it.
PowerShell can do nearly the same thing:
$fso = new-object -com Scripting.FileSystemObject
Using the same ProgID, PowerShell can instantiate the COM object and assign it to a variable so you can work with it. Notice the -com parameter, which is easy to forget. However, if you don't include it, PowerShell will not be able to "find" the COM object and instantiate it for you.
Once instantiated, using a COM object's properties and methods is straightforward:
$file = $fso.OpenTextFile("C:\file.txt",8,True)
You can even pipe the COM object to the Get-Member cmdlet to see the available properties and methods of a COM object:
PS C:\> $fso | get-member TypeName: System.__ComObject#{2a0b9d10-4b87-11d3-a97a-00104b365c9 Name MemberType Definition ---- ---------- ---------- BuildPath Method string BuildPath (string, string) CopyFile Method void CopyFile (string, string, bool) CopyFolder Method void CopyFolder (string, string, bool CreateFolder Method IFolder CreateFolder (string) CreateTextFile Method ITextStream CreateTextFile (string, b DeleteFile Method void DeleteFile (string, bool) DeleteFolder Method void DeleteFolder (string, bool) DriveExists Method bool DriveExists (string) FileExists Method bool FileExists (string) FolderExists Method bool FolderExists (string) GetAbsolutePathName Method string GetAbsolutePathName (string) GetBaseName Method string GetBaseName (string) GetDrive Method IDrive GetDrive (string) GetDriveName Method string GetDriveName (string) GetExtensionName Method string GetExtensionName (string) GetFile Method IFile GetFile (string) GetFileName Method string GetFileName (string) GetFileVersion Method string GetFileVersion (string) GetFolder Method IFolder GetFolder (string) GetParentFolderName Method string GetParentFolderName (string) GetSpecialFolder Method IFolder GetSpecialFolder (SpecialFold GetStandardStream Method ITextStream GetStandardStream (Standa GetTempName Method string GetTempName () MoveFile Method void MoveFile (string, string) MoveFolder Method void MoveFolder (string, string) OpenTextFile Method ITextStream OpenTextFile (string, IOM Drives Property IDriveCollection Drives () {get}
However, there's an important caveat here. PowerShell creates this list by looking at the COM object's type library that is either embedded in the DLL or included in a separate TLB file. If PowerShell can't find the type library, then it can't use the COM component. Most COM components come with type libraries, especially the COM components written by Microsoft. However, some COM components don't have a type library, or if they do, the type library isn't properly registered with Windows. In these cases, the COM component won't be usable within PowerShell.
In addition, if a type library is wrong, which happens occasionally, PowerShell may not be able to utilize the entire COM object. For example, the Microsoft-supplied type library for the WshController COM object provides an incorrect spelling for the Execute method. This makes the object difficult to use properly. However, in the case of this particular object, there's little reason to use it inside PowerShell.
Another way you may have used COM in VBScript was with GetObject(), which often connects to an existing object or service. In VBScript, you could do this:
Set objUser = GetObject("WinNT://don-pc/administrator,user")
This example uses the ADSI WinNT provider to retrieve the local administrator user.
GetObject() in PowerShell is a bit more difficult. Unfortunately, PowerShell doesn't have a cmdlet that does exactly this. In fact, PowerShell doesn't even provide a cmdlet for ADSI; instead, as outlined in Chapter 12, you use the [ADSI] type accelerator, which works similarly to GetObject() in VBScript. Had this GetObject() example been for WMI, we could use the Get-Wmiobject cmdlet instead. In many cases, WMI offers an alternative to what you were doing in ADSI, although certainly not always.