Topics


Blogs


Forums


Samples


Media


Labs


Resources

 




DevCentral > Weblogs > Joe Pruitt - A Software Architect's take on Network Security
  Friday, June 19, 2009 #
  
Shrink-Url – Use PowerShell To Shrink Your Urls
submitted 2 weeks ago

poshShrinkShrinking your Url’s is all the rage nowadays.  If you are on Twitter, then odds are you have used one.  Despite CodingHorror’s distaste for them in his recent blog post on Url Shorteners: Destroying the Web since 2002, they are a fact of life when we live in a world of 140 character status updates.

So what’s a URL shrinking service anyway?  Well, to put it simply, you supply them with a URL, they then supply you with a shorter URL containing a lookup “key”.  When future requests are made to this shorter URL, connections are routed to that services website where they convert the short URL to the original URL and issue a HTTP Redirect back to your browser to send you off to the original long url website.

So, what’s a guy, or gal, to do if they want to set their status programmatically on Twitter, Facebook, FriendFeed, or the other gazillion social networking sites out there today and need to post a very long URL?  Most of these shrinking services offer API’s to access their “shrinking” services so it’s just a matter of digging into the various APIs to get them implemented.  In my original PowerShell Twitter library PoshTweet, I included support for a couple for shrinking URL’s through a couple of shrinking services but I figured it would be good to separate that functionality out into it’s own library. 

So, here’s my first stab at a generic URL shortening library for PowerShell.  I’ve included the following services:

Some of these services have advanced features such as statistical reporting on all your submitted links.  Those services require users to create accounts and register for API keys.  Bit.ly is one of them, so if you want to use that service, you will have to supply this script with your bit.ly username and API key with the Set-BitlyServiceInfo function.

