Blogging From PowerShell – Retrieving Posts With the MetaWeblog API

Wed, May 3, 2006 3-minute read

One of the most difficult aspects of our name change is that we have thousands of pages (spanning hundreds of posts) that use the keyword, “Monad” instead of “PowerShell.”  For users just starting with PowerShell, that means that the content basically does not exist.  If you search for a solution to “PowerShell Hosting,” you find nothing related to Windows PowerShell.

[Tip: If an internet search for PowerShell help comes up fruitless, try it again using Monad as a keyword.  A vast wealth of PowerShell (when it was called Monad) blogging dates back as far back as September, 2004!]

To solve this, I’m going to edit every single one of my PowerShell-related posts to include the following snippet: “[Edit: Monad has now been renamed to Windows PowerShell.  This script or discussion may require slight adjustments before it applies directly to newer builds.]”

I’m not about to do this by hand, of course.  I used the MetaWeblog API to port the content from the old Monad Team Blog to the new PowerShell blog, and was quite pleased with the results.  I may show that one-off script soon, but wanted to give some more detailed explanation of the underlying principles first.

Ideally, I want an experience like this:

$posts = get-blogPosts <parameters>
foreach($post in $posts)
{
   $post.Description += <PowerShell edit string>
   set-post $post
}

So, the first requirement of that scenario leads us to writing a script that produces “BlogPost Objects” – one for each post on the blog.  Here it is:

##############################################################################
##
## Get-BlogPosts.ps1
##
## Get the posts to a blog that you own, using the MetaWeblog API
## Returns a strongly-structured set of object that represent the
## posts
##
## Example Usage:
##   $endPoint = "http://www.yourblog.com/blogger.aspx"
##   .\get-posts.ps1 $endPoint $null "username" "password" 3 | ft
##
##############################################################################
param([string] $postUrl, [string] $blogid, [string] $username, 
      [string] $password, [int] $numberOfPosts)

## Post template as required by the metaWeblog.getRecentPosts
## call format
$postTemplate = @"
<methodCall>
  <methodName>metaWeblog.getRecentPosts</methodName>
    <params>
      <param>
        <value>$blogid</value>
      </param>
      <param>
        <value>$username</value>
      </param>
      <param>
        <value>$password</value>
      </param>
      <param>
        <value><i4>$numberOfPosts</i4></value>
      </param>
    </params>
</methodCall>
"@

## Perform the actual post to the server, and transform the response to
## XML
$responseContent = 
   (new-object System.Net.WebClient).UploadString($postUrl, $postTemplate)
$results = [xml] $responseContent

## Go through each of the items in the response to pick out the properties
foreach($item in $results.methodResponse.params.param.value.array.data.value)
{
   ## Prepare our synthetic object
   $blogEntry = new-object System.Management.Automation.PSObject

   ## Go through each of the properties in the current post
   ## For each, compare its property name to one that we know.  From there,
   ## convert the property value into as strongly-typed of a representation
   ## we can muster
   foreach($property in $item.struct.member)
   {
      $propertyName = $property.name
      $propertyValue = $property.value

      switch($propertyName)
      {
         ## The date the post was created.  Uses ISO8601, which is not
         ## natively supported in .Net.  Returned as a [DateTime]
         "dateCreated" 
         { 
            $propertyValue = 
               [DateTime]::ParseExact($property.value."dateTime.iso8601", `
                  "yyyyMMddTHH:mm:ss", `
                  [System.Globalization.CultureInfo]::InvariantCulture)
            break
         }
         
         ## Pull the simple description (content of the post)
         "description" { $propertyValue = $property.value.string; break }
         
         ## Pull the title of the post
         "title" { $propertyValue = $property.value.string; break }

         ## Pull the categories of the post.  Returned as an array
         ## of strings
         "categories" 
         {
            $propertyValue = @()
            
            foreach($category in $property.value.array.data.value)
            {
               $propertyValue += @($category.string)
            }
 
            break 
         }

         ## Pull the link to the post, returned as an [URI]
         "link" { $propertyValue = [URI] $property.value.string; break }

         ## And the permalink to the post, returned as an [URI]
         "permalink" { $propertyValue = [URI] $property.value.string; break }

         ## Pull the ID of the post
         "postid" { $propertyValue = $property.value.string; break }
      }

      ## Add the synthetic property     
      $blogEntry | add-member NoteProperty $propertyName $propertyValue
   }

   ## Finally output the object that represents the post
   $blogEntry
}

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]