Reading IIS.NET Blogs with Powershell

Posted: Feb 13, 2007  6 comments

Average Rating

Tags
Download
IIS.NET
PowerShell

Being a member of the IIS team, I often find myself checking blog posts to see what the members of the product team are blogging about.  However, since Powershell came out, I find myself doing more and more work on my scripts. It's a bit annoying to have to jump out of Powershell to go read blog posts.  As such, I've written a few quick scripts to help me read IIS.NET from my pretty blue shell. For those of you who are already familiar with powershell and don't want to read the long blog post, you can download my blog script from the DownloadCENTER: http://www.iis.net/downloads/default.aspx?tabid=34&g=6&i=1387

Setting up your Powershell environment


To start, I've written a few supporting functions in my profile.  These functions help me keep my scripts organized and, since I change my scripts quite often, it helps me to sign them as well.

First off, if you haven't created your own certificate for signing code, please go back and take a look at my first Powershell blog post that give you the details on how to do this. 

Next, we need to add a few things to your Powershell profile.  To open your Powershell profile from within Powershell, type:

PS > notepad $profile

First, I add a function to allow us to easily sign our scripts (assuming you have created a cert to sign them wth):

## Sign a file
##-------------------------------------------
  function global:Sign-Script ( [string] $file )
  {
    $cert = @(Get-ChildItem cert:\CurrentUser\My -codesigning)[0]
    Set-AuthenticodeSignature $file $cert
  }
  set-alias -name sign -value sign-script

The next function is used to help me organize things. I have several scripts for various work environments.  I like to organize them by function. So, I keep my IIS scripts in an "IIS" directory, my common scripts in a "common" directory and so on.  Inside each of my script directories, I keep a "load.ps1" script that I can  use to initialize any of my work environments.  Lastly, I create a Powershell drive that matches the work environment name so I can get to my scripts easily. The function below does all the work for me.

## Create a Drive
##-------------------------------------------
  function global:New-Drive([string]$alias)
  {
    $path = (join-path -path $global:profhome -childpath $alias)
    if( !(Test-Path $path ) ) 
    {
      ## Create the drive's directory if it doesn't exist
      new-item -path $global:profhome -name $alias -type directory
    }
    else
    {
      ## Execute the load script for this drive if one exists
      $loadscript = (join-path -path $path -childpath "load.ps1")
      if( Test-Path  $loadscript)
      {
        $load = &$loadscript
      }
    }
    # Create the drive
    new-Psdrive -name $alias -scope global -Psprovider FileSystem -root $path
  }

Within my profile, I simply call this function and pass in an alias. When the function executes it will create a directory with the alias name, if it doesn't exist already. If the directory does exist, it will check for the load.ps1 file inside that path and execute it. Lastly, it will create powershell drive. I have the following calls added to my profile below:

## Custom PS Drives
##-------------------------------------------
  New-Drive -alias "common" 
  New-Drive -alias "iis" 

Go ahead and save your profile now and type these commands:

PS > Set-ExecutionPolicy Unrestricted
PS > &$profile
PS > Sign $profile
PS > Set-ExecutionPolicy AllSigned

The first command sets Powershell into unrestricted mode. This is because we need to execute the profile script and it hasn't been signed yet.  The next command executes the profile. The third command uses the "sign" function that our profile script loaded. Since our profile is now signed, we can set our execution policy back to AllSigned. AllSigned means that Powershell will execute scripts as long as they are signed.

From this point on, we can make changes to our profile and simply call our sign function again before we close our Powershell instance. The next instance of powershell that is opened will have our changes. 

Creating / Using Blog Functionality


Now that we have our environment set up, lets get to the blogging part.  If you've set up your environment right, you can execute the following command:

PS > cd iis:

This command will put you in the iis scripts directory.  Next, create a new blogs script by typing:

PS > notepad blogs.ps1

You'll be prompted if you want to create the file. Go ahead and say yes.  Next, paste the following into the the notepad and save it:

 

## Sets up all custom feeds from feeds.txt
##---------------------------------------------------
function global:Import-Feed
{
  if( $global:RssFeeds -eq $null ) 
  {
    $global:RssFeeds = @{};
  }
  $RssFeeds.Add( "iisblogs",     "http://blogs.iis.net/rawmainfeed.aspx" );
  $RssFeeds.Add( "iisdownloads", "http://www.iis.net/DownloadCENTER/all/rss.aspx" );
}
Import-Feed ## Call Import-Feed so we are ready to go

## Gets a feed or lists available feeds
##---------------------------------------------------
function global:Get-Feed( [string] $name )
{  
  if( $RssFeeds.ContainsKey( $name ) )
  {
    return $RssFeeds[$name];
  }
  else
  {
    Write-Host "The path requested does not exist";
    Write-Output $RssFeeds;
  }
}

