Dark Skies for Windows 8 Updated

I’m happy to finally have the next update to Dark Skies in the Windows 8 store!  In the initial release, I used Bing Maps to display light pollution data.  In this version, I allow users to display and share favorite viewing spots, and spruced up the live tile with some cool info. The main page can display information about a pin on the map: Admittedly, there aren’t too many pins just yet, but it will grow over time.   It’s not just favorite viewing locations – astronomy shops, user groups and clubs, and events can all be added.  Also, the live tile now displays some useful moon info: The tile displays the current phase of the moon, as well as the rise and set times (if location services is enabled).  The little + (or –) signs indicates the set or rise occurs on the next or previous day, so for me, the moon rises at 1:14 p.m. and sets tomorrow at 3:45 a.m. Technical Info This is a developer blog, after all.   Everything in this release relies on Windows Azure Mobile Services (WAMS).   The service for the live tiles is hosted in Windows Azure Web Sites, and Windows Azure Mobile Services does the authentication and single-sign on, and also serves notifications when new sites are added.  For example, if there’s a new site added near any of the user’s home locations, a new tile with a Bing map is sent down as a notification, while the badge displays the total number of new nearby points since last run: It’s been a lot of fun to develop, and really, it would’ve been too much work without having WAMS to power everything.   The bulk of the work was getting things to look just right, rather than fiddling with authentication code and developing a back end system.   I’ve also been using TFS in the cloud to store source code, and do continuous integration with the Windows Azure Web Site (an ASP.NET MVC 4 controller that serves XML as tiles.)

Microsoft DevRadio: How to Integrate TFS Projects with Windows Azure Web Sites

Never too late to post!  Here’s an episode of DevRadio Peter and I did on TFS Projects in Azure!   Abstract: Peter Laudati and Brian Hitney are back for today’s show as they show us how we can integrate TFS (Team Foundation Server) projects with Windows Azure Web Sites. They also discuss Windows Azure’s latest price reduction for Storage as well as tee up new features in Windows Azure Mobile Services. After watching this video, follow these next steps:   Step #1 – Try Windows Azure: No cost. No obligation. 90-Day FREE trial. Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8   Subscribe to our podcast via iTunes or RSS   If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Register for our Windows Azure Hands-on Lab Online (HOLO) events today! Windows Azure Hands-on Labs Online   Blogs: Brian Hitney’s blog Peter Laudati’s blog   Videos: Microsoft DevRadio: How to Get Started with Windows Azure Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites? Microsoft DevRadio: (Part 2) Windows Azure Web Sites Explained   Virtual Labs: MSDN Virtual Labs: Windows Azure   Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)  

Scrubbing UserId in Windows Azure Mobile Services

First, many thanks to Chris Risner for the assistance on this solution!   Chris is part of the corp DPE team and has does an extensive amount of work with Windows Azure Mobile Services (WAMS) – including this session at //build, which was a great resource for getting started. If you go through the demo of getting started with WAMS building a TodoList, the idea is that the data in the todo list is locked down to each user.   One of the nice things about WAMS is that it’s easy to enforce this via server side javascript … for example, to ensure only the current user’s rows are returned, the following read script can be used that enforces the rows returned only belong to the current user: function read(query, user, request) { query.where({ userId: user.userId }); request.execute(); } If we crack open the database, we’ll see that the userId is an identifier, like the below for a Microsoft Account: MicrosoftAccount:0123456789abcd When the app connects to WAMS, the data returned includes the userId … for example, if we look at the JSON in fiddler: The app never displays this information, and it is requested over SSL, but it’s an important consideration and here’s why.   What if we have semi-public data?   In the next version of Dark Skies, I allow users to pin favorite spots on the map.  The user has the option to make those points public or keep them private … for example, maybe they pin a great location for stargazing and want to share it with the world: … Or, maybe the user pins their home locations or a private farm they have permission to use, where it might be inappropriate to show publically. Now here comes the issue:  if a location is shared publically, that userId is included in the JSON results.  Let’s say I launch the app and see 10 public pins.  If I view the JSON in fiddler, I’ll see the userId for each one of those public pins – for example: Now, the userId contains no personally identifiable information.   Is this a big deal, then?   It’s not like it is the user’s name or address, and it would only be included in spots the user is sharing publically anyway. But, if a hacker ever finds a way to map a userId back to a specific person, this is a security issue.  Even my app doesn’t know who the users really are, it just knows the identifier.  Still, I think from a best practice/threat modeling perspective, if we can scrub that data, we should.  Note: this issue doesn’t exist with the todo list example, because the user only, and ever, sees their own data. Ideally, what we’d like to do is return the userId if it’s the current user’s userId.  If the point belongs to another user, we should scrub that from the result set.   To do this via a read script in WAMS, we could do something like: function read(query, user, request) { request.execute( { success: function(results) { //scrub user token if (results.length > 0) { for (var i=0; i< results.length; i++) { if (results[i].UserId != user.userId) { results[i].UserId = 'scrubbeduser'; } } } request.respond(); } }); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }If we look at the results in fiddler, we’ll see that I’ll get my userId for any of my points, but the userId is scrubbed if it’s another user’s points that are shared publically: [Note: these locations are random spots on the map for testing.] Doing this is a good practice.  The database of course has the correct info, but the data for public points is guaranteed to be anonymous should a vulnerability ever present itself.   The downside of this approach is the extra overhead as we’re iterating the results – but, this is fairly minor given the relatively small amounts of data. Technical point:  In my database and classes, I use Pascal case (as a matter of preference), as you can see in the above fiddler captures, such as UserId.   In the todo example and in the javascript variables, objects are conventionally camel case.   So, if you’re using any code here, just be aware that case does matter in situations like this: if (results[i].UserId != user.userId) // watch casing! .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Be sure they match your convention.   Since Pascal case is the standard for properties in C#, and camel case is the standard in javascript, properties in .NET can be decorated with the datamember attribute to make them consistent in both locations – something I, just as a matter of preference, prefer not to do: [DataMember(Name = "userId")] public string UserId { get; set; }

