<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Media And Microcode : Sort-Object</title><link>http://blogs.msdn.com/mediaandmicrocode/archive/tags/Sort-Object/default.aspx</link><description>Tags: Sort-Object</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>Microcode: Scripting RSS Feeds with PowerShell and Microsoft.FeedsManager</title><link>http://blogs.msdn.com/mediaandmicrocode/archive/2008/11/11/microcode-scripting-rss-feeds-with-powershell-and-microsoft-feedsmanager.aspx</link><pubDate>Tue, 11 Nov 2008 04:34:53 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9059055</guid><dc:creator>JamesBrundage</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/mediaandmicrocode/comments/9059055.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mediaandmicrocode/commentrss.aspx?PostID=9059055</wfw:commentRss><description>&lt;p&gt;PowerShell's an amazing glue language.&amp;#160;&amp;#160; It can help you bring code from all corners of the earth into one environment, and then you can custom the code to be more to your liking.&amp;#160; While the last several entries of my blog have spent time looking at what we can glue together with .NET, this one shows you how you can bring COM into the mix.&lt;/p&gt;  &lt;p&gt;Internet Explorer has an RSS feed manager which you can script in .NET.&amp;#160; While the command line might not be the ideal spot to read your blogs, it's possible to make a much nicer front end by scripting WPF &amp;amp; PowerShell, and having a quick and easy API to get at your RSS feeds makes building applications that use RSS feeds as a way to synchronize information between multiple machines.&lt;/p&gt;  &lt;p&gt;The object that makes this all work is &lt;a href="http://msdn.microsoft.com/en-us/library/ms684749.aspx"&gt;Microsoft.FeedsManager&lt;/a&gt;, and the cmdlet that makes working with it possible is &lt;a href="http://technet.microsoft.com/en-us/library/bb978545.aspx"&gt;New-Object&lt;/a&gt;.&amp;#160; By default, New-Object will create a new .NET object from the classes that are currently loaded by .NET (for more on this, see my previous posts about &lt;a href="http://blogs.msdn.com/mediaandmicrocode/archive/2008/10/23/microcode-powershell-scripting-tricks-exploring-net-types-with-a-get-type-function-and-reflection.aspx"&gt;Get-Type&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/mediaandmicrocode/archive/2008/11/08/microcode-exploring-more-of-net-with-get-assembly.aspx"&gt;Get-Assembly&lt;/a&gt;).&amp;#160; While .NET is a fairly easy world to explore, COM is considerably more tricky.&lt;/p&gt;  &lt;p&gt;Luckily, COM objects are the main backbone of VBScript.&amp;#160; This is an important point for VBScripters trying to learn PowerShell: while the world of .NET may be new and exotic, and Cmdlets might be cool, you don't have to drop your VBScript knowledge at the door.&amp;#160; While some of a VBScript (e.g. strings) will require new learning in PowerShell, the vast majority of it doesn't.&lt;/p&gt;  &lt;p&gt;Microsoft.FeedsManager is one of these examples.&amp;#160; I found out about this object by looking at the source code for the RSS reader vista sidebar gadget, and, once I knew its name, I knew how to get at it in PowerShell.&amp;#160; Even though I was looking at javascript, I knew that there was a scriptable COM object there to help me out, and I knew how to bring it into PowerShell. &lt;/p&gt;  &lt;p&gt;To create a Microsoft.FeedsMananger, simply use this one liner:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;New-Object -comObject Microsoft.FeedsManager&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Since the root folder looks promising, let's explore that:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;(New-Object -comObject Microsoft.FeedsManager).RootFolder&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;While I can just save this into a variable and script it like I were still in VBScript land (e.g. $feeds = New-Object -comObject Microsoft.FeedsManager, $feeds.RootFolder), I far prefer the parlance of PowerShell, so I'll make a quick Get-Feed function to explore feeds more easily.&amp;#160; I'll accept a wildcard for the name or title of the feed, and, since the feeds can have an arbitrary number of subfolders, I'll add a -recurse parameter.&amp;#160; In order to make -recurse work elegantly, I'll use a short recursive script and I'll add a $folder parameter, which can be null and will be assumed to be the root folder.&amp;#160; Finally, since I'll often want to read the items more than the feed, I'll add a switch parameter to extract the articles.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;function Get-Feed($feed = &amp;quot;*&amp;quot;, $folder, [switch]$recurse, [switch]$articles) {&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if (! $folder) {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $feedsManager = New-Object -ComObject Microsoft.FeedsManager&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $folder = $feedsManager.RootFolder&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; $folder.Feeds |         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Where-Object {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; ($_.Title -like &amp;quot;$feed&amp;quot;) -or ($_.Name -like &amp;quot;$feed&amp;quot;)         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } | Foreach-Object {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if ($articles) { $_.Items } else { $_ }         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; if ($recurse) {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $folder.Subfolders | Foreach-Object {         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Get-Feed $feed $_ -recurse -articles:$articles         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }         &lt;br /&gt;}&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Once I've defined Get-Feed, I can use it to search my feeds through PowerShell.&amp;#160; This one liner will get my all my feeds, sort them by name, and display just the Name and URL:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Get-Feed -recurse | Sort-Object Name | Select-Object Name, URL &lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;To see all of the feed items sort them by when they were published, and display the post title, the blog title, and the publish date, you can use this pipeline:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Get-Feed -articles -recurse |        &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Sort-Object PubDate -descending |         &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; Select-Object Title, @{Name='Blog'; Expression={$_.Parent.Title }}, PubDate&lt;/em&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;I promise that we can do much more with RSS and PowerShell, but hopefully this post will get you started down the path of using the FeedsManager from PowerShell.&lt;/p&gt;  &lt;p&gt;Hope this helps,&lt;/p&gt;  &lt;p&gt;James Brundage [MSFT]&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;table border="1"&gt;&lt;theader&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td&gt;&lt;strong&gt;Module Name&lt;/strong&gt;&lt;/td&gt;        &lt;td&gt;&lt;strong&gt;Scripts&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt; &lt;/theader&gt;&lt;/tbody&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td&gt;&lt;a href="http://cid-2b8a402d0ba15e82.skydrive.live.com/browse.aspx/PowerShell%20Scripts/RSS"&gt;RSS&lt;/a&gt;&lt;/td&gt;        &lt;td&gt;&lt;a href="http://cid-2b8a402d0ba15e82.skydrive.live.com/self.aspx/PowerShell%20Scripts/RSS/Get-Feed.ps1"&gt;Get-Feed&lt;/a&gt;&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9059055" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Microcode/default.aspx">Microcode</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Select-Object/default.aspx">Select-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Sort-Object/default.aspx">Sort-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Get-Feed/default.aspx">Get-Feed</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/New-Object/default.aspx">New-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Microsoft.FeedsManager/default.aspx">Microsoft.FeedsManager</category></item><item><title>Microcode: Scripting Tricks : Exploring WPF Routed Events with PowerShell</title><link>http://blogs.msdn.com/mediaandmicrocode/archive/2008/10/20/microcode-scripting-tricks-exploring-wpf-routed-events-with-powershell-and-get-member-where-object-and-group-object.aspx</link><pubDate>Mon, 20 Oct 2008 03:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9006725</guid><dc:creator>JamesBrundage</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/mediaandmicrocode/comments/9006725.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mediaandmicrocode/commentrss.aspx?PostID=9006725</wfw:commentRss><description>&lt;P&gt;Both WPF and PowerShell are both full of great little touches.&amp;nbsp; One of WPF's nice touches is &lt;A href="http://msdn.microsoft.com/en-us/library/ms742806.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms742806.aspx"&gt;Routed Events&lt;/A&gt;.&amp;nbsp; Routed Events allow you to capture events raised by child controls or parent controls.&amp;nbsp; This can be incredibly useful, because it allows you write less code (which I believe is generally good) by re-using handlers.&lt;/P&gt;
&lt;P&gt;A good example of why you might want to do this is wanting to have more than one button in a user interface that updates a database.&amp;nbsp; What each button might do may be different, but they all to connect to a database.&amp;nbsp; This means you could write either write three longer (and less portable) methods that connect to the database and perform an operation, or three shorter ( and more portable ) methods that just perform the operation on a database and one operation that connects to the database.&amp;nbsp;&amp;nbsp; By having each of the buttons go through a routed event on a container, you can write one short routing handler that connects to the database, looks at where the message came from, and performs the operation.&lt;/P&gt;
&lt;P&gt;WPF comes with an amazing number of controls, and a pretty nice selection of Routed Events.&amp;nbsp; The WPF team was event nice enough to have a manager for these routed events, which means that we can explore them dynamically using PowerShell.&lt;/P&gt;
&lt;P&gt;The event manager is available in the class &lt;A href="http://msdn.microsoft.com/en-us/library/system.windows.eventmanager(VS.85).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.eventmanager(VS.85).aspx"&gt;System.Windows.EventManager&lt;/A&gt;.&amp;nbsp; Let's start exploring it with PowerShell.&amp;nbsp; To do this, make sure you've loaded the WPF assembly into PowerShell&amp;nbsp; by using the line [Reflection.Assembly]::LoadWithPartialName("PresentationCore"). We can omit the System namespace when referring to a type in PowerShell, so we can call it [Windows.EventManager] from now on.&amp;nbsp; We can use Get-Member -static to see what this class can do.&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;[Windows.EventManager] | Get-Member -static&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;It has the following methods:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Equals (every .NET object has this static member) &lt;/LI&gt;
&lt;LI&gt;GetRoutedEvents()&lt;/LI&gt;
&lt;LI&gt;GetRoutedEventsForOwner(Type ownerType)&lt;/LI&gt;
&lt;LI&gt;ReferenceEquals (every .NET object has this static member)&lt;/LI&gt;
&lt;LI&gt;RegisterClassHandler (Type classType, RoutedEvent routedEvent, Delegate handler)&lt;/LI&gt;
&lt;LI&gt;RegisterClassHandler (Type classType, RoutedEvent routedEvent, Delegate handler, Boolean handledEventsToo)&lt;/LI&gt;
&lt;LI&gt;RegisterRoutedEvent(String name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Since I'm just exploring, GetRoutedEvents() is the method I'm interested in.&lt;/P&gt;
&lt;P&gt;I can see every routed event with the simple PowerShell one-liner:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;[Windows.EventManager]::GetRoutedEvents()&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Of course we can pipe that to Get-Member in order to see what we've got for every Routed Event:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;[Windows.EventManager]::GetRoutedEvents() | Get-Member&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;It's more interesting to me to figure out what events I can bubble up to the parent controls.&amp;nbsp; Since each &lt;A href="http://msdn.microsoft.com/en-us/library/system.windows.routedevent.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.routedevent.aspx"&gt;RoutedEvent&lt;/A&gt; has a &lt;A href="http://msdn.microsoft.com/en-us/library/system.windows.routedevent.routingstrategy.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.routedevent.routingstrategy.aspx"&gt;RoutingStrategy&lt;/A&gt; property, I can write this as a simple filter using Where-Object:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;[Windows.EventManager]::GetRoutedEvents() | Where-Object { $_.RoutingStrategy -eq "Bubble"&lt;/EM&gt;&lt;EM&gt;} | Sort-Object Name&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Since each RoutedEvent also has a &lt;A href="http://msdn.microsoft.com/en-us/library/system.windows.routedevent.handlertype.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.windows.routedevent.handlertype.aspx"&gt;HandlerType&lt;/A&gt; property, I can also see what types of different handlers exist by using&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;[Windows.EventManager]::GetRoutedEvents() | Group-Object HandlerType | Sort-Object Count -descending&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Finally, I can use the EventManager to help guess about what types of controls could fit the bill for whatever I need to do. The next one liner gives me all of the routed events that work with Drag and Drop&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;[Windows.EventManager]::GetRoutedEvents() | Where-Object {$_.Name -like "*Drag*" -or $_.Name -like "*Drop*" }&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Associating these events with a class needs to use some tricks of reflection.&amp;nbsp; In the sample below, I'll look for all drag and drop handlers within PresentationBase (where the EventManager and some base components live) and PresentationFramework (where most of the built-in WPF controls reside):&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;EM&gt;$handlers = [Windows.EventManager]::GetRoutedEvents() | &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Where-Object { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; $_.Name -like "*Drag*" -or $_.Name -like "*Drop*" &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;$assemblies = [Windows.EventManager].Assembly, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [Windows.Window].Assembly &lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;$assemblies | Foreach-Object { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $_.GetTypes() | Where-Object { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; foreach ($handler in $handlers) { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if ($_.GetEvent($handler.Name)) { &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return $true &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;BR&gt;}&lt;/EM&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The script above takes a bit of explaining.&lt;/P&gt;
&lt;P&gt;I store the Drag and Drop handlers into a variable, and store the assemblies I wanted to search in another variable (to search all of my currently loaded types for these handlers, I'd use just assign $assemblies to &lt;EM&gt;[AppDomain]::CurrentDomain.GetAssemblies()&lt;/EM&gt;).&amp;nbsp; Then I go through each assembly, retrieve the types, and pipe them into Where-Object, which will determine if they meet my criteria.&amp;nbsp; I go through each class and each handler that met my criteria, and use the &lt;A href="http://msdn.microsoft.com/en-us/library/system.type.getevent(VS.71).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.type.getevent(VS.71).aspx"&gt;GetEvent&lt;/A&gt; method (which is defined on any .NET type definition) to determine if the event is present.&amp;nbsp; If the event is present, I return $true, which makes the Where-Object output the type.&amp;nbsp; If the event's not present, then code will go onto the next handler and the next type.&lt;/P&gt;
&lt;P&gt;These are just a few examples of the ways you can use PowerShell to explore WPF routed events.&amp;nbsp; The techniques used in this post can be used on to explore just about any .NET type.&amp;nbsp; Exploring .NET through reflection is a great way to save time looking things up, and the pathway to using existing .NET code to solve a problem rather than reinventing the wheel.&lt;/P&gt;
&lt;P&gt;Hope this helps,&lt;/P&gt;
&lt;P&gt;James Brundage [MSFT]&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9006725" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/PowerShell/default.aspx">PowerShell</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Sort-Object/default.aspx">Sort-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Group-Object/default.aspx">Group-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Scripting+Tricks/default.aspx">Scripting Tricks</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/WPF/default.aspx">WPF</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Where-Object/default.aspx">Where-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Get-Member/default.aspx">Get-Member</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/.NET/default.aspx">.NET</category></item><item><title>Microcode: Cleaning up DVR with Get-RecordedTV</title><link>http://blogs.msdn.com/mediaandmicrocode/archive/2008/07/21/microcode-cleaning-up-dvr-with-get-recordedtv.aspx</link><pubDate>Mon, 21 Jul 2008 03:51:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8759886</guid><dc:creator>JamesBrundage</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/mediaandmicrocode/comments/8759886.aspx</comments><wfw:commentRss>http://blogs.msdn.com/mediaandmicrocode/commentrss.aspx?PostID=8759886</wfw:commentRss><description>&lt;p&gt;The first simple way we can approach cleaning up DVR is by making the assertion that shows you don't want as much you won't record as often.&amp;#160; Suppose you record a movie once, or a game, or the pilot of a really bad TV show.&amp;#160;&amp;#160; After a month or so it's still on your hard drive, taking up space but for some reason avoiding the Windows Media Center's cleanup bots.&lt;/p&gt;  &lt;p&gt;Now that we've got a &lt;a href="http://blogs.msdn.com/mediaandmicrocode/archive/2008/07/21/microcode-cleaning-up-get-recordedtv-with-select-object.aspx"&gt;fairly mature Get-RecordedTV&lt;/a&gt;, we can use it to delete a certain number of files from your collection until we reach a desired amount of freed space.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;function Remove-DVRBySeries($cleanupSize = 1gb, $episodeCount = 1)     &lt;br /&gt;{      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; $shows = @()      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; # Pipe the results of Get-RecordedTV so that we can see progress      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; $perc = 0 &lt;/p&gt;    &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; Get-RecordedTV | Foreach-Object {     &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $perc+=5      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if ($perc -gt 100) { $perc = 0 }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Write-Progress &amp;quot;Getting DVR Metadata&amp;quot; &amp;quot;$($_.Series) - $($_.Episode) - $($_.Channel)&amp;quot; -perc $perc      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $shows+=$_      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; $showsbySeries = $shows | Group-Object Series      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; $allSeries = $showsBySeries |      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Where-Object { $_.Count -le $episodeCount} |      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Sort-Object Count      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; foreach ($series in $allSeries)      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; {&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; foreach ($e in $series.Group) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $response =Read-Host &amp;quot;Delete $($e.Series) - $($e.Episode) (Yes/No)&amp;quot;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if ($response -ilike &amp;quot;*Yes*&amp;quot;) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if ($e.File) {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Write-Progress &amp;quot;Deleting $($e.Series) - $($e.Episode)&amp;quot; `      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &amp;quot;$($e.Size / 1mb) megabytes saved - $(($cleanupSize - $e.Size)/1mb) remaining&amp;quot;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Remove-Item $e.File      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; $cleanupSize-=$e.Size      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } else {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Write-Error &amp;quot;$($e.Series) - $($e.Episode) File Not Found&amp;quot;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } else {      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Write-Progress &amp;quot;Skipping show by user request&amp;quot; &amp;quot;$($e.Series) - $($e.Episode)&amp;quot;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if ($cleanupSize -le 0) { return }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; }      &lt;br /&gt;}&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This script will remove shows with one or fewer episodes until it has saved 1gb of space.&amp;#160; If you want to make it save more, use the cleanupSize parameter.&amp;#160; If you want it to check series with more episodes, use the -episodeCount parameter. It will ask to make sure you want to delete each show, and will stop once it has saved you enough space.&lt;/p&gt;  &lt;p&gt;The script above uses a lot of simple PowerShell benefits.&amp;#160; Let's take a closer look at each:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;CleanupSize uses 1gb as its default.&amp;#160; In PowerShell, you can use gb,mb,and kb as numbers, e.g. 1gb, 10mb, or 640kb&lt;/li&gt;    &lt;li&gt;By piping Get-RecordedTV to ForEach-Object, I am able to store the results of Get-RecordedTV as they come in, instead of waiting for all of them to be completed, I can use Write-Progress to display each show as it comes in.&amp;#160; Since I don't know how long it will take, I can just wrap the progress bar around whenever I get to 100%.&lt;/li&gt;    &lt;li&gt;Group-Object will group all of the shows by the value of the series property&lt;/li&gt;    &lt;li&gt;Sort-Object is used to sort the results of Group-Object by the number of items in each group (in our case, the number of recorded episodes of a series)&lt;/li&gt;    &lt;li&gt;Write-Progress is used again to update the user as files are deleted or skipped&lt;/li&gt;    &lt;li&gt;Read-Host displays a prompt and asks for user input&lt;/li&gt;    &lt;li&gt;-ilike is a case insentive like, so $response -ilike will match &amp;quot;Yes&amp;quot;, &amp;quot;yeS', or &amp;quot;Yes Sir&amp;quot;, sadly, the logic will also catch &amp;quot;Yes, I mean No!&amp;quot;&lt;/li&gt;    &lt;li&gt;Write-Error politely informs me that a file cannot be deleted, but does not stop execution of the script (this the&amp;#160; important difference between Write-Error and throw)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;That's it.&amp;#160; We've brought one train of thought to an end.&amp;#160; With this script, I was able to quickly and easily cleanup almost 40gb of shows that I wasn't watching.&amp;#160; I hope it helps you clean up your hard drive, and I hope that explaining how to get here has increased your understanding of PowerShell scripting and problem solving.&lt;/p&gt;  &lt;p&gt;Hope this helps,&lt;/p&gt;  &lt;p&gt;James&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8759886" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/PowerShell/default.aspx">PowerShell</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Microcode/default.aspx">Microcode</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/DVR/default.aspx">DVR</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Get-RecordedTV/default.aspx">Get-RecordedTV</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Write-Error/default.aspx">Write-Error</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Sort-Object/default.aspx">Sort-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Write-Progress/default.aspx">Write-Progress</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Group-Object/default.aspx">Group-Object</category><category domain="http://blogs.msdn.com/mediaandmicrocode/archive/tags/Remove-DVRBySeries/default.aspx">Remove-DVRBySeries</category></item></channel></rss>