Topics


Blogs


Forums


Samples


Media


Labs


Resources

 




DevCentral > Weblogs > Joe Pruitt - A Software Architect's take on Network Security
 Introducing PoshTwitPic – Use PowerShell To Post Your Images To Twitter Via TwitPic
posted on Wednesday, June 17, 2009 5:31 PM

PowerShell-twitpicTwitter, for those who don’t know about it, is a status updating service that is all the rage nowadays.  It’s popularity is primarily due to it’s simplistic nature.  You post a 140 character status (known as a “tweet”) about what you are doing.  You can also friend other folks to see what they are doing.  If you are still lost, read up on the entry in Wikipedia and you should get the gist of it. 

The downside to this minimalistic approach is that it does not allow for rich multimedia content such as images or videos to be associated with your “tweets”.  Let’s face it, posting a tweet about an awesome dinner you just had isn’t as good as posting a picture you took of it.  To account for this, various services have arisen to offload the image or video storage for twitter and many of the Twitter clients out there have incorporated these services into their apps.  TwitPic was an early entry into this category of services.  They allow you to post an image to their site while posting a “tweet” to Twitter including a link to the image.  Fortunately for us, TwitPic exposes their API to allow applications to integrate their features.

Since I’ve already tackled the PowerShell Twitter functionality with my PoshTweet library, I figured the next logical step would be to write a TwitPic library to enable posting images to TwitPic through their API.

The biggest challenge in writing this library was getting the multipart/form-data POST format working correctly.  Luckily I stumbled across a post by Martin Normark on his blog containing a C# TwitPic API client.  It was fairly straightforward coming up with a PowerShell conversion of his C# code.

My library includes the following functions

  • Get-EncodedDataFromFile – Encode a local image file into a string.
  • Get-ImageContentType – Get the Content Type for a given image file (ie. image/jpeg).
  • Execute-HTTPPostCommand – Send a HTTP POST command containing the multipart/form-data request.
  • Post-TwitPic – The main function that takes an image, posts it to TwitPic and optionally posts a Tweet to Twitter.