Calling Stored Procedures from Windows Azure Mobile Services

I was surprised, yet delighted, that Windows Azure Mobile Services uses a SQL database.   Schema-less table storage has its place and is the right solution at times, but for most data driven applications, I’d argue otherwise. In my last post, I wrote about sending notifications by writing the payload explicitly from a Windows Azure Mobile Service.   In short, this allows us to include multiple tiles in the payload, accommodating users of both wide and square tiles.   In my application, I want to execute a query to find push notification channels that match some criteria.  If we look at the Windows Azure Mobile Services script reference, the mssql object allows us to query the database using T-SQL and parameters, such as: mssql.query('select top 1 * from statusupdates', { success: function(results) { console.log(results); } }); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }In my case, the query is a bit more complicated.  I want to join another table and use a function to do some geospatial calculations – while I could do this with inline SQL like in the above example, it’s not very maintainable or testable.  Fortunately, calling a stored procedure is quite easy. Consider the following example:  every time the user logs in, the Channel URI is updated.  What I’d like to do is find out how many new locations (called PointsOfInterest) have been modified since the last time the user has logged in.  To do that, I have a stored procedure like so: create procedure [darkskies].[NewLocationsForChannel] ( @channelUri as nvarchar(512) = null ) as select c.ChannelUri, count(1) as NumNewLocations from darkskies.Channel c inner join darkskies.PointOfInterest p on c.UserId = p.UserId where p.LastUpdated > c.LastUpdated and c.ChannelUri = @channelUri group by c.ChannelUri .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Writing something like that inline to the mssql object would be painful.   As a stored procedure, it’s much easier to test and encapsulate.  In my WAMS script, I’ll call that procedure and send down a badge update: function updateBadge(channelUri) { var params = [channelUri]; var sql = "exec darkskies.NewLocationsForChannel ?"; mssql.query(sql, params, { success: function(results) { if (results.length > 0) { for (var i=0; i< results.length; i++) { if (results[i].ChannelUri !== null && results[i].ChannelUri.length > 0) { push.wns.sendBadge(results[i].ChannelUri, results[i].NumNewLocations); } } } } }); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }This section of code only updates the badge of the Windows 8 Live Tile, but it works out nicely with tile queuing: Note: this app is live in the Windows 8 Store, however, at the time of this writing, these features have not yet been released.  In the next few posts, we’ll look at the notifications a bit more, including how to pull off some geospatial stuff in WAMS.

Best Practice for Sending Windows 8 Tiles from Mobile Services

