Introduction
Every once in a wile I am working on a tutorial blog post that involves the publishing of a large number of pictures or screenshots. Finding the right sequence of pictures, labeling them appropriately and then adding them to Windows Live Writer can be quite tedious. Fortunately there is PowerShell and the Windows Live Writer API that helps you automating this task. This is what this blog post is about.

Figure 1: Picture series for a how-to clean your pool filter tutorial
Video
The following video shows the script in action.
Windows Live Writer API
The adding of content to Windows Live writer is made possible by the Windows Live Writer API. This API is a 32-bit COM object that is unfortunately not accessible from the 64-bit PowerShell ISE. Please use the 32-bit version of the ISE, if you plan on using this script. You can find more details here.
WLW API COM Wrapper for PowerShell
There was another little problem that I ran into during this experiment. I didn’t know how to cast the COM object in PowerShell to a different COM interface. As a workaround I decided to create a .NET wrapper class for the WLW COM API in Visual Studio 2010 and use this instead of using the COM object directly. Here is the listing of this wrapper class. The complete Visual Studio Project is attached.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace WLWAPIWrapper
{
public class WLW
{
public static void BlogThisImageFileList(string title, string[] imageFilePaths, string comment)
{
ValidateTitle(title);
ValidateComment(comment);
ValidateImageFilePaths(imageFilePaths);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
((WindowsLiveWriterApplicationLib.IWindowsLiveWriterApplication2)myWLW).BlogThisImageFileList(title, imageFilePaths, comment);
}
public static void BlogThisHtml(string title, string html)
{
ValidateTitle(title);
ValidateHtml(html);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
((WindowsLiveWriterApplicationLib.IWindowsLiveWriterApplication2)myWLW).BlogThisHtml(title, html);
}
public static void BlogThisImageFile(string title, string imageFilePath, string comment)
{
ValidateTitle(title);
ValidateComment(comment);
ValidatePath(imageFilePath);
ValidateImageFileExtension(imageFilePath);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.BlogThisImageFile(title, imageFilePath, comment);
}
public static void BlogThisFeedItem(string feedName, string itemTitle, string itemUrl, string itemContents, string feedHomepage, string author, string authorEmail, string publishDate)
{
ValidateTitle(feedName);
ValidateTitle(itemTitle);
ValidateUrl(itemUrl);
ValidateContents(itemContents);
ValidateUrl(feedHomepage);
ValidateAuthor(author);
ValidateEmail(authorEmail);
ValidateDate(publishDate);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.BlogThisFeedItem(feedName, itemTitle, itemUrl, itemContents, feedHomepage, author, authorEmail, publishDate);
}
public static void BlogThisImageUrl(string title, string url, string comment)
{
ValidateTitle(title);
ValidateUrl(url);
ValidateUrl(comment);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.BlogThisImageUrl(title, url, comment);
}
public static void BlogThisLink(string title, string url, string comment)
{
ValidateTitle(title);
ValidateUrl(url);
ValidateUrl(comment);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.BlogThisLink(title, url, comment);
}
public static void BlogThisSnippet(string title, string url, string comment, string snippetContents, bool preserveImages)
{
ValidateTitle(title);
ValidateUrl(url);
ValidateUrl(comment);
ValidateHtml(snippetContents);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.BlogThisSnippet(title, url, comment, snippetContents, preserveImages);
}
public static void NewPost()
{
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.NewPost();
}
public static void OpenPost()
{
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.OpenPost();
}
public static void ShowOptions(string optionsPage)
{
ValidateOptionsPage(optionsPage);
var myWLW = new WindowsLiveWriterApplicationLib.WindowsLiveWriterApplication();
myWLW.ShowOptions(optionsPage);
}
private static void ValidateImageFilePaths(string[] imageFilePaths)
{
if (imageFilePaths == null || imageFilePaths.Length == 0)
{
throw new System.InvalidOperationException("There must be at least one valid image path!");
}
else
{
foreach (var imageFilePath in imageFilePaths)
{
ValidatePath(imageFilePath);
ValidateImageFileExtension(imageFilePath);
}
}
}
private static void ValidatePath(string path)
{
if (String.IsNullOrEmpty(path))
{
throw new System.InvalidOperationException("The path parameter is required!");
}
else
{
if (File.Exists(path) != true)
{
throw new System.InvalidOperationException("The file " + path + " does not exist!");
}
}
}
private static void ValidateImageFileExtension(string path)
{
if (String.IsNullOrEmpty(path))
{
throw new System.InvalidOperationException("The path parameter is required!");
}
else
{
FileInfo fi = new FileInfo(path);
string ext = fi.Extension.ToLower();
if (ext != ".jpg" && ext != ".jpeg" && ext != ".png" && ext != ".gif")
{
throw new System.InvalidOperationException(ext + " is not a valid file extension!");
}
}
}
private static void ValidateTitle(string title)
{
if (String.IsNullOrEmpty(title))
{
throw new System.InvalidOperationException("The title parameter is required!");
}
}
private static void ValidateComment(string comment)
{
if (String.IsNullOrEmpty(comment))
{
throw new System.InvalidOperationException("The comment parameter is required!");
}
}
private static void ValidateHtml(string html)
{
if (String.IsNullOrEmpty(html))
{
throw new System.InvalidOperationException("The html parameter is required!");
}
}
private static void ValidateEmail(string email)
{
if (String.IsNullOrEmpty(email))
{
throw new System.InvalidOperationException("The email parameter is required!");
}
}
private static void ValidateUrl(string url)
{
if (String.IsNullOrEmpty(url))
{
throw new System.InvalidOperationException("The url parameter is required!");
}
}
private static void ValidateAuthor(string author)
{
if (String.IsNullOrEmpty(author))
{
throw new System.InvalidOperationException("The author parameter is required!");
}
}
private static void ValidateContents(string contents)
{
if (String.IsNullOrEmpty(contents))
{
throw new System.InvalidOperationException("The contents parameter is required!");
}
}
private static void ValidateDate(string date)
{
if (String.IsNullOrEmpty(date))
{
throw new System.InvalidOperationException("The date parameter is required!");
}
}
private static void ValidateOptionsPage(string optionsPage)
{
if (String.IsNullOrEmpty(optionsPage))
{
throw new System.InvalidOperationException("The options page parameter is required!");
}
}
}
}
PowerShell script
The PowerShell script is straight forward. Use-Add type to load the wrapper assembly. Get a list of picture files, sort them appropriately and then call the function that starts WLW and adds the pictures to it.
$Images = Get-ChildItem -Path "C:\Users\Klaus\Schreibtisch\BlogPosts\InWork\Installing new Haward DE 4800 filter elements" -Filter *.JPG
$Images = $Images | Sort-Object -Property "Name"
#50 Images is Windows Live Writer cut-off. If you add more than 50 images you don't get a choice between photo album and inline pictures when adding an image list.
$ImagePaths = $Images | Select-Object -First 50 | ForEach-Object { $_.FullName }
$ImagePaths
Add-Type -Path "C:\Users\Klaus\SVN\PS\BlogKebab\WLW\BlogThisImageFileList\WLWAPIWrapper\bin\Debug\WLWAPIWrapper.dll" -PassThru
[WLWAPIWrapper.WLW]::BlogThisImageFileList("Hello World From PowerShell", $ImagePaths , "Just Curious");
Download
The Visual Studio project for the WLW API wrapper and the PowerShell script can be downloaded here: BlogThisImageFileList.zip
Ausblick
The PowerShell script in this article uses only one of the many automation features of Windows Live Writer. Next I will explore the other options like publishing html snippets, image URLs and links. Stay tuned!