Without further ado, here’s the code:

   1: param(
   2:   [System.IO.FileInfo]$file = $null,
   3:   [string]$twitteruser = $null,
   4:   [string]$twitterpass = $null,
   5:   [string]$message = $null
   6: );
   7:  
   8: $CODEPAGE = "iso-8859-1";
   9:  
  10: $TWITPIC_API_UPLOAD = "http://twitpic.com/api/upload";
  11: $TWITPIC_API_UPLOADANDPOST = "http://twitpic.com/api/uploadAndPost";
  12:  
  13: #--------------------------------------------------------------------------------------------
  14: # function Get-EncodedDataFromFile
  15: #--------------------------------------------------------------------------------------------
  16: function Get-EncodedDataFromFile()
  17: {
  18:   param(
  19:     [System.IO.FileInfo]$file = $null,
  20:     [string]$codePageName = $CODEPAGE
  21:   );
  22:   
  23:   $data = $null;
  24:  
  25:   if ( $file -and [System.IO.File]::Exists($file.FullName) )
  26:   {
  27:     $bytes = [System.IO.File]::ReadAllBytes($file.FullName);
  28:     if ( $bytes )
  29:     {
  30:       $enc = [System.Text.Encoding]::GetEncoding($codePageName);
  31:       $data = $enc.GetString($bytes);
  32:     }
  33:   }
  34:   else
  35:   {
  36:     Write-Host "ERROR; File '$file' does not exist";
  37:   }
  38:   $data;
  39: }
  40:  
  41: #--------------------------------------------------------------------------------------------
  42: # function Get-ImageContentType
  43: #--------------------------------------------------------------------------------------------
  44: function Get-ImageContentType()
  45: {
  46:   param([System.IO.FileInfo]$file = $null);
  47:   $contentType = $null;
  48:   $contentTypeMap = @{
  49:     ".jpg"  = "image/jpeg";
  50:     ".jpeg" = "image/jpeg";
  51:     ".gif"  = "image/gif";
  52:     ".png"  = "image/png";
  53:     ".tiff" = "image/tiff";
  54:   }
  55:   
  56:   if ( $file )
  57:   {
  58:     $contentType = $contentTypeMap[$file.Extension.ToLower()];
  59:   }
  60:   $contentType;
  61: }
  62:  
  63: #----------------------------------------------------------------------------
  64: # function Execute-HTTPPostCommand
  65: #----------------------------------------------------------------------------
  66: function Execute-HTTPPostCommand()
  67: {
  68:   param(
  69:     [string] $url = $null,
  70:     [string] $data = $null,
  71:     [System.Net.NetworkCredential]$credentials = $null,
  72:     [string] $contentType = "application/x-www-form-urlencoded",
  73:     [string] $codePageName = "UTF-8",
  74:     [string] $userAgent = $null
  75:   );
  76:  
  77:   if ( $url -and $data )
  78:   {
  79:     [System.Net.WebRequest]$webRequest = [System.Net.WebRequest]::Create($url);
  80:     $webRequest.ServicePoint.Expect100Continue = $false;
  81:     if ( $credentials )
  82:     {
  83:       $webRequest.Credentials = $credentials;
  84:       $webRequest.PreAuthenticate = $true;
  85:     }
  86:     $webRequest.ContentType = $contentType;
  87:     $webRequest.Method = "POST";
  88:     if ( $userAgent )
  89:     {
  90:       $webRequest.UserAgent = $userAgent;
  91:     }
  92:     
  93:     $enc = [System.Text.Encoding]::GetEncoding($codePageName);
  94:     [byte[]]$bytes = $enc.GetBytes($data);
  95:     $webRequest.ContentLength = $bytes.Length;
  96:     [System.IO.Stream]$reqStream = $webRequest.GetRequestStream();
  97:     $reqStream.Write($bytes, 0, $bytes.Length);
  98:     $reqStream.Flush();
  99:     
 100:     $resp = $webRequest.GetResponse();
 101:     $rs = $resp.GetResponseStream();
 102:     [System.IO.StreamReader]$sr = New-Object System.IO.StreamReader -argumentList $rs;
 103:     $sr.ReadToEnd();
 104:   }
 105: }
 106:  
 107: #--------------------------------------------------------------------------------------------
 108: # function Post-TwitPic
 109: #--------------------------------------------------------------------------------------------
 110: function Post-TwitPic()
 111: {
 112:   param
 113:   (
 114:     [System.IO.FileInfo]$file = $null,
 115:     [string]$twitteruser = $null,
 116:     [string]$twitterpass = $null,
 117:     [string]$message = $null
 118:   );
 119:   
 120:   if ( $file -and $twitteruser -and $twitterpass )
 121:   {
 122:     $boundary = [System.Guid]::NewGuid().ToString();
 123:     $header = "--{0}" -f $boundary;
 124:     $footer = "--{0}--" -f $boundary;
 125:   
 126:     [System.Text.StringBuilder]$contents = New-Object System.Text.StringBuilder;
 127:     [void]$contents.AppendLine($header);
 128:  
 129:     $filedata = Get-EncodedDataFromFile -file $file -codePageName $CODEPAGE;
 130:     if ( $filedata )
 131:     {
 132:       $fileContentType = Get-ImageContentType -file $file;
 133:       $fileHeader = "Content-Disposition: file; name=""{0}""; filename=""{1}""" -f "media", $file.Name;
 134:  
 135:       [void]$contents.AppendLine($fileHeader);
 136:       [void]$contents.AppendLine("Content-Type: {0}" -f $fileContentType);
 137:       [void]$contents.AppendLine();
 138:       [void]$contents.AppendLine($fileData);
 139:  
 140:       [void]$contents.AppendLine($header);
 141:       [void]$contents.AppendLine("Content-Disposition: form-data; name=""username""");
 142:       [void]$contents.AppendLine();
 143:       [void]$contents.AppendLine($twitteruser);
 144:       
 145:       [void]$contents.AppendLine($header);
 146:       [void]$contents.AppendLine("Content-Disposition: form-data; name=""password""");
 147:       [void]$contents.AppendLine();
 148:       [void]$contents.AppendLine($twitterpass);
 149:       
 150:       $url = $TWITPIC_API_UPLOAD;
 151:       if ( $message )
 152:       {
 153:         [void]$contents.AppendLine($header);
 154:         [void]$contents.AppendLine("Content-Disposition: form-data; name=""message""");
 155:         [void]$contents.AppendLine();
 156:         [void]$contents.AppendLine($message);
 157:         
 158:         $url = $TWITPIC_API_UPLOADANDPOST;
 159:       }
 160:       
 161:       [void]$contents.AppendLine($footer);
 162:       
 163:       $contents.ToString() > ".\out.txt";
 164:       
 165:       $postContentType = "multipart/form-data; boundary={0}" -f $boundary;
 166:       
 167:       [xml]$resp = Execute-HTTPPostcommand -url $url -data $contents.ToString() `
 168:         -contentType $postContentType -codePageName $CODEPAGE -userAgent "PoshTwitPic";
 169:       
 170:       if ( $resp )
 171:       {
 172:         switch ($resp.rsp.stat)
 173:         {
 174:           "ok" {
 175:             $obj = 1 | select mediaid, mediaurl;
 176:             $obj.mediaid = $resp.rsp.mediaid;
 177:             $obj.mediaurl = $resp.rsp.mediaurl;
 178:             $obj;
 179:           }
 180:           "fail" {
 181:             $errcode = $resp.rsp.err.code;
 182:             $errmsg = $resp.rsp.err.msg;
 183:             Write-Host "Post Error: Code = '$errcode'; Message = '$errmsg'";
 184:           }
 185:         }
 186:       }
 187:     }
 188:   }
 189:   else
 190:   {
 191:     Write-Host "USAGE: Post-TwitPic.ps1 -file file -twitteruser user -twitterpass pass";
 192:   }
 193: }
 194:  
 195: if ( $file -and $twitteruser -and $twitterpass )
 196: {
 197:   Post-TwitPic -file $file -twitteruser $twitteruser -twitterpass $twitterpass -message $message;
 198: }
 199: else
 200: {
 201:   Write-Host "USAGE: Post-TwitPic.ps1 -file file -twitteruser user -twitterpass pass";
 202: }

The entire script can be downloaded from here: Post-TwitPic.ps1

Happy Tweeting!



 
      

Feedback


7/16/2009 4:07 PM
Gravatar Thanks for posting this Twitter pic tut! Now maybe I really CAN post that photo of the really big meal I ate last night! lol
Schedule Tweets

7/29/2009 12:43 AM
Gravatar wow interesting code, i'm going to try it out now and see how it works!
resveratrol supplements
 Leave Feedback
Title  
Name  
Email
Url
Comments   
Please add 5 and 5 and type the answer here: