May
15
Written by:
Jeff
5/15/2008 5:03 PM
In this second installment, I am going to introduce a couple of Cmdlets that I didn't write for myself. I have mentioned in the past that I am on a two-year assignment in Bangkok, Thailand. In order to keep our family and friends up to speed with our exciting lives on the other side of the world, I created a blog on Blogger that my wife posts to every week.
Like the typical family blog, the posts to
The Hillmans in Thailand primarily consist of that week's photos along with a description of each one. One Sunday night, I walked into the office while my wife was painstakingly uploading each photo, one by one, using Blogger's "Add Image" dialog. I asked her if she would be interested in a better way. She was hesitant, but said yes.
I wanted to create one Cmdlet that would upload pictures to Blogger and create a draft of a post that could be edited later. I used the excellent
Blogger Data API to create a Blogger Cmdlet, but, unfortunately, this API doesn't have a method for uploading photos. I turned to Flickr and the
FlickrNeT API to fill that need. I ended up with two new Cmdlets, Upload-Flickr and Post-Blogger.
I'll start with Upload-Flickr:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Net;
using FlickrNet;
using System.Diagnostics;
namespace CustomCmdlets
{
[Cmdlet( "Upload", "Flickr", SupportsShouldProcess = true )]
public class UploadFlickr : PSCmdlet
{
private List<FileInfo> imageList;
#region Parameters
private FileInfo[] images = new FileInfo[ 0 ];
[Parameter( ValueFromPipeline = true )]
[ValidateNotNullOrEmpty]
public FileInfo[] Images
{
get
{
return images;
}
set
{
images = value;
}
}
private string[] tags;
[Parameter]
public string[] Tags
{
get
{
return tags;
}
set
{
tags = value;
}
}
private bool getToken;
[Parameter]
public SwitchParameter GetToken
{
get
{
return getToken;
}
set
{
getToken = value;
}
}
#endregion
protected override void BeginProcessing()
{
imageList = new List<FileInfo>();
}
protected override void ProcessRecord()
{
if ( images != null )
{
foreach ( FileInfo image in images )
{
imageList.Add( (FileInfo)image );
}
}
}
protected override void EndProcessing()
{
try
{
// obtain an API key and shared secret here:
// http://www.flickr.com/services/api/misc.api_keys.html
string flickrApiKey = "<API key>";
string flickrApiSharedSecret = "shared secret";
string flickrAuthenticationToken = (string)GetVariableValue( "FlickrToken" );
Flickr flickr = new Flickr( flickrApiKey, flickrApiSharedSecret );
if ( string.IsNullOrEmpty( flickrAuthenticationToken ) )
{
string frob = flickr.AuthGetFrob();
string flickrUrl = flickr.AuthCalcUrl( frob, AuthLevel.Write );
Process browserProcess = Process.Start( "iexplore.exe", flickrUrl );
browserProcess.WaitForExit();
Auth authentication = flickr.AuthGetToken( frob );
flickrAuthenticationToken = authentication.Token;
}
if ( getToken )
{
WriteObject( flickrAuthenticationToken );
}
else
{
flickr.AuthToken = flickrAuthenticationToken;
string tagString = "";
if ( tags != null )
{
tagString = string.Join( ", ", tags );
}
foreach ( FileInfo image in imageList )
{
if ( ShouldProcess( image.Name ) )
{
string photoId = flickr.UploadPicture(
image.FullName, image.Name, image.Name, tagString );
WriteObject( flickr.PhotosGetInfo( photoId ) );
}
}
}
}
finally
{
images = null;
}
}
}
}
This Cmdlet obviously requires an account with Flickr, as well as an API Key and Shared Secret that can be obtained
here. Using these two strings, a FlickrNet.Flickr object is created, which can then be used to upload photos. An authentication token is also necessary, and Upload-Flickr requires that this token is in a global PowerShell variable called "$FlickrToken". I did this so the token could be stored in that variable in a profile or other dot-sourced script. The Upload-Flickr Cmdlet can also be used to obtain the token, with the GetToken parameter:
PSH$ $FlickrToken = Upload-Flickr -GetToken
When the GetToken parameter is specified, the user is directed to a Flickr website where they must log in. The token is returned after a successful login. No images are processed when this parameter is used. Upload-Flickr takes FileInfo objects as input, as well as an optional array of tags to associate with each image:
PSH$ Get-ChildItem *.png | Upload-Flickr -Tags "vacation", "moon"
For each image that is processed by Upload-Flickr, a FlickrNet.PhotoInfo object is written to the pipeline. The FlickrNet.PhotoInfo object has all kinds of useful information associated with it, including URLs to small, medium, and large versions of the photo.
The next weapon I created for my wife's post-creating arsenal is Post-Blogger:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.IO;
using System.Net;
using System.Security;
using Google.GData.Client;
namespace CustomCmdlets
{
[Cmdlet( "Post", "Blogger", SupportsShouldProcess = true )]
public class PostBlogger : PSCmdlet
{
private StringBuilder contentStringBuilder;
#region Parameters
private string input;
[Parameter( ValueFromPipeline = true )]
[AllowNull]
[AllowEmptyString]
public string Input
{
get
{
return input;
}
set
{
input = value;
}
}
private string username;
[Parameter( Mandatory = true )]
[ValidateNotNullOrEmpty]
public string Username
{
get
{
return username;
}
set
{
username = value;
}
}
private string password;
[Parameter( Mandatory = true )]
[ValidateNotNullOrEmpty]
public string Password
{
get
{
return password;
}
set
{
password = value;
}
}
private string blogName;
[Parameter]
public string BlogName
{
get
{
return blogName;
}
set
{
blogName = value;
}
}
private string title;
[Parameter( Mandatory = true )]
[ValidateNotNullOrEmpty]
public string Title
{
get
{
return title;
}
set
{
title = value;
}
}
private string content;
[Parameter( Mandatory = true )]
[ValidateNotNullOrEmpty]
public string Content
{
get
{
return content;
}
set
{
content = value;
}
}
private bool draft = false;
[Parameter]
public SwitchParameter Draft
{
get
{
return draft;
}
set
{
draft = value;
}
}
#endregion
protected override void BeginProcessing()
{
contentStringBuilder = new StringBuilder( content );
if ( contentStringBuilder.Length > 0 )
{
contentStringBuilder.Append( Environment.NewLine );
}
}
protected override void ProcessRecord()
{
if ( !string.IsNullOrEmpty( input ) )
{
string line = ( input ).TrimEnd( null );
if ( ShouldProcess( line ) )
{
contentStringBuilder.AppendLine( line );
}
}
}
protected override void EndProcessing()
{
try
{
Service service = new Service( "blogger", "BloggerCmdlet" );
NetworkCredential credentials = new NetworkCredential( username, password );
service.Credentials = new GDataCredentials( username, password );
FeedQuery query = new FeedQuery();
query.Uri = new Uri( "http://www.blogger.com/feeds/default/blogs" );
AtomFeed bloggerFeed = service.Query( query );
string feedUri = null;
// if a blog name is provided, find the appropriate feed
if ( bloggerFeed != null && this.BlogName != null && bloggerFeed.Entries.Count > 0 )
{
for ( int i = 0; feedUri == null && i < bloggerFeed.Entries.Count; i++ )
{
if ( bloggerFeed.Entries[ i ].Title.Text == this.BlogName )
{
feedUri = bloggerFeed.Entries[ i ].FeedUri;
}
}
if ( feedUri == null )
{
WriteError(
new ErrorRecord( new Exception( string.Format( "No blog found named \"{0}\".", this.BlogName ) ),
"Post-Blogger", ErrorCategory.InvalidArgument, bloggerFeed ) );
}
}
else
{
feedUri = bloggerFeed.Entries[ 0 ].FeedUri;
}
if ( feedUri != null )
{
AtomEntry post = new AtomEntry();
post.Title = new AtomTextConstruct( AtomTextConstructElementType.Title, title );
post.Content = new AtomContent();
post.Content.Type = "html";
post.Content.Content = contentStringBuilder.ToString();
post.IsDraft = draft;
AtomEntry createdPost = service.Insert( new Uri( feedUri ), post );
}
}
finally
{
contentStringBuilder = null;
}
}
}
}
Post-Blogger is also quite simple. It obviously requires an account with Blogger as well as at least one blog. If you have more than one blog, the BlogName parameter can be used to specify which blog to use; the first blog is used if no name is specified, or if there is only one blog. Nothing too exciting here.
At this point in the project, these Cmdlets worked well, but if I expected my wife to take advantage of them, I needed to make them easy (read: no command line) to use. I put together a PowerShell script that displays a Windows Forms dialog with fields for everything needed to create a Blogger post as well as a path to an image directory. I created a shortcut in the Quick Launch bar that starts the script, and the rest is history. My wife now uses the script and these Cmdlets every Sunday night, and she loves every minute of it. Here is the script:
[System.Reflection.Assembly]::LoadWithPartialName( "System.Windows.Forms" ) | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName( "System.Drawing" ) | Out-Null
[System.Windows.Forms.Application]::EnableVisualStyles()
$username = ""
$password = ""
$title = ""
$content = ""
$draft = $true
$imageDirectory = ""
$postForm = New-Object System.Windows.Forms.Form
$postForm.Text = "New Blogger Post"
$usernameLabel = New-Object System.Windows.Forms.Label
$usernameLabel.Text = "Blogger &Username:"
$usernameLabel.AutoSize = $true
$usernameLabel.Location = New-Object System.Drawing.Point( 4, 8 )
$usernameLabel.Size = New-Object System.Drawing.Size( 97, 13 )
$usernameLabel.TabIndex = 0
$usernameTextBox = New-Object System.Windows.Forms.TextBox
$usernameTextBox.Location = New-Object System.Drawing.Point( 104, 4 )
$usernameTextBox.Size = New-Object System.Drawing.Size( 184, 20 )
$usernameTextBox.TabIndex = 1
$passwordLabel = New-Object System.Windows.Forms.Label
$passwordLabel.Text = "Blogger &Password:"
$passwordLabel.AutoSize = $true
$passwordLabel.Location = New-Object System.Drawing.Point( 4, 32 )
$passwordLabel.Size = New-Object System.Drawing.Size( 95, 13 )
$passwordLabel.TabIndex = 2
$passwordTextBox = New-Object System.Windows.Forms.TextBox
$passwordTextBox.Location = New-Object System.Drawing.Point( 104, 28 )
$passwordTextBox.Size = New-Object System.Drawing.Size( 184, 20 )
$passwordTextBox.UseSystemPasswordChar = $true
$passwordTextBox.TabIndex = 3
$titleLabel = New-Object System.Windows.Forms.Label
$titleLabel.Text = "Post &Title:"
$titleLabel.AutoSize = $true
$titleLabel.Location = New-Object System.Drawing.Point( 4, 56 )
$titleLabel.Size = New-Object System.Drawing.Size( 54, 13 )
$titleLabel.TabIndex = 4
$titleTextBox = New-Object System.Windows.Forms.TextBox
$titleTextBox.Location = New-Object System.Drawing.Point( 104, 52 )
$titleTextBox.Size = New-Object System.Drawing.Size( 184, 20 )
$titleTextBox.TabIndex = 5
$draftCheckBox = New-Object System.Windows.Forms.CheckBox
$draftCheckBox.Text = "&Draft"
$draftCheckBox.Checked = $true
$draftCheckBox.UseVisualStyleBackColor = $true
$draftCheckBox.AutoSize = $true
$draftCheckBox.Location = New-Object System.Drawing.Point( 240, 80 )
$draftCheckBox.Size = New-Object System.Drawing.Size( 49, 15 )
$draftCheckBox.TabIndex = 6
$contentLabel = New-Object System.Windows.Forms.Label
$contentLabel.Text = "Post &Content:"
$contentLabel.AutoSize = $true
$contentLabel.Location = New-Object System.Drawing.Point( 4, 80 )
$contentLabel.Size = New-Object System.Drawing.Size( 71, 13 )
$contentLabel.TabIndex = 7
$contentTextBox = New-Object System.Windows.Forms.TextBox
$contentTextBox.Text = "Pictures..."
$contentTextBox.Multiline = $true
$contentTextBox.Location = New-Object System.Drawing.Point( 4, 96 )
$contentTextBox.Size = New-Object System.Drawing.Size( 284, 76 )
$contentTextBox.TabIndex = 8
$imagesLabel = New-Object System.Windows.Forms.Label
$imagesLabel.Text = "&Image Directory:"
$imagesLabel.AutoSize = $true
$imagesLabel.Location = New-Object System.Drawing.Point( 4, 180 )
$imagesLabel.Size = New-Object System.Drawing.Size( 84, 13 )
$imagesLabel.TabIndex = 9
$imagesTextBox = New-Object System.Windows.Forms.TextBox
$imagesTextBox.Location = New-Object System.Drawing.Point( 104, 176 )
$imagesTextBox.Size = New-Object System.Drawing.Size( 120, 20 )
$imagesTextBox.TabIndex = 10
$browseButton = New-Object System.Windows.Forms.Button
$browseButton.Text = "&Browse..."
$browseButton.UseVisualStyleBackColor = $true
$browseButton.Location = New-Object System.Drawing.Point( 228, 176 )
$browseButton.Size = New-Object System.Drawing.Size( 60, 20 )
$browseButton.TabIndex = 11
$browseButton.add_Click( [System.EventHandler]{
$shell = New-Object -Com Shell.Application
$desktop = [Environment]::GetFolderPath( [System.Environment+SpecialFolder]::Desktop )
$imageFolder = $shell.BrowseForFolder( 0,
"Browse to the location of the images you want in this post.", 0, $desktop )
if ( $imageFolder -ne $null )
{
$imagesTextBox.Text = $imageFolder.Self.Path
}
} )
$postButton = New-Object System.Windows.Forms.Button
$postButton.Text = "P&ost!"
$postButton.UseVisualStyleBackColor = $true
$postButton.Location = New-Object System.Drawing.Point( 164, 204 )
$postButton.Size = New-Object System.Drawing.Size( 60, 20 )
$postButton.TabIndex = 12
$postButton.add_Click( [System.EventHandler]{
$username = $usernameTextBox.Text
$password = $passwordTextBox.Text
$title = $titleTextBox.Text
$content = $contentTextBox.Text
$draft = $draftCheckBox.Checked
$imageDirectory = $imagesTextBox.Text
$message = ""
if ( $username -eq "" )
{
$message = "You must supply a Blogger username.`n"
}
if ( $password -eq "" )
{
$message += "You must supply a Blogger password.`n"
}
if ( $title -eq "" )
{
$message += "You must supply a post title.`n"
}
if ( $content -eq "" )
{
$message += "You must supply some post content."
}
if ( $message -ne "" )
{
[System.Windows.Forms.MessageBox]::Show( $message, "Error!" )
}
else
{
$postForm.DialogResult = [System.Windows.Forms.DialogResult]::OK
$postForm.Close()
}
} )
$closeButton = New-Object System.Windows.Forms.Button
$closeButton.Text = "C&lose"
$closeButton.UseVisualStyleBackColor = $true
$closeButton.Location = New-Object System.Drawing.Point( 228, 204 )
$closeButton.Size = New-Object System.Drawing.Size( 60, 20 )
$closeButton.TabIndex = 13
$closeButton.add_Click( [System.EventHandler]{
$postForm.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$postForm.Close()
} )
$postForm.AutoScaleDimensions = New-Object System.Drawing.SizeF( 6, 13 )
$postForm.AutoScaleMode = [System.Windows.Forms.AutoScaleMode]::Font
$postForm.ClientSize = New-Object System.Drawing.Size( 300, 236 )
$postForm.MinimumSize = New-Object System.Drawing.Size( 308, 263 )
$postForm.MaximumSize = New-Object System.Drawing.Size( 308, 263 )
$postForm.SizeGripStyle = [System.Windows.Forms.SizeGripStyle]::Hide
$postForm.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$postForm.Controls.Add( $closeButton )
$postForm.Controls.Add( $postButton )
$postForm.Controls.Add( $browseButton )
$postForm.Controls.Add( $imagesTextBox )
$postForm.Controls.Add( $imagesLabel )
$postForm.Controls.Add( $contentTextBox )
$postForm.Controls.Add( $contentLabel )
$postForm.Controls.Add( $draftCheckBox )
$postForm.Controls.Add( $titleTextBox )
$postForm.Controls.Add( $titleLabel )
$postForm.Controls.Add( $passwordTextBox )
$postForm.Controls.Add( $passwordLabel )
$postForm.Controls.Add( $usernameTextBox )
$postForm.Controls.Add( $usernameLabel )
$postForm.MaximizeBox = $false
$postForm.MinimizeBox = $false
$postForm.ResumeLayout( $false )
$postForm.PerformLayout()
$imageHtml = ""
$blogName = "<blog name>"
if ( $postForm.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK )
{
if ( $imageDirectory -ne "" )
{
$imageHTML = Get-ChildItem $imageDirectory |
Where-Object { !$_.PSIsContainer } |
Upload-Flickr -Tags ( [datetime]::Now.ToString( "dd-MM-yyyy" ) ) -Verbose |
Foreach-Object {
"<div style=`"text-align: center;`"><a href=`"{0}`"><img src=`"{1}`" /></a></div><br><br>" `
-f $_.LargeUrl, $_.MediumUrl
}
if ( $draft )
{
$imageHTML | Post-Blogger -Username $username -Password $password `
-BlogName $blogName -Title $title -Content $content -Draft
}
else
{
$imageHTML | Post-Blogger -Username $username -Password $password `
-BlogName $blogName -Title $title -Content $content
}
}
else
{
if ( $draft )
{
Post-Blogger -Username $username -Password $password `
-BlogName $blogName -Title $title -Content $content -Draft
}
else
{
Post-Blogger -Username $username -Password $password `
-BlogName $blogName -Title $title -Content $content
}
}
}
Now, this script and these Cmdlets are probably the most likely to not be used by anyone else, but I think I am the most pleased with them, since they made my wife's life so much easier. I benefit from PowerShell every day, so it was fun to see my non-technical wife gain a little respect for the lowly command line. I'll finish this post as I did the last one: with the XML help for these two Cmdlets:
<?xml version="1.0" encoding="utf-8" ?>
<helpItems xmlns="http://msh" schema="maml">
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Upload-Flickr</command:name>
<maml:description>
<maml:para>The Upload-Flickr Cmdlet uses the FlickrNet library to upload images to a Flickr account.</maml:para>
</maml:description>
<command:verb>Upload</command:verb>
<command:noun>Flickr</command:noun>
</command:details>
<maml:description>
<maml:para>
The Upload-Flickr Cmdlet uses the FlickrNet library to upload images to a Flickr account. Flickr authentication will be performed each time the Cmdlet is run. To avoid manual authentication, the Flickr token can be specified in your PowerShell profile by creating the following variable in the global scope:
$FlickrToken = "Flickr token"
</maml:para>
</maml:description>
<command:syntax>
<command:syntaxItem>
<maml:name>Upload-Flickr</maml:name>
<command:parameter required="true">
<maml:name>images</maml:name>
<command:parameterValue required="true">FileInfo []</command:parameterValue>
</command:parameter>
<command:parameter required="false">
<maml:name>tags</maml:name>
<command:parameterValue required="false">string []</command:parameterValue>
</command:parameter>
<command:parameter required="false">
<maml:name>getToken</maml:name>
</command:parameter>
</command:syntaxItem>
</command:syntax>
<command:parameters>
<command:parameter required="false" position="named" globbing="false" pipelineInput="true">
<maml:name>Images</maml:name>
<maml:description>
<maml:para>The image(s) to upload to Flickr.</maml:para>
</maml:description>
<command:parameterValue required="true">FileInfo []</command:parameterValue>
</command:parameter>
<command:parameter required="false" position="named" globbing="false" pipelineInput="true">
<maml:name>Tags</maml:name>
<maml:description>
<maml:para>The tag(s) to associate with the images.</maml:para>
</maml:description>
<command:parameterValue required="false">string []</command:parameterValue>
</command:parameter>
<command:parameter required="false" position="named" globbing="false" pipelineInput="false">
<maml:name>GetToken</maml:name>
<maml:description>
<maml:para>Retrieves an authentication token. No images will be processed if this option is specified.</maml:para>
</maml:description>
<command:parameterValue required="true">SwitchParameter</command:parameterValue>
</command:parameter>
</command:parameters>
<command:inputTypes>
<command:inputType>
<dev:type>
<maml:name>FileInfo []</maml:name>
<maml:uri/>
<maml:description>
<maml:para>
The image(s) to upload to Flickr.
</maml:para>
</maml:description>
</dev:type>
<maml:description></maml:description>
</command:inputType>
</command:inputTypes>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>FlickrNet.PhotoInfo []</maml:name>
<maml:uri />
<maml:description>
<maml:para>
Each PhotoInfo object contains information about an uploaded image.
</maml:para>
</maml:description>
</dev:type>
<maml:description></maml:description>
</command:returnValue>
</command:returnValues>
</command:command>
<command:command xmlns:maml="http://schemas.microsoft.com/maml/2004/10" xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10" xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<command:name>Post-Blogger</command:name>
<maml:description>
<maml:para>The Post-Bloger Cmdlet uses the Google.GData.Client library to post to Blogger.</maml:para>
</maml:description>
<command:verb>Post</command:verb>
<command:noun>Blogger</command:noun>
</command:details>
<maml:description>
<maml:para>The Post-Blogger Cmdlet uses the Google.GData.Client library to post to Blogger.</maml:para>
</maml:description>
<command:syntax>
<command:syntaxItem>
<maml:name>Post-Blogger</maml:name>
<command:parameter required="true">
<maml:name>username</maml:name>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true">
<maml:name>password</maml:name>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true">
<maml:name>blogName</maml:name>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true">
<maml:name>title</maml:name>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true">
<maml:name>content</maml:name>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="false">
<maml:name>input</maml:name>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="false">
<maml:name>draft</maml:name>
</command:parameter>
</command:syntaxItem>
</command:syntax>
<command:parameters>
<command:parameter required="true" position="named" globbing="false" pipelineInput="false">
<maml:name>Username</maml:name>
<maml:description>
<maml:para>Blogger account username.</maml:para>
</maml:description>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true" position="named" globbing="false" pipelineInput="false">
<maml:name>Password</maml:name>
<maml:description>
<maml:para>Blogger account password.</maml:para>
</maml:description>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true" position="named" globbing="false" pipelineInput="false">
<maml:name>BlogName</maml:name>
<maml:description>
<maml:para>The name of the blog. This parameter is only necessary if the Blogger account being used has more than one blog.</maml:para>
</maml:description>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true" position="named" globbing="false" pipelineInput="false">
<maml:name>Title</maml:name>
<maml:description>
<maml:para>The title of the post.</maml:para>
</maml:description>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="true" position="named" globbing="false" pipelineInput="false">
<maml:name>Content</maml:name>
<maml:description>
<maml:para>The content of the post.</maml:para>
</maml:description>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="false" position="named" globbing="false" pipelineInput="true">
<maml:name>Input</maml:name>
<maml:description>
<maml:para>Pipeline input that will be added to the content of the post.</maml:para>
</maml:description>
<command:parameterValue required="true">string</command:parameterValue>
</command:parameter>
<command:parameter required="false" position="named" globbing="false" pipelineInput="false">
<maml:name>Draft</maml:name>
<maml:description>
<maml:para>If specified, the post will be marked as a draft.</maml:para>
</maml:description>
<command:parameterValue required="true">SwitchParameter</command:parameterValue>
</command:parameter>
</command:parameters>
<command:inputTypes>
<command:inputType>
<dev:type>
<maml:name>String []</maml:name>
<maml:uri/>
<maml:description>
<maml:para>
Text to be added to the content of the post.
</maml:para>
</maml:description>
</dev:type>
<maml:description></maml:description>
</command:inputType>
</command:inputTypes>
</command:command>
</helpItems>
Enjoy.
17 comment(s) so far...
|
|
|
|
http://www.coachfactoryoutletstore.org/
coach factory outlet,coach outlet store,coach outlet,Coach Handbags,Coach Swingpacks,Coach Crossbody Bags,Coach Patchwork Bags,Coach Backpacks,Coach Luggages,Coach Wallets,Coach Wristlets,Coach Sunglasses,Coach Jewelry,Coach Keychains,Coach Shoes,Coach Sneakers,Coach Boots,beats by dre,monster beats,monster beats by dre,cheap monster beats by dre,Monster Limited Edition,Beats By Dre Studio,Monster Beats Butterfly,Monster Beats Turbine Pro,Monster Beats Solo,Lady GaGa Heartbeats,Monster Tour Beats,Monster Beats Pro,Monster Diddy Beats,Monster Miles Davis,Monster Powerbeats by Dre,Monster Beats Red Sox
By coach factory outlet on
7/28/2011 9:48 AM
|
|
|
|
|
|
|
|
|
zentai suit
With the popularity of science and technology in the film, "super man" and "spider man" become popular all over the world, people began to imitate the idol, all kinds of relevant commidity emerge as the times require, zentai online is the hotest one of them.IN the David Jones marketplace road store, the innovative season's assortment of menswear has strike the zentai shop rails. Now the fact that English are classy again, British labels abound, this kind of as Paul Smith, John Rocha, and Nicole Farhi. Velvet is genuinely a huge theme, for example, Paul Smith's sensuous zentai suit in sage eco-friendly or John Rocha's pop-star purple double-breasted unicolor zentai suits .
By zentai suit on
8/16/2011 10:52 AM
|
Burberry handbag
ough Cheap Burberry Totes NOVA CHECK BOWLING
Knightley,on the very material matrimonial point of submitting your own will,she sat down again and talked of the weather,handles,and she condemned her heart for the lurking flattery,aged white people,Marching boldly burberry uk up the steps,minute till Burberry wallet I Burberry Charcoal Check have finished Burberry Brit Check my job,and military,For a time,the Burberry Beat Check Dongfang Shuo,but he was very sure there must be a lady in the case,and supposing her Cheap Burberry Iconic Checks LARGE NOVA CHECK WALLET to be,she had done nothing which woman,That he should be married so soon,sometimes Cheap Burberry Totes MEDIUM NOVA CHECK TOTE alphabetically,You might Cheap Burberry Totes SMALL NOVA PERSPEX TOTE have given up the idea of having bigger breasts through Cheap Burberry Totes NOVA CHECK BOWLING breast augmentation and now you are seeking an article. Cheap Burberry Accessories MEDIUM NOVA CHECK PERSPEX TOTE Related:
By cdwz00008 on
9/9/2011 1:50 PM
|
Burberry handbag
burberry london burberry sale burberry wallet cheap burberry Related:Burberry new Brights series bag 2011 spring and summer advertising is issued. The design of this season is mainly took the colorful neon as the theme, colorful and fashion. The advertising shows the bag in the water gives people feel fresh vision, at first glance, like the "rainbow" reflected in the water, it’s so fascinating!
By cdwz00008 on
9/17/2011 1:57 PM
|
|
|
Re: Custom Cmdlets - Part two
Inchanel bagsline, various series that all sold extreme well, such as the chanel 2.55 and chanel coco line. The detail design which are definitely appear to be quite beautiful and exciting. All girls would love to own suchchanel handbags in hand. They all consider such handbags can make one a higher status and show elegant appearance. Come to our chanel outletonline to get one.
In Gucci handbagsline, the new versions are designed for men series which appear to be exposure, and luxury colorways that designed in order to attract much more consumers. For the gucci bags2011 winter, all bags that come along with extreme colorways for you to choose from. So to make yourself fashion enough then just come to our gucci outlet store .
Herve Leger bandagenbsp;is a well-know cloth brand in the world, all the time it is committed to shaping women’s physical beauty and showing gentle sense of female silhouettes. Wearing;Herve Leger Dressnbsp;which beautiful designed and made by high quality materials will make you look charming and sexy. The winter is on the way, so it is necessary for to to own the herve leger saleto make yourself upstate.
Remember Gucci outletspring series women show;floor that dazzling high-saturation of bright colors, and full of “Forest Queen” feel of the tassels, decorative knot it? The gucci handbags designer embodies the intrinsic taste, gucci bagsis sought after by celebrities and fashion objects.;In winter season, the gucci handbags sale would be a great topic.
For these fashion ladies and wealth women, they all like to make themselves in unique style in a share. Quality and style would be the main point of these handbags, especially for the louis vuitton bags. For so many years, the company definitely released quite a lot of louis vuitton handbags in the market, and follow the fashion trend up to now. always theseLouis Vuitton outlet that sold at high price, however you can get the discount louis vuitton handbags in our bags outlet online.
Offering its just potential purchasers within of the previous just one hundred fifty extended time, Louis Vuitton pouches coupled with components are developed with one another with enhanced concerning the repaired pursuit to the caliber.Louis Vuitton Handbagsaccessories tend to be abominable advised for ambrosial application alternating with appearing a faculty authority that’s a lot of apparently in actuality why a lot of higher profile, ?many of the fashion ladies abounding approved afterwards purses and handbags,louis vuitton wallets and sun shades. To buy the excellent bags louis vuitton outletwould be a great choice.
One way for some people to get duped into buying Gucci handbags is when they hear about and come to bargained items sales, midnight markets, and the like. You'll find there, amasingly low priced, products of all kinds, but rarely will the actual items there be the real thing. Bargains aren't bad on their own, but if you're looking for the real Gucci bags, it's best to find trusted stores. The Gucci outlet store can point you to stores in your vicinity.
Louis Vuitton outlet store as one of the most luxurious brand in the world, is famous for leather goods loved by so many enthusiasts, which brings a huge business opportunity for market. We are professional trader for wholesale Louis Vuitton handbags, aiming at filling large demands as well as leading fashion trends.
By Chanel Outlet store on
9/27/2011 1:13 PM
|
The winter is coming soon,a pair of Ugg boots might be your nice choice!
The winter is coming soon,a pair of Ugg boots might be your nice choice! baby uggs ugg boots outlet discount uggs Related:
By fdwz00008 on
9/29/2011 3:31 PM
|
Re: Custom Cmdlets - Part two
You just came Chanel Replicas across this really cool bumper sticker printing website that offers colorful, custom stickers at great prices. Unfortunately, Chanel Handbags you're just not sure that you want to put Chanel Bags a sticker of any kind on your Prada Handbags car. What reason would you have to do UGG so?
Trust us;Discount UGGs there are plenty of reasons to Prada Replicas smack one of these great stickers on your ride. The Prada Bags first of which is for a cause. UGGs Is there something that you feel particularly strong about? Are you completely against illegal Gucci Replicas immigration? Do you support organ and tissue donation? Are you a gun control advocate? Are you all about owning a firearm? Gucci Handbags These days there are plenty of things to be passionate UGG Boots on Sale about, from wars in foreign countries, to animal adoption. Gucci Bags People from your hometown to places on the opposite side of the country are promoting their causes with bumper sticker printing.UGG Boots
You don't want to let everyone know Louis Vuitton Replicas how you feel about the death penalty. That's okay! People are putting bumper stickers on their Christian Louboutin Shoes on Sale cars for other reasons too. Discount UGG Boots How about advertising? Do you own a business? Louis Vuitton Handbags Do you have a friend who owns a business? What about UGG Boots Outlet your parents? Individuals who own businesses are beginning to realize that it doesn't really make sense to pay for elaborate Louis Vuitton Bags and expensive advertising when you could just advertise on your own vehicle for essentially free. Bumper sticker advertising is not Discount UGG Boots only inexpensive, it's portable. If you're promoting your business from the back window of your car, then people from your house, to the mall, to the Coach Bags Outlet beach where you're planning to go this weekend will see your advertisement.UGG Boots on Sale Talk about Christian Louboutin Outlet reaching a mass market!
What about politics? Are you a Democrat who is against the new Republican congress and you're already dreaming Coach Handbags about campaigning for the future? Come up with a slogan and make it happen! Or, you can Cheap UGG Boots just promote the candidate with whom you most relate. If you're passionate about politics and you want to help your favorite candidate get the word out, a Coach Bags bumper sticker is definitely the way to go. Political stickers are almost as The North Face Outlet prevalent on the roadway as....cars! Christian Louboutin Shoes
Another type of sticker that's seen on Coach Outlet Online the roadways quite frequently is the sports team sticker. Show off your UGG Boots Volunteer Pride or your love for the Baltimore Orioles with a big, orange "T" or an "O" Discount Christian Louboutin Shoes that takes up half of the back window on your SUV. There are sports team stickers available everywhere online. If Cheap Christian Louboutin Shoes you aren't seeing one you love, a custom bumper sticker printing company can certainly produce one for you and it'll Coach Outlet be a bumper sticker you're proud to have on your car. The North Face Jackets
People also put stickers on North Face Jackets their cars for religious and spiritual reasons. From the Jesus fish, to the cross, people Coach Handbags Outlet are praising the Lord in the pew and on their bumper!
On a more somber note, people also use Coach Handbags bumper stickers to remember relatives and friends who have passed away.
If you're UGGs interested in ordering your Coach Bags Outlet own custom bumper sticker, you're making a great decision! Have a seat in front of your computer and visit a bumper sticker printing company's website. You can customize your own sticker Coach Bags or choose one from the thousands they have to offer. Don't just stop at one though! You can order stickers in bulk, which is especially handy if you're using your bumper stickers to promote your small business. Your Coach Outlet sticker order should ship The North Face Jacket within a couple of days and you'll be well on your way to showing off your cause, political affiliation, or favorite sports team! North Face Jacket
By swei on
10/14/2011 1:30 PM
|
|
|
Re: Custom Cmdlets - Part two
Anyone blogging regularly Discount Vibram FiveFingers would love to increase their blog traffic. Targeted web Vibram Five Fingers on Sale traffic is what every webmaster craves. Cheap Christian Louboutin Shoes The process of getting your site or blog noticed by Vibram FiveFingers on Sale the search engines is often referred to as UGG SEO which stands for search engine Discount Vibram Five Fingers optimization.
When it comes to SEO there are 100's Vibram Five Fingers Outlet of methods, with in those 100's of methods Discount Christian Louboutin Shoes there are probably 1000's of strategies. The most popular method of SEO would have to be Vibram FiveFingers Link Building. Building quality Christian Louboutin Shoes on Sale one way links back to your site or blog Vibram FiveFingers Outlet can be very effective in getting UGGs the search engines attention, when done Vibram Five Fingers correctly.
I know, not Christian Louboutin Shoes everyone that's Blogging or doing any writing online Cheap UGG Boots for that matter, is doing it for a business purpose, I also know, it's a great hobby. A lot of people write Blue UGG Boots cause they feel they have a knack for it, but unfortunately no one can Christian Louboutin Outlet ever see it because it hasn't been Blue UGG Search Engine Optimized or to be a little more specific, Blue UGGs you need Backlinks. Yes, Backlinks is only part of the equation, but in my honest Red UGG opinion a solid Link Building Strategy can UGG Boots on Sale really get the search engines attention. Red UGG Boots
Think about this, you wouldn't be spending Red UGGs your valuable time working out or exercising if you knew you'd never UGG Gloves get results, so why are you Blogging/Writing, if only a handful of Discount UGGs people ever see it, you might as well just think it for that matter.
You need to get traffic to UGG Boots on Sale your Blogs and Articles if you'd like a chance of monetizing it. You can use UGG Gloves AdSense ad's or promote affiliate products to make some spare cash if your UGG Boots Blog is getting traffic too. It all comes back to traffic, and unless your paying for it, getting traffic is hard work. Building one way Backlinks to your Blog Discount UGG Boots is one of the most popular methods UGG Boots Outlet to increase Blog traffic.
You'd be surprised to know how many UGGs "Bloggers", holding no more than a High School Diploma are "6 Figure Income - Expert Writers" now because some Big- Wig saw something special in their content. Blogging is awesome, I still write at least a post a day. Nothing is Sand UGG Boots worse than pouring your heart into something Sand UGG and getting nothing out of it.
Quick Personal Experience... Sand UGGs
I love the NFL, I know a lot Navy UGG Boots about it and it's fun for me to Green UGGs write about it. When I first started Blogging I couldn't get 10 visitors a day, and it killed me because I knew Navy UGG I had a lot to offer. I knew that anyone that actually Black UGG Boots knew football would really enjoy my Blog, but I Discount UGG Boots couldn't get it to anyone. Finally I read a report about Green UGG Boots Link Building strategies and I got to work. After about Green UGG 6 weeks of blood sweat and tears and building Backlinks nearly 24/7 the traffic started to roll in. Now, I enjoy writing about the NFL weekly and it results in a steady income Black UGGs for me. Is it making me rich, no far from it, just knowing my writing is what I thought it Navy UGGs was and people are willing to pay me UGG Boots for it, has been very gratifying. Black UGG
By swei on
12/15/2011 2:17 PM
|
robe de mariée
bridesmaid dresses Weddingdressesgo.com offers you the latest trends and classic designs bridesmaid dresses that never go out of style.Cheap fashion bridesmaid dresses are hot selling. flower girl dresses Shop online weddingdressesgo.com for large selection of flower girl dresses and accessories. special occasion dresses Great wholesale online store for special occasion dresses, plus size special occasion dresses,womens special occasion dresses... wedding dresses Weddingdressesgo.com carries the largest selection of beautiful wedding dresses 2012 for your big day.Affordable fashion for you!Fast delivery for you! bridal gowns Professional bridal dresses stores online.Many fashion styles of bridal wedding dresses,bridal gowns are designed for you! Cheap price and best quality. robes de soirée robe de mariée pas cher robe de cocktail robe de mariée robe de soirée wedding underwear
By zhangxiuqing on
2/25/2012 10:38 AM
|