Posts
49
Comments
83
Trackbacks
0
July 2006 Entries
Script to keep all your darned IE RSS subscriptions in sync on all your PCs

The new IE7 is pretty awesome. But to this day I'm amazed at why people continue to think of features in relation to just one computer or a disconnected computer. Its like the phone that isn't connected to the phone network. IE7's RSS features are comprehensive, but if you have more than one machine (laptop, home pc, work pc and so on), you'll quickly find yourself with new subscriptions on each different computer... So here's a little PowerShell one-liner to keep your subscriptions in sync (only works with IE7 installed). First export the current subscription on your first PC:

$feeds = new-object -com Microsoft.FeedsManager
$feeds.RootFolder.Feeds | select Name,Url | export-clixml feeds.xml

Now transfer the file feeds.xml or, whatever you called it, to your second PC and do this:

$feeds = new-object -com Microsoft.FeedsManagerimport-clixml feeds.xml | % { if (!( $feeds.IsSubscribed($_.Url) )) { $feeds.RootFolder.CreateFeed( $_.Name, $_.Url ) } }

There you go. In about 4 lines you can keep your feeds in sync on multiple machines. The obvious questions/extesnsions are a) can this solution be optimized further so that manual copying of the file isn't necessary b) what other interesting things can you do once you access to your feeds :). I've got some ideas and tricks, but I'm saving them for another blog post. Meanwhile, innovate away!

BTW: IE team, nice work on 7. Here's my wishlist: automatic sync'ing between multiple PCs would be killer, add support for highlighting search terms, map CTRL-S to searching the internet with a nice pop-up that could be configured by search providers to show their branding, allow the search box to be moved to more accessible places (fly-out, status bar, floater even). Keep up the great work!

posted @ Friday, July 28, 2006 10:07 PM | Feedback (0)
Sample Code: Calling Exchange cmdlets from .Net code

Now that CDOEXM and WMI providers are gone from Exchange 2007, many custom application developers are probably wondering: "what do I use instead?". The answer is the same as it is for admins who want to move from using CDOEXM/WMI to PowerShell, which is: use the Exchange cmdlets from code.

The PowerShell SDK provides a great set of APIs that will let you host an instance of the PowerShell engine and run cmds / scripts through it. So let's talk about how to code against PowerShell. Think of the PowerShell engine as being similar to the SQL engine. Both engines do specialized jobs, which require a dedicated processing engine. In SQL's case, the processing engine (the database) does all kinds of complicated stuff like joins, sorts, merges, relational queries etc. Well, to access all this good stuff, you need to invoke the database engine---basically you use SQL Command to interact with the engine. PowerShell is very similar: it has lots of specialized logic (pipelines, warning streams, progress streams, errors and so on) that can only be available through the PowerShell engine. Since all the Exchange cmdlets use this good stuff, you need to invoke the PowerShell engine when calling our cmdlets.

Enough talk, here is the sample app (very lightly tested, please use this is a template only).

Important Things to Note:  

You'll note that I don't have any references to Exchange namespaces, except adding the snapin. This is the recommended pattern, see "dealing with PSobject" below. You can also see in the sample that I don't treat the returned data as strong typed data. I deal with everything using "PSObject", which is a generic property bag that PowerShell keeps internally. This is again the recommended pattern. Another reason for dealing with MSHObjects and not casting to a strong type, is that Exchange has not interesting methods on the output classes. That's right---there are no methods on our output classes. The pattern is to use the property collection to find props and set/get them and to use cmdlets to achieve actions (like get/set/add/remove/mount/dismount etc.). The sample assumes an Exchange 2007 installation. Exchange 2007 beta 2 uses Monad RC0, whilst the SDK link above is the newly renamed PowerShell RC1, both are functionally equivalent, however that means that whereever you see PS in the name of a class or type, substitute MSH :)
Caveats:
You may see a 'path cannot be a null' exception when you pass in bad args to the app (and thus to the shell), this is a red herring, its our watson generating code messing up. Fixed in post beta 2 builds. Make sure to quote arguments properly when passing them to the app (and thus to the shell). For example: expshtest 'get-mailbox \"some user with space in their name\" '. Or expshtest 'get-mailboxdatabase \"server1\test db\" ' Make sure to pass in -confirm:$false to Exchange cmdlets that are destructive, or allow the user to pass in that option. Otherwise you'll get a 'host does not support operation' exception from PowerShell (actually right now you get the path cannot be null error. yuck!). This is a super simple app, so make sure to test for null args and so on. I stripped out all the basic stuff to keep the code small.