Those that know me know I am not a fan of javascript, in pretty much all of its forms (including node.js), however, I’m really digging Windows Azure Mobile Services (WAMS).  WAMS allows you to easily provide a back end to applications for storing data, authenticating users, and supporting notifications on not just Windows and Windows Phone, but also iOS with future plans of supporting Android soon. Now, I mention javascript because WAMS provides a slick node-like powered data service that makes it really easy to store data in the cloud.  The ToDoList example exercise illustrates the ease at storing user data in the cloud and hooking it up with authentication and notification support.   The nice thing about the authentication is that it’s easily integrated into the backend: But, more on this later.  Right now, I want to deal with notifications in WAMS.  In WAMS, you have the opportunity to right custom server-side javascript to do things like send notifications on insert/update/delete/read access: In my case, I want to send a tile update if the new data meets some criteria.   Let’s start all the way down the code and work our way out, starting with the notification piece.    One page you MUST have bookmarked is the tile template catalog on MSDN.   This page defines the XML syntax for all possible tiles your tile can have, including both small/square tiles, and large/wide tiles.    All of these have a defined schema, such as this for TileSquarePeekImageAndText04: <tile> <visual> <binding template="TileSquarePeekImageAndText04"> <image id="1" src="image1" alt="alt text"/> <text id="1">Text Field 1</text> </binding> </visual> </tile> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Which produces a tile that “peeks”, such as this (which flips between the top half and bottom half): Yes, it’s easy to laugh at the magic “04” in the template title.  I like to joke that my personal favorite is TileWideSmallImageAndText03.   But, there variety is crucial to creating the ideal app experience and that depends on how you want to display the data -- and that requires knowing the XML template. Now, in WAMS, there’s a great tutorial on sending some basic notifications.   In that walkthrough, a notification is sent via the server-side javascript like so: push.wns.sendTileSquareText02(“https://bn1.notify.windows.com?[snip]”, { text1: “some text”, text2: “more text”}); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Now, at first glance, this is very nice because WAMS will write the XML for you.  However, you still must know what data the template requires.  Does it need an image?  One text line?  Two?   You get the point.  Unsurprisingly, calling that method will generate XML like: <tile> <visual> <binding template="TileSquareText02"> <text id="1">some text</text> <text id="2">more text</text> </binding> </visual> </tile> You can learn more about this in the WAMS script reference.  Another must-have bookmark.  However, I recommend you don’t use these at all, and instead write the XML payload directly.   This is for a few reasons, but primarily, it’s for control – and, really, you have to know the fields required anyway and you’ll still have the tile catalog page open for reference. In looking at the mpns (Microsoft Push Notification Service) library a bit closer (awesome job by the guys, by the way) up on git, it has this method: var raw = new mpns.rawNotification('My Raw Payload', options); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } When developing my app, I realized I had no idea what tile size the user has.   Some may opt to use a wide tile, others a small tile.  I needed different tiles to support both.   I didn’t like sending two notifications (seems wasteful, doesn’t it?) and to do this efficiently, it’s easier to just create the payload explicitly that includes all tiles.  For example, this includes two completely different tiles: var payload = "<tile><visual><binding template='TileWideImageAndText02'>" + "<image id='1' src='" + xmlEscape(bigImage) + "' alt='map'/>" + "<text id='1'>" + text1 + "</text>" + "<text id='2'>" + text2 + "</text>" + "</binding>" + "<binding template='TileSquareImage' branding='none'>" + "<image id='1' src='" + xmlEscape(smallImage) + "' alt='map'/></binding></visual></tile>"; push.wns.send(channelUri, payload, 'wns/tile', { client_id: 'ms-app://<snip>', client_secret: 'i will never tell', headers: { 'X-WNS-Tag' : 'MainTile' } }... .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Sure, it doesn’t look as clean and (gasp!) we have to do string concatenation.   But, it’s only a couple of minutes more work and just more flexible.  Like I said: either way, you need to know the template.   In my case, I’m sending both notifications in one payload.  The first is TileWideImageAndText02, which produces a nice image with the text on the bottom describing the image.  If the user has a small tile, it will use TileSquareImage, which basically just forgoes the text and just displays the image.  After trying a few, I settled on this combination as the best user experience.  This is an easy way, with minimal effort, to support both wide and narrow tiles. As an aside, I recommend setting the tag (X-WNS-Tag) header, particularly if your app cycles tiles and you want to replace a specific tile.  Also, it’s a good ideal to XML escape all data, which I’m doing with the long image URLs … and this, I believe, is taken right from the mpns library: var xmlEscape = function (text) { return text.replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;') .replace(/"/g, '&quot;'); } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } If you don’t escape the data and have some illegal chars in there as a result, the notification gets sent correctly (that is, accepted), but gets ignored by the client. Now that I’ve got the basic code to send a tile, I needed to filter some data and run a query and sort users by distance.  Sound like fun?  I’ll write about that next…

Rock, Paper, Azure Re-launch!

I’m a little late getting this out (pesky vacations and all) but we re-launched Rock, Paper, Azure (RPA) a few weeks back with weekly competitions! What is Rock, Paper, Azure?  In short, it’s a game, primarily for developers.  It’s also a fun way to learn programming, as the concept is simple however winning is not.  You write code that plays a modified Rock, Paper, Scissors like game and tries to beat everyone else doing the same.   The code that you download has everything ready to go, so you just need to worry about implementing some logic.  No advanced degree required! We developed RPA as a teaching tool for the cloud.   The RPA site and game engine all run in Windows Azure, and it’s a good example of building a scalable application:  when the game engine is under demand, such as during our prize rounds, we’ve been able to scale up to keep up with the bot submissions.   As a player, you’ll get to try out Windows Azure and learn a little about it along the way.  You can also win some great stuff – like a Microsoft Surface, Kinect, and Best Buy gift cards! Check it out at http://www.rockpaperaure.com – have fun playing!

Azure this Week!

Lots of things going on in Windows Azure this week!  First up, I’ll be presenting at the TRINUG on Windows Azure on Wednesday, Nov. 14th 2012 .   If you’re in the area, stop by! This Wednesday, the corp team is also holding a Windows Azure conference appropriately named Windows Azure Conf,  be sure to check it out.    The event will be streamed online via Channel 9 and include a keynote from ScuttGu: On November 14, 2012, Microsoft will be hosting Windows AzureConf, a free event for the Windows Azure community. This event will feature a keynote presentation by Scott Guthrie, along with numerous sessions executed by Windows Azure community members. Streamed live for an online audience on Channel 9, the event will allow you to see how developers just like you are using Windows Azure to develop applications on the best cloud platform in the industry. Community members from all over the world will join Scott in the Channel 9 studios to present their own inventions and experiences. Whether you’re just learning Windows Azure or you've already achieved success on the platform, you won’t want to miss this special event. Here’s a rundown of the schedule!

Microsoft DevRadio: (Part 1) What is Windows Azure Web Sites?

Peter Laudati and Brian Hitney welcome Windows Azure Technical Evangelist Brady Gaster to the show as they discuss Windows Azure Web Sites. In part one of this series, tune in as they chat about what it is, what its key benefits are for web developers and agencies, how the Azure Web Sites infrastructure works for easier site deployment, an intro to the web sites gallery, as well as a special announcement for .NET applications. After watching this video, follow these next steps: Step #1 – Start Your Free 90 Day Trial of Windows Azure Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes, Zune, or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Websites: Learn more about Windows Azure Blogs: Brian Hitney’s blog Peter Laudati’s blog Brady Gaster’s blog Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)

Microsoft DevRadio: How to Get Started with Windows Azure

Peter Laudati and I kick off our new Windows Azure series by giving us a tour of what’s new in Azure with Windows Azure Web sites, Virtual Machines and Mobile Services. Tune in as we provide a brief overview of Azure’s many services and features as well as how to get started with a free 90 day trial. After watching this video, follow these next steps: Step #1 – Start Your Free 90 Day Trial of Windows Azure Step #2 – Download the Tools for Windows 8 App Development Step #3 – Start building your own Apps for Windows 8 Subscribe to our podcast via iTunes, Zune, or RSS If you're interested in learning more about the products or solutions discussed in this episode, click on any of the below links for free, in-depth information: Websites: Learn more about Windows Azure Blogs: Brian Hitney’s blog Peter Laudati’s blog Virtual Labs: MSDN Virtual Labs: Windows Azure Download MP3 (Audio only) MP4 (iPod, Zune HD) High Quality MP4 (iPad, PC) Mid Quality MP4 (WP7, HTML5) High Quality WMV (PC, Xbox, MCE)

Using PowerShell to Manage Windows Azure Applications

I was recently asked to do a presentation on managing Windows Azure applications with PowerShell by the Charlotte PowerShell users group.   At first I was a bit unsure about doing the presentation – with Jim Christopher and Ed Wilson in the group as well as other PowerShell gurus, it can be tough to ramp up to a respectable level of knowledge.  But, these guys are awesome and Ed welcomed me to pen a blog post for them, so check it out on the Hey, Scripting Guy! blog. I learned a ton in the process.  While I knew there were the Azure PowerShell cmdlets to aid in virtually everything you  can do via the management interface, getting hands on and really putting it through the paces still wows me at what you can do with PowerShell. In the blog post, an sample website is deployed to two different datacenters, and then load balanced geographically using the Traffic Manager.  Instances can be easily altered, storage accounts created, etc.  And then, finishing it with only a few lines a code to tear it all down.    All in all, it integrates really nicely with any application lifecycle process. Check out the post and try the code out for yourself!

My Apps

Dark Skies Astrophotography Journal Vol 1 Explore The Moon
Mars Explorer Moons of Jupiter Messier Object Explorer
Brew Finder Earthquake Explorer Venus Explorer  

My Worldmap

Month List