Monthly Archive



WMF 5.0 COM applications

One change in WMF 5.0 that I hadn’t got round to testing was the speed up in COM based operations.


COM – Component Object Model – was the Microsoft programming model before .NET.  Its old but still around – the interfaces for Internet Explorer and Office are all COM based for instance.


WMF 5.0 promises faster running for COM based applications.  To test it I tried an old script that opens an Excel spread sheet and populates some columns.

$xl = New-Object -comobject 'Excel.Application'
$xl.visible = $true
$xlbooks =$xl.workbooks
$wkbk = $xlbooks.Add()
$sheet = $wkbk.WorkSheets.Item(1)

## create headers
$sheet.Cells.Item(1,1).FormulaLocal = 'Value'
$sheet.Cells.Item(1,2).FormulaLocal = 'Square'
$sheet.Cells.Item(1,3).FormulaLocal = 'Cube'
$sheet.Cells.Item(1,4).FormulaLocal = 'Delta'

$row = 2

for ($i=1;$i -lt 25; $i++){

$f = $i*$i

$sheet.Cells.Item($row,1).FormulaLocal = $i
$sheet.Cells.Item($row,2).FormulaLocal = $f
$sheet.Cells.Item($row,3).FormulaLocal = $f*$i
$sheet.Cells.Item($row,4).FormulaR1C1Local = '=RC[-1]-RC[-2]'



In the past working with Excel has been glacially slow. So slow that you could watch each individual change.


In WMF 5.0 its much, much faster.


In the past my advice has been to create a CSV file and then import the data from that into Excel. With the much better speed offered by WMF 5.0 I may have to reconsider that and think that working directly with Excel is now a viable proposition.

Create a calendar item

Continuing the occasional look at Outlook automation its time to see how we create a calendar item

function new-calendaritem {            
param (            
$outlook = New-Object -ComObject Outlook.Application            
$folder = get-mailfolders |             
where {$_.Path -like "*calendar*" -and $_.Path -notlike "*birthday*" -and $_.Path -like "*$mailbox*"}            
$calendar = $outlook.Session.GetFolderFromID($folder.EntryID, $folder.StoreID)            
$entry = $calendar.Items.Add(1)            
$entry.Start = $start            
$entry.End = $end            
$entry.Subject = $subject            
$entry.Location = $location            
$entry.Body = $body             


The appropriate calendar is identified – remember I have 4 to choose from. The Add method is used from the calendar items collection and the properties populated.

I always enter dates like this “14 September 2011 11:00” as it removes any problems with culture. In the UK this would be “14/9/2011 11:00” but when entering in this style I have to remember to use the US format “9/14/2011 11:00”

The mailbox parameter helps identify which calendar the entry goes

Controlling Firewall Rules

I decide that for this module I wanted some functions that control specific rule that I could be working with often e.g. Enable/Disable WMI rules and then I want a generic function for everything else.

Lets start with some specifics. If we look at the WMI rules

get-rule | where{$_.Name -like "*wmi*"}

we get this output.

Action    : Allow
Name      : Windows Management Instrumentation (WMI-Out)
Profile   : {Private, Public}
Direction : Outbound
Protocol  : TCP

Action    : Allow
Name      : Windows Management Instrumentation (WMI-In)
Profile   : {Private, Public}
Direction : Inbound
Protocol  : TCP

Action    : Allow
Name      : Windows Management Instrumentation (WMI-Out)
Profile   : {Domain}
Direction : Outbound
Protocol  : TCP

Action    : Allow
Name      : Windows Management Instrumentation (WMI-In)
Profile   : {Domain}
Direction : Inbound
Protocol  : TCP

As they are enabled we’ll start by looking at disabling them.

function disable-wmi {             
param (            
$fw = New-Object -ComObject HNetCfg.FwPolicy2            
switch ($psCmdlet.ParameterSetName) {            
 "Inbound"  {$direction = 1 }            
 "Outbound"  {$direction = 2 }            
 default {Write-Host "Error!!! Should not be here" }            
$fw.Rules | where {$_.Name -like "Windows Management Instrumentation*" -and $_.Direction -eq $direction} |            
foreach {            
 if($domain -and ($_.profiles -eq 1)) {$_.Enabled = $false}             
 if($private -and ($_.profiles -eq 2)) {$_.Enabled = $false}              
 if($public -and ($_.profiles -eq 4)) {$_.Enabled = $false}              
 if($domain -and ($_.profiles -band 1)) {$_.Enabled = $false}             
 if($private -and ($_.profiles -band 2)) {$_.Enabled = $false}              
 if($public -and ($_.profiles -band 4)) {$_.Enabled = $false}              
Disables WMI through firewall

Disables WMI through firewall

disable-wmi -in -domain

disable-wmi -in -domain -pp

disable-wmi -out  -pp


I’ve used parameter sets to distinguish in and outbound rules. The network types are set as switches.

The rules are scanned and depending on the network type and profile the Enabled property is set to $false. I’ve tested the profile as an equals and as a –band to catch the singleton and mixed profile

Firewall rules (OK)

The really important thing about our firewall is the rules that are configured.

function get-rule {             
param ()             
$fw = New-Object -ComObject HNetCfg.FwPolicy2            
$fw.Rules |            
foreach {            
$profiles = @()            
$ruleprofile = $_.Profiles            
@(1,2,4, 1073741824) |             
foreach {            
  if ($_ -band $ruleprofile){$profiles += [ProfileType]($_)}            
 $rule = New-Object -TypeName PSObject -Property @{            
     Name = $_.Name            
     Protocol = [Protocol]($_.Protocol)            
     Direction = [Direction]($_.Direction)            
     Profile = $profiles            
     Action = [Action]($_.Action)            
 $rule.PSTypeNames[0] = "FirewallRule"            
Displays firewall rules

Displays firewall rules.
Properties are:


get-rule | format-table -AutoSize -Wrap

Start with the HNetCfg.FwPolicy2   object. Put the Rules collection onto the pipeline. check each of the possible profiles and add them to the array.

An output object is created with the properties converted from their numeric values to descriptive values using a few more enumerations.

Suggested usage:


get-rule | format-table -AutoSize -Wrap

Windows firewall

I normally leave the Windows firewall enabled in my test environment. It ensures I don’t forget it when testing. My recent session for the TechEd:Australia PowerShell conference involved me disabling various firewall rules on the subject machine to set up part of the demo. I had to use the GUI tools to do this. I'’ve moaned to myself that I needed some PowerShell tools for working with the firewall especially as the netsh syntax has changed in Windows 2008 R2 – the session has prompted me to do something about it.

James O’Neill has written a very nice Configurator module for setting up servers. I’ve borrowed some of his ideas but as I’m just working with the firewall I thought I’d be a bit more verbose in the way I do things.

First off I want to know which network types are enabled on my machine. I need to consider them when working with  firewall rules.

I’m creating these functions as a module so I can define my networks (firewall profiles) in the .psm1 file

## types            
Add-type @"
public enum ProfileType {
 Domain   = 1,
 Private  = 2,
 Public   = 4,
 All      = 1073741824
## functions            
. $psScriptRoot/Get-Profile.ps1

I can use this enum in the function to display the firewall profiles

function get-profile {             
param ()             
$fw = New-Object -ComObject HNetCfg.FwPolicy2            
$fwtypes = $fw.CurrentProfileTypes            
@(1,2,4) |             
foreach {            
 $cpt = New-Object -TypeName PSObject -Property @{            
     Enabled = $false            
     Profile = [ProfileType]($_)             
 $cpt.PSTypeNames[0] = "FirewallProfile"            
 if ($_ -band $fwtypes){$cpt.Enabled = $true}            
Determines active firewall profiles

Determines active firewall profiles.
Possible values are:



The function gets the firewall COM object. For the three network types we create an object that gives the name and that its disabled. We change the object type and then if test if the value and the firewall CurrentProfileTypes property can band. If they do we set the profile to enabled ($true). The object is displayed.

Output looks like this

PS> get-profile | ft -a

Profile Enabled

------- -------

Domain   False

Private    True

Public    True

Outlook Connector & mail folder item count

On my home laptop I use Live Mail to aggregate my hotmail accounts. On my travelling netbook I decided to try the Outlook Connector

This add in enables you to access hotmail accounts from Outlook & because I’m using Outlook 2010 I can have multiple mailboxes open at once.

This leads to some interesting PowerShell opportunities as having multiple mailboxes open means that some of the standard approaches won’t work – most scripts you see assume that you are connecting to an Exchange mailbox and that there is only one of them.

As an example consider getting a list of all of the mail folders and the number of items in each

function get-mailitemcount {            
Add-Type -Assembly Microsoft.Office.Interop.Outlook            
$olFolders = "Microsoft.Office.Interop.Outlook.OlDefaultFolders" -as [type]            
$outlook = New-Object -ComObject Outlook.Application            
foreach ($folder in $outlook.Session.Folders){            
  foreach($mailfolder in $folder.Folders ) {            
    New-Object -TypeName PSObject -Property @{            
      Mailbox = $($folder.Name)            
      Folder = $($mailfolder.Name)            
      ItemCount = $($mailfolder.Items.Count)            
    } | select Mailbox, Folder, ItemCount            

The first two lines add the interop assembly and create an object representing the default folders. If these are used directly all we get is the folders for the default (first) mailbox.

Create an object for the outlook application and iterate through the folders in the session – these are the individual mailboxes.

For each of those create an object and set the properties. The select ensures the object properties display in the order we need.

I used foreach instead of foreach-object so that I could use a variable rather than $_ as it would have confusing with nested foreachs

There is quite a bit to play with here and some very interesting PowerShell issues.

IE history to CSV

Back in April last year I wrote a post about viewing IE history

I had a comment left asking how this could be put into a CSV file

We’ll start by turning the script into an advanced function that outputs an object

function get-iehistory {            
param ()            
$shell = New-Object -ComObject Shell.Application            
$hist = $shell.NameSpace(34)            
$folder = $hist.Self            
$hist.Items() |             
foreach {            
 if ($_.IsFolder) {            
   $siteFolder = $_.GetFolder            
   $siteFolder.Items() |             
   foreach {            
     $site = $_            
     if ($site.IsFolder) {            
        $pageFolder  = $site.GetFolder            
        $pageFolder.Items() |             
        foreach {            
           $visit = New-Object -TypeName PSObject -Property @{            
               Site = $($site.Name)            
               URL = $($pageFolder.GetDetailsOf($_,0))            
               Date = $( $pageFolder.GetDetailsOf($_,2))            

The main changes are to stop writing strings to the output and to create an object to put the data into.

Run the function by dot sourcing the file you have the script in – its easier to do this in ISE Then try these commands


get-iehistory | export-csv iehistory.csv -TypeInformation

Import-Csv iehistory.csv

Windows Updates: remote machines


My main blog is now at but I also maintain as a mirror and in case I want the two to diverge at some point.

My recent posts on accessing Windows updates – especially when testing for available updates have raised a number of comments

One very interesting question is about getting information on the state of updates on remote machines.

We are using COM classes in these functions. It is possible for programmers to access COM objects on remote machines but it isn’t an easy proposition in PowerShell. The best way round this I can think of is to do something like this

get-qadcomputer |
foreach {
invoke-command -filepath c:\scripts\getupdates.ps1 -ComputerName $_.Name


The getupdates script would contain this code

$session = New-Object -ComObject Microsoft.Update.Session            
$searcher = $session.CreateUpdateSearcher()            
$result = $searcher.Search("IsInstalled=0 and Type='Software' and ISHidden=0" )            
if ($result.Updates.Count -gt 0){            
 $result.Updates |             
 select Title, IsHidden, IsDownloaded, IsMandatory,             
 IsUninstallable, RebootRequired, Description            
else {            
 Write-Host " No updates available"            

Alternatively leave it as a function and add a call to the function as the last line of the script. I’ll be returning to this idea in a little while as I want to do some more on automating updates across my test environment

Viewing favourites

I recently copied my favourites between machines which started me thinking about viewing favourites. Like many people I have generated a lot of favourites over the years – do I really need them all. Don’t know because I don’t know what they are.  Its easy to correct that

$favs = New-Object -ComObject Shell.Application            
Get-ChildItem -Path $favs.NameSpace(0x6).Self.Path -Recurse |            
where {-not $_.PSIsContainer} |            
foreach {            
 $fav = New-Object -TypeName PSObject -Property @{            
  Name = $_.BaseName             
 Get-Content -Path $_.FullName | foreach {            
  if ($_.StartsWith("URL=")) {            
   $fav | Add-Member -MemberType NoteProperty -Name URL -Value $_.Replace("URL=","")}            

The script use the Shell COM object to access the favourites special folder. We then iterate through the favourites and get the content of each favourite. These are just text files so we can pick out the URL. An object is created to hold the favourite name and URL and then displayed

Windows Updates: 3 Installing Updates

Now we have discovered the updates we have available we can think about installing them.

function install-update {

$session = New-Object -ComObject Microsoft.Update.Session
$searcher = $session.CreateUpdateSearcher()

$result = $searcher.Search("IsInstalled=0 and Type='Software' and ISHidden=0" )

if ($result.Updates.Count -eq 0) {
Write-Host "No updates to install"
else {
$result.Updates | select Title

$downloads = New-Object -ComObject Microsoft.Update.UpdateColl

foreach ($update in $result.Updates){

$downloader = $session.CreateUpdateDownLoader()
$downloader.Updates = 

$installs = New-Object -ComObject Microsoft.Update.UpdateColl
foreach ($update in $result.
if ($update.

$installer = $session.CreateUpdateInstaller()
$installer.Updates = 
 = $installer.Install()



The function looks for non-hidden software updates that aren’t hidden.  At the moment I want some control over driver updates. If there are updates available they are added to a download collection and then downloaded.

The update collection returned from our original search is automatically updated with the fact the update is now downloaded.

We create an installer, add the updates to it and install.

The function is still a bit rough but it works and better still illustrates how the COM objects work.

Next jobs are to tidy up the functions and extend the functionality to remote machines!