Exploring COM with PowerShell

What is COM?

I hope to explain how to use COM object in PowerShell. A COM object is an interface into an application or Windows. For example the Excel COM object will allow you to work with an Excel spreadsheet, or the iTunes COM object will allow you to control iTunes via PowerShell. It’s not always pretty, or easy. If you have a built-in PowerShell command, use it. (For example Export-Csv is easier then using Excel to work with CSV.)

Getting Started

Maybe you don’t know the exact name of the COM object you want to use? Sometimes a quick web search will uncover it. If not, this bit of PowerShell code will list the COM objects available on your machine.

Get-ChildItem HKLM:\Software\Classes -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^\w+\.\w+$' -and (Test-Path -Path "$($_.PSPath)\CLSID") } | Select-Object -ExpandProperty PSChildName

(via PowerShell Magazine)

The list may take a few minutes. I see “iTunes.Application” in there. That’s what I want.

Using the COM Object

I tell PowerShell to create a new object:

$Itunes = New-Object  -ComObject iTunes.Application

To see what we can do with this object, execute the above then type this PowerShell command (gm is the alias for Get-Member):

$Itunes | gm

This tells me the methods and properties supported by this COM object. Browsing through this will reveal more details, if you need it. “$itunes.LibraryPlaylist.Tracks” is all the tracks. And

$itunes.LibraryPlaylist.Tracks[1] | gm

shows you the methods and properties relating to tracks. (I use the “[1]” to make the listing faster. Since tracks is an array of all the tracks in iTunes, this could take a long time to list all the methods and properties, if you have many tracks. Since all tracks have the same member names (like Artist, Year, Name, etc), I’ll just list the members from the first track.)

So for example, if you wanted iTunes to play, you could do:

$Itunes.play()

Or this little script goes through all your tracks and counts the artists in your collection:

$Itunes = New-Object  -ComObject iTunes.Application
# Get a list of artists from tracks
$Artist = @()
foreach ($Track in  $Itunes.LibraryPlaylist.Tracks)
    {
    $Artist += $Track.Artist
    }
# eliminate duplicates in the list
$artist = $artist | sort -Unique 
Write-Host "$($artist.count) artists found in your iTunes collection"

PowerShell script to generate a Rainmeter skin

I recently discovered Rainmeter, a desktop customization tool that lets you use some really nice looking gadgets. I wanted a simple skin to show disk free space.

rainmeterskin

I have five volumes, I could have manually written a custom skin. (Rainmeter skins are INI files.) That would involve setting a measure section for each disk and a in another section define how the output looks. Or I could take the much more time consuming task of writing a PowerShell script to iterate through my disks and write the skin INI file.

Download RainmeterDisksSkin.ZIP

The body of the script:

# Stop on the first error
$ErrorActionPreference = "Stop"

$RainmeterPath = [environment]::getfolderpath("mydocuments") + "\Rainmeter\Skins\"
$SkinName = "Kenward"
$FileName = "disks.ini"

If (-Not (Test-Path $($RainmeterPath + $SkinName))) {
    Set-Location $RainmeterPath
    mkdir $SkinName
    }

$OutFile = $RainmeterPath + $SkinName + "\" + $FileName
$Disks = Get-Volume | where {$_.DriveType -eq "Fixed"} | sort -Property DriveLetter
$Disks

$Header = @"
[Rainmeter]
Update=1000

[Variables]
vFontName=Segoe UI Light
vFontColor=255,255,255,255
vSolidColor=0,0,0,128
vFontSize=14
vStringCase=Lower
"@

$MeterCommon = @"
`n[MeterDriveInfo]
NumOfDecimals=0
FontFace=#vFontName#
FontSize=#vFontSize#
Meter=String
X=0
Y=0
FontColor=#vFontColor#
SolidColor=#vSolidColor#
AntiAlias=1
AutoScale=1
StringCase=#vStringCase#
"@

Out-File -FilePath $Outfile -InputObject $Header

foreach ($Disk in $Disks) {
    Out-File -FilePath $Outfile -Append -InputObject "`n[MeasureFreeDiskSpace$($Disk.DriveLetter)]"
    Out-File -FilePath $Outfile -Append -InputObject "Measure=FreeDiskSpace"
    Out-File -FilePath $Outfile -Append -InputObject "Drive=$($Disk.DriveLetter):"
    Out-File -FilePath $Outfile -Append -InputObject "UpdateDivider=5"
    }

Out-File -FilePath $Outfile -Append -InputObject $MeterCommon

for ($i = 0; $i -le $Disks.count - 1; $i++)
    { 
    if ($i -eq 0) {
        $Output = "MeasureName=MeasureFreeDiskSpace$($Disks[$i].DriveLetter)"
        $TextValue = "text = ""$($Disks[$i].DriveLetter) drive %1B free"
        }
        else {
            $Output = "MeasureName$($i+1)=MeasureFreeDiskSpace$($Disks[$i].DriveLetter)"
            $TextValue += "#crlf#$($Disks[$i].DriveLetter) drive %$($i + 1)B free"
        }
    Out-File -FilePath $Outfile -Append -InputObject $Output
    }

Out-File -FilePath $Outfile -Append -InputObject $($TextValue + '"')

PowerShell and the Registry, a Quick Start

It’s very easy to access the registry in PowerShell. Usually you will want to read or write to the registry. These examples show how.

The registry key in these examples is “HKLM:\SOFTWARE\MyAwesomeKey“.

Suppose I wanted to read the data from a value called “Kenward”, into a variable. I would use this command:

$myvalue = (Get-ItemProperty -Path HKLM:\SOFTWARE\MyAwesomeKey).Kenward

Easy huh?

If you want to write to the registry, it’s also very easy, for example:

Set-ItemProperty -Path HKLM:\SOFTWARE\MyAwesomeKey -Name "Kenward" -Value "somevalue"

PowerShell is smart enough to know that you are writing a string to the registry, so that it automatically makes the value type a string (“REG_SZ”) in the registry.

If you write a number to the registry, like this:

Set-ItemProperty -Path HKLM:\SOFTWARE\MyAwesomeKey -Name "Meaning" -Value 42

It will make the value of type “REG_DWORD”, a 32 bit number.

If for some reason you need to force the value type to be a certain type, you can use the -type parameter of Set-ItemProperty to specify Binary, Dword, ExpandStrind, MultiString, None, Qword (64 bit number), String, or Unknown.

That’s it! Let me know if you have any questions.