Get-Tweet

Since I find myself spending so much time in a PowerShell console, I’m always trying to find ways to stay. I recently posted my version of a PowerShell script to send a message to Twitter. But that’s only half the story.  If I want to check for recent tweets I have to switch to Firefox and the use the Twitterfox addon. But since everything in Twitter comes via a web page or RSS feed, it is pretty simple to use the System.Net.Webclient class in a PowerShell script to get what I want. To that end I wrote a function called Get-Tweet to return recent tweets. You can download the file here.

Function Get-Tweet {

    #check for global Twitter credential
if (!$global:Twitter_Credential) {
$global:Twitter_Credential=Get-Credential
}

    #check for last tweet check
if ($global:Tweet_Check) {
[datetime]$since=$global:Tweet_Check
}
else {
#if not found then calculate the date 6 hours ago
[datetime]$since=(Get-Date).AddHours(-6)
}
#convert to GMT and a string
[string]$sinceGMT=$since.ToUniversalTime().ToString()
#replace AM or PM with GMT
if ($sinceGMT.EndsWith(“AM”)) {
$sinceGMT=$sinceGMT.Replace(“AM”,”GMT”)
}
else {
$sinceGMT=$sinceGMT.Replace(“PM”,”GMT”)
}
#construct URL
[string]$urlbase=”http://twitter.com/statuses/friends_timeline.rss?since={0}”
[string]$url=$urlbase -f $sinceGMT
#this line is optional, but informational
Write-Host “Downloading $url [$since]” -foregroundcolor CYAN
#create web client
$webclient=New-Object “System.Net.WebClient”
#create network credential
$username=$global:Twitter_Credential.GetNetworkCredential().Username
$password=$global:Twitter_Credential.GetNetworkCredential().Password
$webclient.credentials = New-Object System.Net.NetworkCredential($username,$password)
#retrieve RSS file and store as an XML object
[xml]$tweets=$webclient.DownloadString($url)
#parse RSS/XML and write to the pipeline
#only keep tweets that are newer than the last Tweet Check
$tweets.rss.channel.item |
where {($_.pubDate -as [datetime]) -gt $global:Tweet_Check} | select `
@{name=”Twitted”;Expression={
#convert to a datetime object
$_.pubDate -as [datetime]}},`
@{name=”Twitter”;Expression={
#parse out the friend name
$t=$_.title
$t.substring(0,$t.indexof(“:”))}}, `
@{name=”Tweet”;Expression={
#parse out the message
$t=$_.title
$t.substring($t.indexof(“:”)+1).Trim()}}
#store datetime for last tweet check
$global:Tweet_Check = Get-Date
}

This function uses the same stored Twitter credential that I use in Out-Twitter. If it doesn’t exist, you’ll get prompted for your Twitter username and password which is then stored as a global variable.

if (!$global:Twitter_Credential) {
$global:Twitter_Credential=Get-Credential
}

I designed the function to only return tweets that were posted since the last time the function checked. The last time is stored as a global variable Tweet_Check.

if ($global:Tweet_Check) {
[datetime]$since=$global:Tweet_Check
}
else {
#if not found then calculate the date 6 hours ago
[datetime]$since=(Get-Date).AddHours(-6)
}
If the variable doesn’t exist then I’ll set my cut off time to 6 hours earlier. The URL I’m going to access requires a date parameter in GMT. It takes a few steps to convert the $since [datetime] object to a properly formatted GMT timestamp.

[string]$sinceGMT=$since.ToUniversalTime().ToString()
#replace AM or PM with GMT
if ($sinceGMT.EndsWith(“AM”)) {
$sinceGMT=$sinceGMT.Replace(“AM”,”GMT”)
}
else {
$sinceGMT=$sinceGMT.Replace(“PM”,”GMT”)
}

Constructing the URL and WebClient object is similar to what I do in the Out-Twitter function. The current tweets are downloaded and stored as an [xml] object.

[xml]$tweets=$webclient.DownloadString($url)   

All that is left is to parse the XML. There’s a lot going on here so let me break it down. Every tweet is an item node in the XML document. One of the properties is pubDate which is when the tweet was posted. I pipe the item to Where-Object which compares the pubDate property recast as a [datetime] to the $tweet_check variable.

$tweets.rss.channel.item |
where {($_.pubDate -as [datetime]) -gt $global:Tweet_Check}

This will filter out older tweets. These objects are then piped to Select-Object. I essentially create a custom object by using a hashtable to create new properties from the incoming object. The first property, Twitted, is the pubDate property re-cast as a [datetime] object.

| select `
@{name=”Twitted”;Expression={
#convert to a datetime object
$_.pubDate -as [datetime]}},`

I did this so that I could sort on this property if  necessary and it would sort as a date and not a string. The title property includes both the friend name and the tweet.

<title>jonwalz: @halr9000 -is presenting at the PowerShell Virtual User Group meeting. W00t!</title>

Since I might want to sort or filter further on the friend name, I parsed out the friend name by using the SubString() method to parse out everything up to the first colon.

@{name=”Twitter”;Expression={
#parse out the friend name
$t=$_.title
$t.substring(0,$t.indexof(“:”))}},

I also parse out the message in much the same way.

@{name=”Tweet”;Expression={
#parse out the message
$t=$_.title
$t.substring($t.indexof(“:”)+1).Trim()}}

The function ends by storing a new value for $Tweet_Check.

To use the function once it is loaded into your PowerShell session is as simple as calling Get-Tweet. However I find it helpful to add a little formatting:

get-tweet | format-table -autosize -wrap

Because objects are written to the pipeline, this allows you to do other things such as filtering out your own tweets:

get-tweet | where {$_.twitter -notmatch “JeffHicks”} | format-table -auto -wrap

Or maybe you only want to see tweets from a given friend:

get-tweet | where {$_.twitter match “halr9000”} | format-table Twitted,Tweet -autosize -wrap

To make it even easier (more efficient, lazier, etc) I define a script block in my profile:

$tw={get-tweet | where {$_.twitter -notmatch “JeffHicks”} | sort “Twitted” |format-table -autosize -wrap}

Whenever I want to see the latest tweets all I have to do is invoke $tw

PS C:\> &$tw

You may not use Twitter, but the techniques I’m using here can work with any web based XML or RSS feed. Maybe there’s another site you’d like to scrape and quickly display in PowerShell. I actually have another idea or two.  Now, if I could get PowerShell to make coffee and let the dog out….

Don’t forget, you can follow me on Twitter @JeffHicks. I hope you will.