So, here’s the script, hope you all enjoy!

 

   1: param(
   2:   [string]$longurl = $null,
   3:   [string]$provider = "tinyurl"
   4: );
   5:  
   6: $script:DIGG_APPKEY = "http://devcentral.f5.com/PoshShrink";
   7: $script:BITLY_LOGIN = "";
   8: $script:BITLY_KEY = "";
   9:  
  10: #----------------------------------------------------------------------------
  11: # function Set-BitlyServiceInfo
  12: #----------------------------------------------------------------------------
  13: function Set-BitlyServiceInfo()
  14: {
  15:   param(
  16:     [string]$login = $null,
  17:     [string]$key = $null
  18:   );
  19:   if ( $login -and $key )
  20:   {
  21:     $script:BITLY_LOGIN = $login;
  22:     $script:BITLY_KEY = $key;
  23:   }
  24:   else
  25:   {
  26:     Write-Error "Usage: Set-BitlyServiceInfo -login login -key key";
  27:   }
  28: }
  29:  
  30: #----------------------------------------------------------------------------
  31: # function Shrink-Url
  32: #----------------------------------------------------------------------------
  33: function Shrink-Url()
  34: {
  35:   param(
  36:     [string]$longurl = $null,
  37:     [string]$provider = "tinyurl"
  38:   );
  39:   
  40:   $shorturl = $null;
  41:   if ( $longurl )
  42:   {
  43:     switch ($provider.ToLower())
  44:     {
  45:       "is.gd" {
  46:         $shorturl = Execute-HTTPGetCommand "http://is.gd/api.php?longurl=$longurl";
  47:       }
  48:       "tinyurl" {
  49:         $shorturl = Execute-HTTPGetCommand "http://tinyurl.com/api-create.php?url=$longurl";
  50:       }
  51:       "snurl" {
  52:         $shorturl = Execute-HTTPGetCommand "http://snipr.com/site/snip?r=simple&link=$longurl";
  53:       }
  54:       "digg" {
  55:         [xml]$results = Execute-HTTPGetCommand `
  56:           "http://services.digg.com/url/short/create?url=${longurl}&appkey=${script:DIGG_APPKEY}";
  57:         $shorturl = $results.shorturls.shorturl.short_url;
  58:       }
  59:       "tr.im" {
  60:         [xml]$results = Execute-HTTPGetCommand "http://api.tr.im/api/trim_url.xml?url=$longurl";
  61:         $shorturl = $results.trim.url;
  62:       }
  63:       "bit.ly" {
  64:         if ( !$BITLY_LOGIN -or !$BITLY_KEY )
  65:         {
  66:           Write-Error "ERROR: You must configure your bit.ly LOGIN and APIKEY!"
  67:           exit;
  68:         }
  69:         else
  70:         {
  71:           $results = Execute-HTTPGetCommand `
  72:             "http://api.bit.ly/shorten?version=2.0.1&longUrl=$longurl&login=$script:BITLY_LOGIN&apiKey=$script:BITLY_KEY";
  73:           $shorturl = $results.Split("`n")[7].Split("""")[3];
  74:         }
  75:       }
  76:       default {
  77:         $shorturl = Execute-HTTPGetCommand "http://tinyurl.com/api-create.php?url=$longurl";
  78:       }
  79:     }
  80:   }
  81:   else
  82:   {
  83:     Write-Host "ERROR: Usage: Shrink-Url -longurl http://www.foo.com";
  84:   }
  85:   $shorturl;
  86: }
  87:  
  88: #----------------------------------------------------------------------------
  89: # function Execute-HTTPGetCommand
  90: #----------------------------------------------------------------------------
  91: function Execute-HTTPGetCommand()
  92: {
  93:   param([string] $url = $null);
  94:   
  95:   $user_agent = "PoshShrink";
  96:   
  97:   if ( $url )
  98:   {
  99:     $request = [System.Net.HttpWebRequest]::Create($url);
 100:     $request.UserAgent = $user_agent;
 101:     $request.Credentials = [System.Net.CredentialCache]::DefaultCredentials;
 102:     if ( $request.Proxy )
 103:     {
 104:       $request.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;
 105:     }
 106:     $response = $request.GetResponse();
 107:     $rs = $response.GetResponseStream();
 108:     [System.IO.StreamReader]$sr = New-Object System.IO.StreamReader -argumentList $rs;
 109:     $sr.ReadToEnd();
 110:   }
 111: }
 112:  
 113: Shrink-Url -longurl $longurl -provider $provider;

 

You can download the full contents for this script here: Shrink-Url.ps1


One Comment | Email This
  del.icio.us
      

  Wednesday, June 17, 2009 #
  
Introducing PoshTwitPic – Use PowerShell To Post Your Images To Twitter Via TwitPic
submitted 2 weeks ago

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!


Add Comment | Email This
  del.icio.us
      

  Monday, June 08, 2009 #
  
Introducing AskBing – The PowerShell Bing Twitter Proxy
submitted 3 weeks ago

TwitterBingLast week I posted a PowerShell function library for Microsoft’s newly introduced search engine at Bing.com.  The function library was appropriately named PoshBing. There was a log of interest in the script so I quickly moved it off my blog and onto a CodePlex project under PoshBing.

Working on the command line is fun and all, but since I spend a good portion of my time accessing my twitter account, I figured it would be a bit of fun to integrate it with my previously released PoshTweet PowerShell twitter library.

So, after an hour or so of coding it up and creating the @askbing twitter account, I’ve got it up and running. 

Using it is as simple as posting a message mentioning the @askbing account.  The Usage is as follows:

@askbing [sourcetype [options]] question_or_search_terms

If you omit the sourcetype it will default to “web”.  The following sourcetypes and options are currently available:

  • @askbing image iPod
  • @askbing instantanswer feet in a mile
  • @askbing news FFIV
  • @askbing mobileweb games
  • @askbing phonebook “F5 Networks”
  • @askbing relatedsearch “Xbox”
  • @askbing spell Is this missspelled?"
  • @askbing web Apple
  • @askbing translation en:es Hi, how are you?
  • @askbing video The Pick of Destiny

The only source type that includes a separate option is “translation”  By default it will translate from English to Spanish.  If you want to override these languages, you can use the “from:to” option to override these defaults.  The values for the from and to languages

  • Ar = Arabic
  • zh-CHS = Simplified Chinese
  • zh-CHT = Traditional Chinese
  • Nl = Dutch
  • En = English
  • Fr = French
  • De = German
  • It = Italian
  • Ja = Japanese
  • Ko = Korean
  • Pl = Polish
  • Pt = Portuguese
  • Ru = Russian
  • Es = Spanish

After you post an @reply to @askbing, you should expect a @reply to your account within a minute or so.

Since I’ve only spent an hour or so on this, there are bound to be some issues so please let me know if you find any.  Here' are a few known issues:

  1. It queries it’s @replies every 60 seconds and only queries 100 entries so if this ever gets more popular that that, I’ll need to enhance the request logic.
  2. It only returns the first entry returned from the bing services.  I might change this to a random entry later on.
  3. It has little error handling so if you get a garbled response, then that’s likely the reason.
  4. It uses tinyurl for Url shortening which is sometimes fairly flaky.
  5. Probably more…

So, when you’ve got some time, Send a @reply to @askbing and see how it works for you.  I’d love to hear any and all feedback.

-Joe


6 Comments | Email This
  del.icio.us
      

  Wednesday, June 03, 2009 #
  
Introducing PoshBing – The PowerShell library for Microsoft’s Bing Search Engine
submitted 4 weeks ago

PoshBing Microsoft released their new search engine called “Bing” at, aptly named, http://www.bing.com.  Microsoft is getting positive reviews from the likes of CNET, The Wall Street Journal, and TechCrunch.  Instead of posting my review of the site, I’ll let you browse the above links to find out what the services is all about.

What interested me about Bing is that Microsoft has released a full API to allow you to use their services in your applications.  The Bing API is documented at Microsoft’s developer site and I thought to myself how I could test it out.  The obvious answer was PowerShell of course.  My previous PoshTweet Twitter Library has been fairly popular so I figured I’d give a “library” type project another go around and tackle the Bing APIs.

The Bing API has the concept of “SourceTypes” which are essentially data sources that you can search into.  My script library provides access to the Image, InstantAnswer, News, MobileWeb, Phonebook, RelatedSearch, Spell, Web, Translation, and Video SourceTypes with the following functions:

  • Get-BingImage – Search the Image SourceType for a list of images including properties about the media files.
  • Get-BingInstantAnswer – Get single, authoritative answers to questions.
  • Get-BingNews – Provide news specific to a topic, a location, or breaking news.
  • Get-BingMobileWeb – Returns mobile web results, primarily relevant XHTML or WML pages.
  • Get-BingPhonebook – Enables you to view details about a business for which you are searching as if they were a phonebook entry.
  • Get-BingRelatedSearch – View searches that provide information in which you might be interested, based on your current search.
  • Get-BingSpell – Query alternative spellings for a given word or phrase.
  • Get-BingWeb – Get pages relevant to the queried terms.
  • Get-BingTranslation – Translate a term from one language to another.
  • Get-BingVideo – return a list of videos and their properties relevant to the query terms.

I’ve included parsing for the response streams for the above SourceTypes, but if you would like to get the raw XML back, all of the above functions include a “-raw” parameter to allow you to bypass the response processing.

 

*Update* 

This little script has taken on a life of it’s own.  As a consequence, I’ve created a project on CodePlex.com to manage the distributions.  You can access it now at the following link:

http://poshbing.codeplex.com

Enjoy!


26 Comments | Email This
  del.icio.us
      

  Monday, May 18, 2009 #
  
Unix To PowerShell - Md5
submitted 6 weeks ago

PowerShell_unix PowerShell is definitely gaining momentum in the windows scripting world but I still hear folks wanting to rely on Unix based tools to get their job done.  In this series of posts I’m going to look at converting some of the more popular Unix based tools to PowerShell.

md5

The Unix “md5” command (aliased to “openssl dgst –md5” or “md5sum”) calculates and verifies 128-bit MD5 hashes as described in RFC 1321.  The MD5 hash (or checksum) functions as a compact digital fingerprint of a file.  It is extremely unlikely that any two non-identical files existing in the real world will have the same MD5 hash.

The “openssl dgst –md5” option, there is a “-c” option to include colons between the two digit groups in the digest.  The “md5sum” command does not.  I’ve opted to use the output format of the “openssl” version of the command for my PowerShell function.

Unix PowerShell Description
-c -colons Print the digest in two-digit groups
separated by colons.

 

   1: #----------------------------------------------------------------
   2: # Md5.ps1
   3: #----------------------------------------------------------------
   4: param
   5: (
   6:   [string]$filespec = $null,
   7:   [bool]$colons = $false
   8: );
   9:  
  10: #----------------------------------------------------------------
  11: # function Do-Md5
  12: #----------------------------------------------------------------
  13: function Do-Md5()
  14: {
  15:   param
  16:   (
  17:     [string]$filespec = $null,
  18:     [bool]$colons = $false
  19:   );
  20:   
  21:   $hashAlgorithm = new-object -TypeName "System.Security.Cryptography.MD5CryptoServiceProvider";
  22:   
  23:   $files = @(Get-ChildItem -Path $filespec -ErrorAction SilentlyContinue);
  24:   foreach ($file in $files)
  25:   {
  26:     $stream = $file.OpenRead();
  27:     $hashByteArray = $hashAlgorithm.ComputeHash($stream);
  28:     $stream.Close();
  29:     
  30:     $md5StringBuilder = New-Object System.Text.StringBuilder
  31:     
  32:     $hashByteArray | % {
  33:       if ( $colons )
  34:       {
  35:         if ( $md5StringBuilder.Length -gt 0 ) { [void] $md5StringBuilder.Append(":") }
  36:       }
  37:       [void] $md5StringBuilder.Append($_.ToString("x2"))
  38:     }
  39:     
  40:     "MD5($($file.Name))= $($md5StringBuilder.ToString())";
  41:  
  42:     # Ensure stream is closed if exceptions occurred.
  43:     trap
  44:     {
  45:         if ($stream -ne $null) { $stream.Close(); }
  46:         break;
  47:     }
  48:   }
  49: }
  50:  
  51: Do-Md5 -filespec $filespec -colons $colons;

You can download the source for this script here: Md5.ps1


One Comment | Email This
  del.icio.us
      

  Thursday, May 07, 2009 #
  
Unix To PowerShell - Touch
submitted 8 weeks ago

PowerShell_unix PowerShell is definitely gaining momentum in the windows scripting world but I still hear folks wanting to rely on Unix based tools to get their job done.  In this series of posts I’m going to look at converting some of the more popular Unix based tools to PowerShell.

touch

The Unix “touch” command is used to change a file’s access and modification timestamps.  It can also be used to create a new empty file.

The options to the Unix touch command are implemented with the following PowerShell parameters:

Unix PowerShell Description
FILE -filespec The files to modify.
-d -datetime Parse STRING and use it instead of current time.
-F -forward Modify the time by going forward SECONDS seconds.
-r -reference Use this file as a reference instead of the current time.
-m -only_modification Change only the modification time.
-a -only_access Change only the access time.

 

   1: #----------------------------------------------------------------
   2: # Touch.ps1
   3: #----------------------------------------------------------------
   4: param
   5: (
   6:   [string]$filespec = $null,         # Files to touch
   7:   [DateTime]$datetime = ([DateTime]::Now), # Use DateTime STRING instead of current time.
   8:   [int]$forward = 0,                 # Modify the time by going forward SECONDS s.
   9:   [string]$reference = $null,        # Use this file's time instead of current time.
  10:   [bool]$only_modification = $false, # Change only the modification time.
  11:   [bool]$only_access = $false        # Change only the access time
  12: );
  13:  
  14: #----------------------------------------------------------------
  15: # Function Do-Touch
  16: #----------------------------------------------------------------
  17: function Do-Touch {
  18:   param(
  19:     [string]$filespec = $null,
  20:     [datetime]$datetime = ([DateTime]::Now),
  21:     [int]$forward = 0,
  22:     [string]$reference = $null,
  23:     [bool]$only_modification = $false,
  24:     [bool]$only_access = $false
  25:   );
  26:   
  27:   $touch = $null;
  28:   
  29:   if ( $filespec )
  30:   {
  31:     $files = @(Get-ChildItem -Path $filespec -ErrorAction SilentlyContinue)
  32:     if ( !$files )
  33:     {
  34:       # If file doesn't exist, attempt to create one.
  35:       # A wildcard patter will fail silently.
  36:       Set-Content -Path $filespec -value $null;
  37:       $files = @(Get-ChildItem -Path $filespec -ErrorAction SilentlyContinue);
  38:     }
  39:     
  40:     if ( $files )
  41:     {
  42:       if ( $reference )
  43:       {
  44:         $reffile = Get-ChildItem -Path $reference -ErrorAction SilentlyContinue;
  45:         if ( $reffile )
  46:         {
  47:           [datetime]$touch = $reffile.LastAccessTime.AddSeconds($forward);
  48:         }
  49:       }
  50:       elseif ( $datetime )
  51:       {
  52:         [datetime]$touch = $datetime.AddSeconds($forward);
  53:       }
  54:       
  55:       if ( $touch )
  56:       {
  57:         [DateTime]$UTCTime = $touch.ToUniversalTime();
  58:         foreach ($file in $files)
  59:         {
  60:           if ( $only_access )
  61:           {
  62:             $file.LastAccessTime=$touch
  63:             $file.LastAccessTimeUtc=$UTCTime
  64:           }
  65:           elseif ( $only_modification )
  66:           {
  67:             $file.LastWriteTime=$touch
  68:             $file.LastWriteTimeUtc=$UTCTime
  69:           }
  70:           else
  71:           {
  72:             $file.CreationTime = $touch;
  73:             $file.CreationTimeUtc = $UTCTime;
  74:             $file.LastAccessTime=$touch
  75:             $file.LastAccessTimeUtc=$UTCTime
  76:             $file.LastWriteTime=$touch
  77:             $file.LastWriteTimeUtc=$UTCTime
  78:           }
  79:           $file | select Name, *time*
  80:         }
  81:       }
  82:     }
  83:   }
  84: }
  85:  
  86: Do-Touch -filespec $filespec -datetime $datetime -forward $forward -reference $reference `
  87:   -only_modification $only_modification -only_access $only_access;

You can download the full script here: Touch.ps1


Add Comment | Email This
  del.icio.us
      

  Wednesday, May 06, 2009 #
  
Unix To PowerShell – Cut
submitted 8 weeks ago

PowerShell_unix PowerShell is definitely gaining momentum in the windows scripting world but I still hear folks wanting to rely on Unix based tools to get their job done.  In this series of posts I’m going to look at converting some of the more popular Unix based tools to PowerShell.

cut

The Unix “cut” command is used to extract sections from each link of input.  Extraction of line segments can be done by bytes, characters, or fields separated by a delimiter.  A range must be provided in each case which consists of one of N, N-M, N- (N to the end of the line), or –M (beginning of the line to M), where N and M are counted from 1 (there is no zeroth value).

For PowerShell, I’ve omitted support for bytes but the rest of the features is included.  The Parse-Range function is used to parse the above range specification.  It takes as input a range specifier and returns an array of indices that the range contains.  Then, the In-Range function is used to determine if a given index is included in the parsed range. 

The real work is done in the Do-Cut function.  In there, input error conditions are checked.  Then for each file supplied, lines are extracted and processed with the given input specifiers.  For character ranges, each character is processed and if it’s index in the line is in the given range, it is appended to the output line.  For field ranges, the line is split into tokens using the delimiter specifier (default is a TAB).  Each field is processed and if it’s index is in the included range, the field is appended to the output with the given output_delimiter specifier (which defaults to the input delimiter).

The options to the Unix cut command are implemented with the following PowerShell arguments:

Unix PowerShell Description
FILE -filespec The files to process.
-c -characters Output only this range of characters.
-f -fields Output only these fields specified by given range.
-d -delimiter Use DELIM instead of TAB for input field delimiter.
-s -only_delimited Do not print lines not containing delimiters.
--output-delimiter -output_delimiter Use STRING as the output deflimiter.

 

   1: #----------------------------------------------------------------
   2: # Cut.ps1
   3: #----------------------------------------------------------------
   4: param
   5: (
   6:   [string]$filespec = $null,
   7:   [string]$characters = $null,      # Output only this range of characters
   8:   [string]$fields = $null,          # Output Only this field range (ie 1-2; 3,4)
   9:   [string]$delimiter = $null,        # Use DELIM instead of TAB for field delimiter
  10:   [bool]$only_delimited = $false,   # Do not print lines not containing delimiter
  11:   [string]$output_delimiter = $null # Use STRING as output delimiter 
  12: );
  13:  
  14: $script:IN_DELIMITER = "`t";
  15: if ( $delimiter ) { $script:IN_DELIMITER = $delimiter; }
  16: $script:OUT_DELIMITER = $delimiter;
  17: if ( $output_delimiter ) { $script:OUT_DELIMITER = $output_delimiter; }
  18:  
  19: $script:MAX_COLUMNS = 1000;
  20:  
  21: #----------------------------------------------------------------
  22: # function Show-Error
  23: #----------------------------------------------------------------
  24: function Show-Error()
  25: {
  26:   param([string]$msg = $null);
  27:   if ( $msg )
  28:   {
  29:     Write-Host $msg;
  30:     exit;
  31:   }
  32: }
  33:  
  34: #----------------------------------------------------------------
  35: # function Parse-Range
  36: #----------------------------------------------------------------
  37: function Parse-Range()
  38: {
  39:   param([string]$range);
  40:   
  41:   [int[]]$indices = @();
  42:   if ( $range )
  43:   {
  44:     $tokens = $range.Split(',');
  45:     foreach ($token in $tokens )
  46:     {
  47:       if ( $token.Contains("-") )
  48:       {
  49:         $subtokens = $token.Split('-');
  50:         if ( $subtokens.Length -ne 2 )
  51:         {
  52:           Show-Error "Cut: Invalid character or field list."
  53:           exit;
  54:         }
  55:         else
  56:         {
  57:           if ( ($subtokens[0].Length -eq 0) -and ($subtokens[1].Length -gt 0) )
  58:           {
  59:             # -N
  60:             $indices += @(1 .. $subtokens[1]);
  61:           }
  62:           elseif ( ($subtokens[1].Length -eq 0) -and ($subtokens[0].Length -gt 0) )
  63:           {
  64:             # N-
  65:             $indices += @($subtokens[0] .. $script:MAX_COLUMNS);
  66:           }
  67:           else
  68:           {
  69:             # N-N
  70:             if ( $subtokens[1] -lt $subtokens[0] )
  71:             {
  72:               Show-Error "Cut: Invalid character or field list";
  73:             }
  74:             else
  75:             {
  76:               $indices += @($subtokens[0] .. $subtokens[1]);
  77:             }
  78:           }
  79:         }
  80:       }
  81:       else
  82:       {
  83:        $indices += @($token);
  84:       }
  85:     }
  86:   }
  87:   $indices;
  88: }
  89:  
  90: #----------------------------------------------------------------
  91: # function In-Range
  92: #----------------------------------------------------------------
  93: function In-Range()
  94: {
  95:   param
  96:   (
  97:     [int]$index = 0,
  98:     [int[]]$range = $null
  99:   );
 100:   $inrange = $true;
 101:   
 102:   if ( $range )
 103:   {
 104:     $inrange = $false;
 105:     foreach ($i in $range )
 106:     {
 107:       if ( $i -eq $index )
 108:       {
 109:         $inrange = $true;
 110:       }
 111:     }
 112:   }
 113:   $inrange;
 114: }
 115:  
 116: #----------------------------------------------------------------
 117: # function Do-Cut
 118: #----------------------------------------------------------------
 119: function Do-Cut()
 120: {
 121:   param
 122:   (
 123:     [string]$filespec = $null,
 124:     [string]$characters = $null,
 125:     [string]$fields = $null,
 126:     [string]$delimiter = $null,
 127:     [bool]$only_delimited = $false,
 128:     [string]$output_delimiter = $null
 129:   );
 130:   
 131:   if ( $filespec )
 132:   {
 133:     # Check parameters
 134:     if ( $characters -and $fields )
 135:     {
 136:       Show-Error "Cut: only one type of list may be specified.";
 137:     }
 138:     elseif ( !$characters -and !$fields )
 139:     {
 140:       Show-Error "Cut: You must specify a list of characters or fields.";
 141:     }
 142:     else
 143:     {
 144:       if ( $characters )
 145:       {
 146:         $range = Parse-Range -range $characters;
 147:       }
 148:       elseif ( $fields )
 149:       {
 150:         $range = Parse-Range -range $fields;
 151:       }
 152:       
 153:       $files = @(Get-ChildItem -Path $filespec);
 154:       foreach ($file in $files)
 155:       {
 156:         $lines = Get-Content -Path $file;
 157:         foreach ($line in $lines)
 158:         {
 159:           $line_out = $line;
 160:           if ( $characters )
 161:           {
 162:             $line_out = "";
 163:             for($i = 1; $i -le $line.Length; $i++)
 164:             {
 165:               if ( In-Range $i $range )
 166:               {
 167:                 $line_out += $line[$i-1];
 168:               }
 169:             }
 170:           }
 171:           elseif ( $fields )
 172:           {
 173:             $line_out = "";
 174:             $line_fields = $line.Split($script:IN_DELIMITER);
 175:             if ( $only_delimited -and ($line_fields.Length -eq 1) )
 176:             {
 177:               # Skip this line since it didn't contain the delimiter
 178:               continue;
 179:             }
 180:             else
 181:             {
 182:               for($i=1; $i -le $line_fields.Length; $i++)
 183:               {
 184:                 if ( In-Range $i $range )
 185:                 {
 186:                   if ( $line_out.Length ) { $line_out += $script:OUT_DELIMITER; }
 187:                   $line_out += $line_fields[$i-1];
 188:                 }
 189:               }
 190:             }
 191:           }
 192:           $line_out;
 193:         }
 194:       }
 195:     }
 196:   }
 197: }
 198:  
 199: Do-Cut -filespec $filespec -characters $characters -fields $fields `
 200:   -delimiter $delimiter -only_delimited $only_delimited `
 201:   -output_delimiter $output_delimiter;

You can download the script here: Cut.ps1


5 Comments | Email This
  del.icio.us
      

  Tuesday, May 05, 2009 #
  
Confessions Of A Two Week Old iRule Developer
submitted 8 weeks ago

Ian-iRules Every now and then we get some interesting email addressed to us here on the DevCentral team.  Most of the time they are not blog worthy, but yesterday one came in that I thought I needed to share.

Instead of trying to provide some witty commentary, I’m just going pass along what was in the email and leave it to you to comment on.

To: DevCentral
From: Ian
Subject: My First iRule

Hi,

My name is Ian and I’m two weeks old.  I was checking out DevCentral after my father told me all about it and was wondering if you had any iRules tutorials for a slightly younger audience?  I can’t read yet, but if you have some deployments guides in Baby Einstein format or maybe just big blocks that move around, showing how iRules work, that would be awesome.

I’m working on an iRule right now to solve a buffering in my diaper issue I’m having.

I don’t know much about networking, so I’m assuming TCP stands for “The Cr@py P00p”

when CLIENT_ACCEPTED {
  TCP::collect 30
}
when_CLIENT_DATA {
  If { [TCP::payload] > 800 } {
    TCP:: release
    drop
}

I’ll take any feedback on whether you think it will work.

Have a great day

Ian

I usually don’t post stuff like this, but seeing how it’s coming from a 2 weeks old, I figured others out there might get a kick out of it.  Despite his amazing grasp of the English language, I did have to edit some of his words in the sentence right before the iRule in case you were wondering if he knew leet speek on his own.

Enjoy and please pass this along!

-Joe


Add Comment | Email This
  del.icio.us
      

  Monday, May 04, 2009 #
  
Unix To PowerShell - Basename
submitted 8 weeks ago

PowerShell_unix PowerShell is definitely gaining momentum in the windows scripting world but I still hear folks wanting to rely on Unix based tools to get their job done.  In this series of posts I’m going to look at converting some of the more popular Unix based tools to PowerShell.

basename

The Unix “basename” command will delete any prefix up to the last slash (‘/’) character and return the result. 

For my PowerShell implementation, I’ve switched the slash path separator character with the Windows backslash (‘\’) path separator. 

PowerShell does have the Split-Path cmdlet that will parse a path into it’s components.  And with it’s “-Leaf” argument, you can extract the basename equivalent.  My first implementation used this route, but the Split-Path cmdlet didn’t work correctly with relative paths.  More specifically, the Unix command passing in “.” would return “.”.  PowerShell returns the value of the current directory.   I tested out the “-LiteralPath” option but it still required a “-Path” option and would not interpret the “.” or “..” as literal strings.

So, I went ahead and wrote a little reverse string walking loop which turns out to be about 25% faster than using “Split-Path –Leaf”.  I’ve also included in this script a few unit tests I ran to verify the output.

 

   1: #----------------------------------------------------------------
   2: # Dirname.ps1
   3: #----------------------------------------------------------------
   4: param
   5: (
   6:   [string]$name = $null
   7: );
   8:  
   9: $script:SEPARATOR = "\";
  10:  
  11: #----------------------------------------------------------------
  12: # function Do-Basename
  13: #----------------------------------------------------------------
  14: function Do-Basename()
  15: {
  16:   param
  17:   (
  18:     [string]$name = $null
  19:   );
  20:   
  21:   $basename = "";
  22:   
  23:   if ( $name  )
  24:   {
  25:     if ( $name.EndsWith($script:SEPARATOR) )
  26:     {
  27:       $name = $name.SubString(0, $name.Length -1);
  28:     }
  29:     $i = 0;
  30:     for ($i = $name.Length-1; $i -ge 0; $i--)
  31:     {
  32:       if ( $name[$i] -eq $script:SEPARATOR )
  33:       {
  34:         break;
  35:       }
  36:     }
  37:     if ( $i -ge 0 )
  38:     {
  39:       $basename = $name.SubString($i+1)
  40:     }
  41:     else
  42:     {
  43:       $basename = $name;
  44:     }
  45:   }
  46:   $basename;
  47: }
  48:  
  49: #----------------------------------------------------------------
  50: # function Do-BasenameUnitTests
  51: #----------------------------------------------------------------
  52: function Do-BasenameUnitTests()
  53: {
  54:   $tests = @( 
  55:     @("foo", "foo"),
  56:     @("foo\", "foo"),
  57:     @("", ""),
  58:     @("\foo", "foo"),
  59:     @("\foo\", "foo"),
  60:     @("\foo\bar", "bar"),
  61:     @("\foo\bar\", "bar"),
  62:     @("c:\foo", "foo"),
  63:     @("c:\foo\bar", "bar"),
  64:     @("c:\foo\bar\", "bar"),
  65:     @("c:\foo\bar\ ", " "),
  66:     @(".", "."),
  67:     @("..", ".."),
  68:     @(".\", "."),
  69:     @("..\", ".."),
  70:     @("..\.", "."),
  71:     @("..\.\foo", "foo")
  72:   );
  73:   
  74:   $success = "PASS";
  75:   
  76:   "  {0,-15}      {1,-15}       {2,-15}    {3}" -f ("Test", "Expected", "Found", "Pass");
  77:   foreach ($test in $tests)
  78:   {
  79:     $result = Do-Basename $test[0];
  80:     $status = $result -eq $test[1];
  81:     "({0,-15} -> {1,-15}) -> {2,-15} : {3}" -f ("""$($test[0])""", """$($test[1])""", """$($result)""", $status);
  82:     #Write-Host "TEST: (""$($test[0])"" -> ""$($test[1])"") -> ""$result"" : $status";
  83:     if ( ! $status ) { $success = "FAIL"; }
  84:   }
  85:   ""
  86:   "RESULT: $success";
  87: }
  88:  
  89: Do-Basename -name $name;
  90: #Do-BasenameUnitTests;

You can download the full script here: Basename.ps1


2 Comments | Email This
  del.icio.us
      

  Friday, May 01, 2009 #
  
Unix To PowerShell - Cat
submitted 9 weeks ago

PowerShell_unix PowerShell is definitely gaining momentum in the windows scripting world but I still hear folks wanting to rely on Unix based tools to get their job done.  In this series of posts I’m going to look at converting some of the more popular Unix based tools to PowerShell.

cat

The Unix “cat” command is used to concatenate and display files.   Given a file or filename list, it will print the contents of that file to standard output.  There are several options in the Unix command that are implemented with the following PowerShell arguments:

Unix PowerShell Description
-b filespec A file or file matching pattern to concatenate.
-n -number Prefix all output lines with line numbers
-b -number_nonblank Prefix nonblank output lines with numbers.
-E -show_ends display “$” at the end of each line.
-T -show_tabs Display TAB characters as “^I”
-s -squeeze_blanks Never more than one consecutive single blank line
 
   1: #----------------------------------------------------------------
   2: # Cat.ps1
   3: #----------------------------------------------------------------
   4: param
   5: (
   6:   [string]$filespec = $null,
   7:   [bool]$number = $false,  # number output lines
   8:   [bool]$number_nonblank = $false, # Number nonblank output lines
   9:   [bool]$show_ends = $false, # Display $ at end of each line
  10:   [bool]$squeeze_blank = $false, # never more than one single blank line
  11:   [bool]$show_tabs = $false # display TAB characters as ^I
  12: );
  13:  
  14: #----------------------------------------------------------------
  15: # function Do-Cat
  16: #----------------------------------------------------------------
  17: function Do-Cat()
  18: {
  19:   param
  20:   (
  21:     [string]$filespec = $null,
  22:     [bool]$number = $false,  # number output lines
  23:     [bool]$number_nonblank = $false, # Number nonblank output lines
  24:     [bool]$show_ends = $false, # Display $ at end of each line
  25:     [bool]$squeeze_blank = $false, # never more than one single blank line
  26:     [bool]$show_tabs = $false # display TAB characters as ^I
  27:   );
  28:  
  29:   if ( $number_nonblank ) { $number = $false; }
  30:  
  31:   if ( $filespec )
  32:   {
  33:     $files = @(Get-ChildItem $filespec -ErrorAction SilentlyContinue);
  34:     if ( $files.Length –gt 0 )
  35:     {
  36:       $cur_number = 1;
  37:       foreach ($file in $files)
  38:       {
  39:         $content = @(Get-Content -Path $file);
  40:         $last_line = $null;
  41:         
  42:         # iterate through the lines in the file
  43:         for ($i=0; $i -lt $content.Length; $i++)
  44:         {
  45:           $line = $content[$i];
  46:           
  47:           # If sqeezing blanks, if the this and last lines are empty, 
  48:           # continue to next line
  49:           if ( $squeeze_blank )
  50:           {
  51:             if ( ($last_line -ne $null) -and ($last_line.Length -eq 0) -and ($line.length -eq 0) )
  52:             {
  53:               continue;
  54:             }
  55:           }
  56:           
  57:           # Append "$" to ends of lines
  58:           if ( $show_ends )
  59:           {
  60:             $line = $line + "$";
  61:           }
  62:           
  63:           # Replace tabs with "^I"
  64:           if ( $show_tabs )
  65:           {
  66:             $line = $line.Replace("`t", "^I");
  67:           }
  68:           
  69:           # Prefix with numbers.  number_nonblank overrides number