Sample: 

using System; using System.IO;
using System.Reflection; 
using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Host;

namespace Test
{
 class TestOne
 {
  static void TestCallCmdlet(string args)
  {
   try
   {
           RunspaceConfiguration rc = RunspaceConfiguration.Create();            
          
MshSnapInException snapEx = null;

           MshSnapInInfo info = rc.AddMshSnapIn("Microsoft.Exchange.Management.Msh.Admin", out snapEx);

           Runspace r = RunspaceFactory.CreateRunspace(rc);
           r.Open();
           RunspaceInvoke ri = new RunspaceInvoke(r);
           ICollection results = ri.Invoke( args );
           List mailboxList = new List();

           foreach (MshObject mo in results)
           {
             MshPropertyInfo prop = (MshPropertyInfo)mo.Properties["Name"];
             if (prop != null)
                {
                    Console.WriteLine("Cmdlet: " + args + ",
val: " + prop.Value);
                    mailboxList.Add(prop.Value.ToString());
                }
           }
           ri.Dispose();
           r.Close();
   }
   catch (Exception ex)
   {
    Console.WriteLine(ex.Message.ToString() );
   }
  }

  static void Main(string[] args)
  {
   TestCallCmdlet(args[0]);
  }
 }
}

And here is the step to compile this sample (adjust it to match your install points):   

csc expshtest.cs /r:"c:\Program Files\Microsoft Command Shell\v1\System.Management.Automation.dll"

posted @ Thursday, July 27, 2006 8:07 AM | Feedback (20)
Videos: History behind Exchange Management Shell and some cool demos!

Mihai (awesome lead developer for the Exchange Management Shell) and I did a video series on some of our design decisions as well as the history behind why Exchange partnered with PowerShell/Monad in the first place. The second video has some neat demos that we did---just a little teaser for all of you who want to get Beta 2 (hint, keep watchin msexchangeteam.com for exact details on where to get it). Here are the videos:

 Video: Vivek Sharma and Mihai Jalobeanu on Exchange Management Shell
 Video: Exchange Management Shell in action 

If you have any questions or feedback, please let us know.

posted @ Friday, July 21, 2006 4:07 PM | Feedback (0)
Register for Exchange 2007 Beta

Its almost time. In fact its so close to the beta that you might as well register for it now.Remember, this is how you get to play part in the PowerShell/Exchange scripting contest, try out all the cool new Exchange features (some that will be total suprises... in a good way) and start planning your upgrades. So go register now. Do it. Do it. Do it. Do it. Do it. Ok that was annoying. Do it. :-)  

posted @ Tuesday, July 18, 2006 10:07 PM | Feedback (1)
PowerShell snippet to get perfcounters
Somebody at work asked me whether its possible to get perfcounters through PowerShell. The answer, as with any question directed at this blog, is yes. Here is a little snippet below to do just that. Hint: its possible to compress this to a single line, experiment with passing in arguments to new-object it if you don't want to create a script like the one below:   
param(
$CounterName=$(read-host CounterName),
$CategoryName=$(read-host CategoryName),
$InstanceName=$(read-host InstanceName),
$MachineName="."
) 
## Example CounterName = "% Processor Time"
##         CategoryName = "Processor"
##         "_Total"
##
##   get-perfcounter "Disk Transfers/sec" "PhysicalDisk" "_Total" 

$counter = new-object System.Diagnostics.PerformanceCounter
$counter.CounterName = $CounterName
$counter.CategoryName = $CategoryName
$counter.InstanceName = $InstanceName
$counter.MachineName = $machinename

$counter
posted @ Monday, July 17, 2006 3:07 PM | Feedback (2)
News
A little slow these days as I'm busy working on exchangelabs.com. I will try and post tidbits when I get some time. Enjoy the older posts till then!