## Gets IIS Blogs
##---------------------------------------------------
function global:Get-Blog([int]$index, [int]$last, [int]$first, [int]$open)
{
  $url = (Get-Feed iisblogs)
  return (Get-RSS $url $index $last $first $open)
}

## Gets a specific blog
##---------------------------------------------------
function global:Get-AuthorBlog([string]$creator)
{
  Get-Blog | Where-Object {$_.creator -eq $creator}
}


## Gets Downloads from IIS
##---------------------------------------------------
function global:Get-Download([int]$index, [int]$last, [int]$first, [int]$open)
{
  $url = (Get-Feed iisdownloads)
  return (Get-RSS $url $index $last $first $open)
}

## Gets a generic RSS Feed
##---------------------------------------------------
function global:Get-RSS([string]$url, [int]$index, [int]$last, [int]$first, [int]$open)
{
  $feed = [xml](new-object System.Net.WebClient).DownloadString($url)
  if($index)
  {
    return $feed.rss.channel.item[$index]
  }
  if($open)
  {
    $ieaddr = $env:programfiles + "\internet explorer\iexplore.exe"
    return &(get-item $ieaddr) $feed.rss.channel.item[$open].link
  }
  if($last)
  {
    return ($feed.rss.channel.item | Select -last $last)
  }
  if($first)
  {
    return ($feed.rss.channel.item | Select -first $first)
  }
  return $feed.rss.channel.item
}

Once you've saved this file, close it.  We need to sign this script and execute it by typing:

PS IIS:> sign blogs.ps1
PS IIS:> ./blogs.ps1

Now lets start reading. 

  • Read all Blogs

PS iis:\> Get-Blog

  • Read the last five blog posts

PS iis:\> Get-Blog -last 5

  • Read the first five blog posts

PS iis:\> Get-Blog -first 5

  • Read the 8th blog post

PS iis:\> Get-Blog -index 8

  • Open the 12th blog post and open in Internet Explorer

PS iis:\> Get-Blog -open 12

  • Read all blog posts by Bill Staples

PS iis:\> Get-AuthorBlog bills

  • Read all items in DownloadCENTER

PS iis:\> Get-Download

  • Get titles of all items in DownloadCENTER

PS iis:\> Get-Download | Select Title

Of course, all the laws of Powershell still apply, so I can still do fun stuff like like listing only the blog titles from my blog.

PS iis:\> Get-AuthorBlog TobinTitus | Select Title

I can do the same witht he raw blog output:

PS iis:\> Get-Blog -last 5 | Select pubDate, Creator, Title

Happy reading.

IIS.NET Blogs in Powershell

Comments

  1. Tobin Titus Blog Photos
    February 13, 2007

    Read about this feature here: http://blogs.iis.net/tobintitus/archive/2007/02/13/reading-iis-net-blogs-with-powershell.asp...

  2. qbernard
    February 13, 2007

    OMG... you really love powershell :)  Great stuff.. maybe you should promote it further "eat ps, drink ps, sleep ps!"   On the other hand, it would nice to have a column for numbering, for now need to count which row is it before you can issue get-blog -index 9, etc.

  3. TobinTitus
    February 13, 2007

    If you think this is bad, you should see the full script I have on my box.  I actually have written a full RSS reader, complete with adding/removing feeds to a list.  I tried to add a numbering column but ran into some really kludgy behavior depending on how you query the data.  I'm going to take another whack at it sometime next week. I have some more powershell scripts specific to IIS coming this weekend.  Stay tuned!

  4. Jeffrey Snover
    February 14, 2007

    Very cool stuff!  I just had 2 points about conventions:

    1) You should use "new" instead of "create" as a verb.

    2) We discourage the use of plurals "drive" vs "drives" (english is so irregular that plurals screw up lots of people especially non-english users).

    > On the other hand, it would nice to have a column for numbering, for now need to count which row is it before you can issue get-blog -index 9, etc.

    You can help make this happen in the next release by filing a bug/feature request.  You can submit it by using the links at: http://www.microsoft.com/technet/scriptcenter/csc/default.mspx

    Cheers!

    Jeffrey Snover [MSFT]

    Windows PowerShell/MMC Architect

    Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell

    Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

  5. TobinTitus
    February 14, 2007

    HOLY COW!  Jeffrey Snover graced my blog!

    Thanks for the style pointers.  I sort skipped the style guide and started playing with features right away. I'll update my blog and scripts accordingly.

  6. Tobin Titus
    February 14, 2007

    Being a member of the IIS team, I often find myself checking blog posts to see what the members of the

Page view counter