<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type='text/xsl' href='http://keithhill.spaces.live.com/mmm2008-05-17_13.22/rsspretty.aspx?rssquery=en-US;http%3a%2f%2fkeithhill.spaces.live.com%2ffeed.rss' version='1.0'?><rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:msn="http://schemas.microsoft.com/msn/spaces/2005/rss" xmlns:live="http://schemas.microsoft.com/live/spaces/2006/rss" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Keith Hill's Blog</title><description>Windows PowerShell MVP</description><link>http://keithhill.spaces.live.com/</link><language>en-US</language><pubDate>Wed, 23 Jul 2008 22:49:17 GMT</pubDate><lastBuildDate>Wed, 23 Jul 2008 22:49:17 GMT</lastBuildDate><generator>Microsoft Spaces v1.1</generator><docs>http://www.rssboard.org/rss-specification</docs><ttl>60</ttl><live:identity><live:id>6524913499512388247</live:id><live:alias>keithhill</live:alias></live:identity><image><title>Keith Hill's Blog</title><url>http://byfiles.storage.live.com/y1pCTlB20j76CEjBAMhg4JPTXq1UIDSkNrGHG83HKzgTFIVFGMTnMtxXA</url><link>http://keithhill.spaces.live.com/</link></image><cf:listinfo><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="typelabel" label="Type" /><cf:group ns="http://schemas.microsoft.com/live/spaces/2006/rss" element="tag" label="Tag" /><cf:group element="category" label="Category" /><cf:sort element="pubDate" label="Date" data-type="date" default="true" /><cf:sort element="title" label="Title" data-type="string" /><cf:sort ns="http://purl.org/rss/1.0/modules/slash/" element="comments" label="Comments" data-type="number" /></cf:listinfo><item><title>Off Topic: Music, DRM and Tanking CD Sales</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6226.entry</link><description>&lt;p&gt;I took my 9 year old daughter to her first concert last night.  The band was &lt;a href="http://www.lifehousemusic.com/" target="_blank"&gt;Lifehouse&lt;/a&gt;, a relatively newish, great alternative rock band.   &lt;p&gt;&lt;a href="http://61ptqq.bay.livefilestore.com/y1psPgV93RCi5OksVUXoe84kA_CLXoCVGYDLE85HqvW5IBOCoxigEzu5V3y03d04Pc7O4SLgn-JQNksF0u6LTKKvkGsI4xxF-m0?PARTNER=WRITER"&gt;&lt;img style="border-right:0px;border-top:0px;border-left:0px;border-bottom:0px" height=142 alt="Lifehouse in Fort Collins Cropped" src="http://byfiles.storage.msn.com/y1p_nr8c7Lq5kLIGr6fONFD5M0C0e8yZgiwSXsZ3pUePGCzwOhSOmTKSnb-yHpIXPL42hPMUeJvXcDIXI88buIQcHRXt6tf7EeD?PARTNER=WRITER" width=244 border=0&gt;&lt;/a&gt;  &lt;p&gt;I had seen them last summer as an opening act for the &lt;a href="http://www.googoodolls.com/" target="_blank"&gt;Goo Goo Dolls&lt;/a&gt;.  I hadn't heard of Lifehouse before but was very impressed with their &amp;quot;big&amp;quot; sound.  After that concert I bought two of their CDs.  Yeah I'm one of those guys who still buys CDs because I despise DRM and I don't want to buy compressed/encoded (lossy) music.  I'd rather do the compression and encoding myself.  Plus I'll always have access to the raw, uncompressed music for future re-encoding in better formats.   &lt;p&gt;Regarding DRM, I despise it because it isn't user friendly.  It tends to be tied to a particular device instead of a person.  Devices come and go and the pushups you have to go through to deactivate one device and activate another get to be a right pain in the rear.  This is one of the reasons I stopped using Audible.com.  I got tired of the whole deactivation/activation dance every year.  Yeah, I go through new devices that often. &lt;p&gt;One very unfortunate downside to the ease with which music can be copied is piracy.  I'm both a musician and a software developer so the notion of protecting intellectual property and copyrighted material hits close to home.  After the concert, my daughter and I got to meet the band members who were signing autographs.  What a great bunch of guys!  They were all down to earth and very nice.  I even got a picture of my daughter with Jason Wade - the lead singer.  She was thrilled.  :-) &lt;p&gt;I told them that I had seen them a year ago opening for the Goo Goo Dolls whom they were touring with.  I asked if that helped boost CD sales because touring with GGD had to expose them to a wider audience.  The reply shouldn't have surprised me but there is nothing like hearing it come right from the horse's mouth.  Their guitarist said that CD sales across the industry have tanked.  The only way they're making money these days is by touring, touring and more touring.  That's a shame.  I have no idea how to solve this problem but it starts with folks internalizing that copying copyrighted music without paying for it is stealing.  That's certainly what I'll be teaching my kids. &lt;p&gt;Give Lifehouse a listen, they have some really good tunes and if you like what you hear, buy it.  We need to support the arts, right?  My favorite songs?  Well most folks will recognize &lt;a href="http://www.amazon.com/No-Name-Face-Lifehouse/dp/B000050HZO/ref=pd_bbs_sr_2?ie=UTF8&amp;amp;s=music&amp;amp;qid=1213570501&amp;amp;sr=8-2" target="_blank"&gt;Hanging by a Moment&lt;/a&gt; but my favorite is &lt;a href="http://www.amazon.com/Who-We-Are-Lifehouse/dp/B000Q9OD5I/ref=pd_sim_m_img_1" target="_blank"&gt;First Time&lt;/a&gt; followed closely by &lt;a href="http://www.amazon.com/Who-We-Are-Lifehouse/dp/B000Q9OD5I/ref=pd_sim_m_img_1" target="_blank"&gt;Who We Are and Bridges&lt;/a&gt;.   &lt;p&gt;BTW for you PowerShellers, check out this album cover: &lt;p&gt;&lt;a href="http://www.amazon.com/gp/product/images/B000Q9OD5I/ref=dp_image_0?ie=UTF8&amp;amp;n=5174&amp;amp;s=music"&gt;&lt;img height=240 alt="Who We Are" src="http://ecx.images-amazon.com/images/I/51mdILz9siL._SL500_AA240_.jpg" width=240 border=0&gt;&lt;/a&gt; &lt;p&gt;The bald headed guy, who is Lifehouse's drummer, looks an awful lot like PowerShell's language designer - Bruce Payette.  Check out this &lt;a href="http://www.amazon.com/gp/blog/id/A24OUCYOSFCKB8" target="_blank"&gt;picture of Bruce on Amazon&lt;/a&gt;. I wonder if someone is leading a double life.  :-)  OK now back to our regularly scheduled PowerShell programming.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Off+Topic%3a+Music%2c+DRM+and+Tanking+CD+Sales&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>Music</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6226.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6226.entry</guid><pubDate>Sun, 15 Jun 2008 23:31:54 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6226/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6226.entry#comment</wfw:comment><dcterms:modified>2008-06-15T23:31:54Z</dcterms:modified></item><item><title>Poor Man's File/Directory Name Indexer Using Windows PowerShell</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6186.entry</link><description>&lt;p&gt;The following is a script that I have set up on my dev PCs to run nightly via a scheduled task:&lt;pre&gt;&lt;span style="color:rgb(0,0,0)"&gt;## CatalogFileSystem.ps1&lt;br&gt;param([&lt;/span&gt;&lt;span style="color:rgb(0,128,128)"&gt;string&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;[]]&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$paths&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;)&lt;br&gt;&lt;span style="color:rgb(95,158,160)"&gt;Set-PSDebug&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;-Strict&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;

&lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;function&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; Main {
&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;    foreach&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; (&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;in&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$Paths&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;) {
&lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;        if&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; (!(&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;Test-Path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;-PathType&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; Container)) {
&lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;            &lt;span style="color:rgb(95,158,160)"&gt;Write-Error&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;'$path' doesn't exist or isn't a directory&lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;
            exit &lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;1&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;
        }
		
&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;        $filelist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; = &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;Join-Path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; filelist.txt
&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;        $dirlist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;  = &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;Join-Path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; dirlist.txt
		
&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;        Remove-Item&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$filelist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;-ErrorAction&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; SilentlyContinue
&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;        Remove-Item&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$dirlist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;  &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;-ErrorAction&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; SilentlyContinue
		
        CatalogFolder &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;	
    }
}

&lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;function&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; CatalogFolder(&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;) {
&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;    Get-ChildItem&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;-ErrorAction&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; SilentlyContinue | &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;sort&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; FullName | &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;foreach&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; {
&lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;        if&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; (&lt;/span&gt;&lt;span style="color:rgb(0,0,128)"&gt;$_&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.PSIsContainer) {
&lt;/span&gt;&lt;span style="color:rgb(0,0,128)"&gt;            $_&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.FullName &amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$dirlist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;
            CatalogFolder &lt;/span&gt;&lt;span style="color:rgb(0,0,128)"&gt;$_&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.FullName
        }
&lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;        else&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; {
&lt;/span&gt;&lt;span style="color:rgb(0,0,128)"&gt;            $_&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.FullName &amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$filelist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;
        }
    }
}

. Main&lt;br&gt;## End of CatalogFileSystem.ps1
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;
&lt;p&gt;My scheduled task is configured like so (and runs everyday at 4 am): 
&lt;p&gt;&lt;font face="Courier New" size=2&gt;Program: C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe&lt;br&gt;Arguments: -Command C:\Bin\CatalogFileSystem C:, D:&lt;/font&gt; 
&lt;p&gt;I also set this task to run with highest privileges on Vista so it can catalog more of the nooks and crannies of my filesystem.  This script creates two files setting at the root of each path supplied.  In my case: 
&lt;p&gt;&lt;font face="Courier New" size=2&gt;C:\dirlist.txt&lt;br&gt;C:\filelist.txt&lt;br&gt;&lt;/font&gt;&lt;font face="Courier New" size=2&gt;D:\dirlist.txt&lt;br&gt;D:\filelist.txt&lt;/font&gt; 
&lt;p&gt;Searching for files on my filesystem is now very easy: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Select-String afxwin\.h \filelist.txt | select Line&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="color:rgb(255,255,255)"&gt;Line&lt;br&gt;----&lt;br&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afxwin.h&lt;br&gt;&lt;span style="color:rgb(255,255,255)"&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\atlmfc\include\afxwin.h&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;In fact I have created a shortcut function for the above I call Find-File (alias ff):&lt;pre&gt;&lt;span style="color:rgb(0,0,255)"&gt;Set-Alias &lt;font color="#000000"&gt;ff Find-File&lt;/font&gt;&lt;br&gt;function&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; Find-File(&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$pattern&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;) {
&lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;    $filelist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; = &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;Join-Path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$pwd&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.drive.root filelist.txt
&lt;/span&gt;&lt;span style="color:rgb(0,0,255)"&gt;    if&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; (!(&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;Test-Path&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$filelist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;-PathType&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; Leaf)) {
&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;        Write-Error&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;$filelist doesn't exist or isn't a file&lt;/span&gt;&lt;span style="color:rgb(128,0,0)"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;
    }
&lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;    Select-String&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$pattern&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; &lt;/span&gt;&lt;span style="color:rgb(128,0,128)"&gt;$filelist&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; | &lt;/span&gt;&lt;span style="color:rgb(95,158,160)"&gt;foreach&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt; {&lt;/span&gt;&lt;span style="color:rgb(0,0,128)"&gt;$_&lt;/span&gt;&lt;span style="color:rgb(0,0,0)"&gt;.Line}
}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;And then this sort of filename search gets even easier: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; ff afxwin\.h&lt;br&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\include\afxwin.h&lt;br&gt;C:\Program Files\Microsoft Visual Studio 9.0\VC\ce\atlmfc\include\afxwin.h&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Now you might be wondering why I don't just use the search built into Vista.  Well first off, Vista's search doesn't index your whole hard drive or any volumes other than the contents of C: by default.  While it can be set up to index more locations I worry about the performance hit because the second issue is that the Vista search indexer runs in the background all the time.  The CatalogFileSystem script runs just once a day (or however often you schedule it) when you're typically not using the computer.  Yeah, it could be as much as 24 hours out of date but the vast majority of the time I'm searching for files that have been on my system for a while: C++ header files, SDK header files, C runtime source files, windows DLLs, etc. 
&lt;p&gt;I'm sure some folks are going to think this is goofy but honestly I do search the filelist.txt file quite often (not so much the dirlist.txt file).  Do you have any similar convenience scripts like this?  If you do, please add a comment and let me know.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Poor+Man's+File%2fDirectory+Name+Indexer+Using+Windows+PowerShell&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6186.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6186.entry</guid><pubDate>Tue, 27 May 2008 02:33:11 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6186/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6186.entry#comment</wfw:comment><dcterms:modified>2008-05-27T02:35:02Z</dcterms:modified></item><item><title>Northern Colorado .NET User Group Windows PowerShell Presentation</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6172.entry</link><description>&lt;p&gt;Tonight I gave a one hour introductory talk on Windows PowerShell to my local .NET user group.  The primary focus of this talk was to show how PowerShell should be interesting to .NET developers.  As promised, here is the slide deck and the samples.  If you have any questions, please let me know.
&lt;p&gt;&lt;iframe style="border-right:#dde5e9 1px solid;padding-right:0px;border-top:#dde5e9 1px solid;padding-left:0px;padding-bottom:0px;margin:3px;border-left:#dde5e9 1px solid;width:240px;padding-top:0px;border-bottom:#dde5e9 1px solid;height:66px;background-color:#ffffff" marginwidth=0 marginheight=0 src="http://cid-5a8d2641e0963a97.skydrive.live.com/embedrowdetail.aspx/Public/NorthernCODotnetUG-2008-05-12/The What and Why of Windows PowerShell.pptx" frameborder=0 scrolling=no&gt;&lt;/iframe&gt;&lt;iframe style="border-right:#dde5e9 1px solid;padding-right:0px;border-top:#dde5e9 1px solid;padding-left:0px;padding-bottom:0px;margin:3px;border-left:#dde5e9 1px solid;width:240px;padding-top:0px;border-bottom:#dde5e9 1px solid;height:66px;background-color:#ffffff" marginwidth=0 marginheight=0 src="http://cid-5a8d2641e0963a97.skydrive.live.com/embedrowdetail.aspx/Public/NorthernCODotnetUG-2008-05-12/WindowsPowerShellSamples.zip" frameborder=0 scrolling=no&gt;&lt;/iframe&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Northern+Colorado+.NET+User+Group+Windows+PowerShell+Presentation&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6172.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6172.entry</guid><pubDate>Tue, 13 May 2008 05:13:54 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6172/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6172.entry#comment</wfw:comment><dcterms:modified>2008-05-13T05:15:24Z</dcterms:modified></item><item><title>Effective PowerShell Item 13: Comparing Arrays in Windows PowerShell</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6159.entry</link><description>&lt;p&gt;PowerShell has a lot of useful operators such as -contains which tests if an array contains an particular element.  But as far as I can tell PowerShell doesn't &amp;quot;seem&amp;quot; to provide an easy way to test if two array's contents are equal.  This if often quite handy and I was a bit surprised by this apparent omission.  
&lt;p&gt;I came upon this need to compare arrays while answering a question on the microsoft.public.windows.powershell newsgroup.  The poster wanted to find UTF8 encoded files by inspecting their BOM or &lt;a href="http://en.wikipedia.org/wiki/Byte_Order_Mark" target="_blank"&gt;byte order mark&lt;/a&gt;.  One relatively straight forward approach to this is: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $preamble = [System.Text.Encoding]::UTF8.GetPreamble()&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $preamble | foreach {&amp;quot;0x{0:X2}&amp;quot; -f $_}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;0xEF&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;0xBB&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;0xBF&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $fileHeader = Get-Content Utf8File.txt -Enc byte -Total 3&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $fileheader | foreach {&amp;quot;0x{0:X2}&amp;quot; -f $_}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;0xEF&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;0xBB&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;0xBF&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;While it is easy enough to visually inspect this and see we have a match, visual inspection doesn't work in a script.  :-)  You could also test each individual element which isn't bad for a three element array but when you hit say 10 elements that approach might starting looking tedious.  
&lt;p&gt;You might think that we could just compare these two arrays directly like so: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $preamble -eq $fileHeader | Get-TypeName &lt;font color="#00ffff"&gt;# Get-TypeName is from the PowerShell Community Extensions&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#ffff00"&gt;WARNING: Get-TypeName did not receive any input. The input may be an empty collection. You can either &lt;br&gt;prepend the collection expression with the comma operator e.g. &amp;quot;,$collection | gtn&amp;quot; or you can pass the &lt;br&gt;variable or expression to Get-TypeName as an argument e.g. &amp;quot;gtn $collection&amp;quot;.&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $preamble -eq 0xbb&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;187&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;But comparing arrays via the -eq operator doesn't actually compare the contents of two arrays.  As you can see above, this results in no output.  When the left hand side of the -eq operator is an array, PowerShell return the elements of the array that match the value specified on the right hand side (shown above where I test for -eq to 0xbb). 
&lt;p&gt;OK so it looks like we need to roll our own mechanism to compare arrays.  Here is one way: 
&lt;p style="margin-bottom:0pt;line-height:normal;tab-stops:22.5pt"&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;function&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; AreArraysEqual(&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;, &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;) {&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;if&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; (&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-isnot&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; [&lt;/span&gt;&lt;span style="font-size:10pt;color:teal;font-family:'Courier New'"&gt;array&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;] &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-or&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-isnot&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; [&lt;/span&gt;&lt;span style="font-size:10pt;color:teal;font-family:'Courier New'"&gt;array&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;]) { &lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;throw&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:maroon;font-family:'Courier New'"&gt;&amp;quot;Both inputs must be an array&amp;quot;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;if&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; (&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.Rank &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-ne&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.Rank) { &lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;return&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;$false&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;if&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; ([&lt;/span&gt;&lt;span style="font-size:10pt;color:teal;font-family:'Courier New'"&gt;System.Object&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;]::&lt;/span&gt;&lt;span style="font-size:10pt;color:saddlebrown;font-family:'Courier New'"&gt;ReferenceEquals&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;, &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;)) {&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;return&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;$true&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;for&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; (&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$r&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; = 0; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$r&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-lt&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.Rank; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$r&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;++) {&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;if&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; (&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.GetLength(&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$r&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;) &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-ne&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.GetLength(&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$r&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;)) {&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;return&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;$false&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;}&lt;br&gt;&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$enum1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; = &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.GetEnumerator()&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$enum2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; = &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$a2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.GetEnumerator()&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;p style="margin-bottom:0pt;line-height:normal;tab-stops:22.5pt"&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;while&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; (&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$enum1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.MoveNext() &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-and&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$enum2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.MoveNext()) {&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;if&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; (&lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$enum1&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.Current &lt;/span&gt;&lt;span style="font-size:10pt;color:red;font-family:'Courier New'"&gt;-ne&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:purple;font-family:'Courier New'"&gt;$enum2&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;.Current) {&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;return&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;$false&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;      &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;}&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;return&lt;/span&gt;&lt;span style="font-size:10pt;color:black;font-family:'Courier New'"&gt; &lt;/span&gt;&lt;span style="font-size:10pt;color:blue;font-family:'Courier New'"&gt;$true&lt;br&gt;&lt;/span&gt;&lt;span style="font-size:10pt;color:black;line-height:115%;font-family:'Courier New'"&gt;}&lt;/span&gt; 
&lt;p&gt;And it works as expected: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; AreArraysEqual $preamble $fileHeader&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;True&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;However there turns out to be a way to do this within PowerShell but it isn't exactly obvious.  At least it wasn't to me - at first.  
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; @(Compare-Object $preamble $fileHeader -sync 0).Length -eq 0&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;True&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Good old Compare-Object will compare the arrays and if there are no differences it won't output anything.  If we wrap the output of Compare-Object in an array subexpression @() then we will get an array with either 0 or more elements.  A simple compare of the length to 0 will confirm that there was no output, hence the arrays are equal.  
&lt;p&gt;&lt;strong&gt;[Updated: 5/12/2008 - need to use -SyncWindow 0 to get correct result - thanks Arnoud and Roman]&lt;/strong&gt;  Let me elaborate more on this updated information.  As Roman points out in the comments on this post, Compare-Object compares two objects to see if they have the same set of elements.  Normally it does not care if the elements are in the same sequence in each object (each array in this case).  For example: 
&lt;p&gt;&lt;font face="Courier New" color="#17365d" size=2&gt;PS&amp;gt; $a1 = 1,1,2&lt;br&gt;PS&amp;gt; $a2 = 1,2,1&lt;br&gt;PS&amp;gt; @(Compare-Object $a1 $a2).length -eq 0&lt;br&gt;True&lt;/font&gt;
&lt;p&gt;Obviously that isn't what we want when comparing arrays for equality.  Fortunately, as Arnoud points out, we can use the SyncWindow parameter with a value 0 to get Compare-Object to &amp;quot;force sequence equality&amp;quot; as Arnoud succinctly phrases it.
&lt;p&gt;How about performance of these two approaches: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $a1 = 1..10000&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $a2 = 1..10000&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; (Measure-Command { AreArraysEqual $a1 $a2 }).TotalSeconds&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;1.236252&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; (Measure-Command { @(Compare-Object $a1 $a2 -sync 0).Length -eq 0 }).TotalSeconds&lt;/span&gt;
&lt;span style="color:rgb(255,255,255)"&gt;0.3259954&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Compare-Object beats out my PowerShell function by a good margin which isn't too surprising[1].  After all, one is compiled code and the other is interpreted script.  So there you have it.  If you need a quick way to compare to arrays, just remember that arrays are objects too and that is what Compare-Object does best - compare two objects. 
&lt;p&gt;&lt;font color="#808080" size=1&gt;[1] - Except for comparing against the same array where my function is two orders of magnitude faster.  It seems that the Compare-Object cmdlet could benefit from a quick System.Object.ReferenceEquals check.  :-)  Admittedly this is a bit of a corner case scenario.&lt;/font&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Effective+PowerShell+Item+13%3a+Comparing+Arrays+in+Windows+PowerShell&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>Effective PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6159.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6159.entry</guid><pubDate>Sun, 11 May 2008 18:41:30 GMT</pubDate><slash:comments>6</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6159/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6159.entry#comment</wfw:comment><dcterms:modified>2008-05-13T15:31:51Z</dcterms:modified></item><item><title>Effective PowerShell Item 12: Understanding ByValue Pipeline Bound Parameters</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6158.entry</link><description>&lt;p&gt;In &lt;a href="http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6130.entry" target="_blank"&gt;item 11, I covered ByPropertyName pipeline bound parameters&lt;/a&gt;.  In this post, I'll cover the other variety of pipeline binding - ByValue.  ByValue binding takes the input object itself and attempts to bind it by type using type coercion if possible to parameters decorated as ByValue.  For example, most of the *-Object utility cmdlets operate on whatever object is presented to them.  The help on Where-Object shows this: 
&lt;p&gt;&lt;font face="Courier New" size=2&gt;-inputObject &amp;lt;psobject&amp;gt;&lt;br&gt;    Specifies the objects to be filtered. If you save the output of a command in a variable, &lt;br&gt;    you can use InputObject to pass the variable to Where-Object. However, typically, the &lt;br&gt;    InputObject parameter is not typed in the command. Instead, when you pass an object &lt;br&gt;    through the pipeline, Windows PowerShell associates the passed object with the&lt;br&gt;    InputObject parameter. &lt;/font&gt;
&lt;p&gt;&lt;font face="Courier New" size=2&gt;    Required?                    false&lt;br&gt;    Position?                    named&lt;br&gt;    Default value&lt;br&gt;&lt;strong&gt;    Accept pipeline input?       true (ByValue)&lt;br&gt;&lt;/strong&gt;    Accept wildcard characters?  false&lt;/font&gt; 
&lt;p&gt;It turns out that ByValue isn't nearly as popular as ByPropertyValue.  How can I make such a statement you ask?  Well this is one of the things that I love about PowerShell.  It provides so much metadata about itself.  It is very &amp;quot;self describing&amp;quot;.  You can easily walk every parameter on every cmdlet that is currently loaded into PowerShell.  First let's see what information is available for a parameter: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff80"&gt;PS&amp;gt;&lt;/font&gt; Get-Command -CommandType cmdlet | Select -Expand ParameterSets | &lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Select -Expand Parameters -First 1 | Get-Member&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;   TypeName: System.Management.Automation.CommandParameterInfo&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Name                                MemberType Definition&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;----                                ---------- ----------&lt;br&gt;&lt;/span&gt;&lt;font color="#ffffff"&gt;...&lt;/font&gt;
&lt;span style="color:rgb(255,255,255)"&gt;Aliases                             Property   System.Collections.ObjectModel.ReadOnlyCollection`1[[...&lt;br&gt;Attributes                          Property   System.Collections.ObjectModel.ReadOnlyCollection`1[[...&lt;br&gt;HelpMessage                         Property   System.String HelpMessage {get;}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;IsDynamic                           Property   System.Boolean IsDynamic {get;}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;IsMandatory                         Property   System.Boolean IsMandatory {get;}&lt;br&gt;Name                                Property   System.String Name {get;}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;ParameterType                       Property   System.Type ParameterType {get;}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Position                            Property   System.Int32 Position {get;}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;ValueFromPipeline                   Property   System.Boolean ValueFromPipeline {get;}&lt;br&gt;ValueFromPipelineByPropertyName     Property   System.Boolean ValueFromPipelineByPropertyName {get;}&lt;br&gt;ValueFromRemainingArguments         Property   System.Boolean ValueFromRemainingArguments {get;}&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The interesting properties for us here are the Name and ValueFromPipeline* properties.  Given this information it is easy to figure out how many of each type there are: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; (Get-Command -CommandType cmdlet | Select -Expand ParameterSets | Select -Expand Parameters |&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;   Where {$_.ValueFromPipeline -and !$_.ValueFromPipelineByPropertyName} | Measure-Object).Count&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;55&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; (Get-Command -CommandType cmdlet | Select -Expand ParameterSets | Select -Expand Parameters |&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;   Where {!$_.ValueFromPipeline -and $_.ValueFromPipelineByPropertyName} | Measure-Object).Count&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;196&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; (Get-Command -CommandType cmdlet | Select -Expand ParameterSets | Select -Expand Parameters |&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;   Where {$_.ValueFromPipeline -and $_.ValueFromPipelineByPropertyName} | Measure-Object).Count&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;66&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;So from here we can see the following: 
&lt;table cellspacing=0 cellpadding=2 width=337 border=1&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign=top width=253&gt;&lt;strong&gt;Type of Pipeline Binding&lt;/strong&gt; 
&lt;td valign=top align=middle width=82&gt;&lt;strong&gt;Count&lt;/strong&gt; 
&lt;tr&gt;
&lt;td valign=top width=254&gt;ValueFromPipeline 
&lt;td valign=top align=right width=82&gt;55 
&lt;tr&gt;
&lt;td valign=top width=255&gt;ValueFromPipelineByPropertyName 
&lt;td valign=top align=right width=82&gt;196 
&lt;tr&gt;
&lt;td valign=top width=256&gt;Both 
&lt;td valign=top align=right width=82&gt;66&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;So indeed binding by property name is much more common.  Binding by value from the pipeline is primarily for cmdlets that manipulate objects.  In the query below we can see that the InputObject parameter is by far the most common &amp;quot;ByValue&amp;quot; pipeline bound parameter: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; Get-Command -CommandType cmdlet | Select -Expand ParameterSets | Select -Expand Parameters |&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Where {$_.ValueFromPipeline -and !$_.ValueFromPipelineByPropertyName} |&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Group Name -NoElement | Sort Count -Desc&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Count Name&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;----- ----&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;   40 InputObject&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    4 Message&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    3 String&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    2 SecureString&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    1 ExecutionPolicy&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    1 Object&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    1 AclObject&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    1 DifferenceObject&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    1 Id&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    1 Command&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;A little further digging reveals the cmdlets that use the ByValue bound InputObject parameters as shown below.  Note that a single parameter can appear in more than one parameter set on a cmdlet, which explains why there are only 36 cmdlets that account for the 40 instances of InputObject. 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; $CmdletName = @{Name='CmdletName';Expression={$_.Name}}&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; Get-Command -CommandType cmdlet | Select $CmdletName -Expand ParameterSets |&lt;br&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Select CmdletName -Expand Parameters |&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Where {$_.ValueFromPipeline -and !$_.ValueFromPipelineByPropertyName} |&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Group Name | Sort Count -Desc | Select -First 1 | Foreach {$_.Group} |&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;  Sort CmdletName -Unique | Format-Wide CmdletName -AutoSize&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;&amp;gt;&amp;gt;&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Add-History      Add-Member       ConvertTo-Html   Export-Clixml    Export-Csv      ForEach-Object&lt;br&gt;Format-Custom    Format-List      Format-Table     Format-Wide      Get-Member      Get-Process&lt;br&gt;Get-Service      Get-Unique       Group-Object     Measure-Command  Measure-Object  Out-Default&lt;br&gt;Out-File         Out-Host         Out-Null         Out-Printer      Out-String      Restart-Service&lt;br&gt;Resume-Service   Select-Object    Select-String    Sort-Object      Start-Service   Stop-Process&lt;br&gt;Stop-Service     Suspend-Service  Tee-Object       Trace-Command    Where-Object    Write-Output&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;As you can see most of these cmdlets are designed to deal with objects in general.  Note to cmdlet developers - pipeline bound parameters is how your cmdlets receive pipeline objects.  When writing a cmdlet there is no $_.  If your cmdlet wants to &amp;quot;participate&amp;quot; in the pipeline it must set the ParameterAttribute property ValueFromPipeline and/or ValueFromPipelineByPropertyName to true on at least one of its parameters.  
&lt;p&gt;As mentioned above most ByValue parameters are of the InputObject (type psobject or psobject[]) variety so they pretty much accept anything.  However not all cmdlets work that way.  The -Id parameter (type [long[]]) on Get-History is pipeline bound ByValue.  The follow Trace-Command output shows how PowerShell works hard when necessary to convert the input object's type to the expected type. In this case a scalar string value of '1' to an array of Int64: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; Trace-Command -Name ParameterBinding -PSHost -Expression {'1' | get-history}&lt;br&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;BIND NAMED cmd line args [Get-History]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;BIND POSITIONAL cmd line args [Get-History]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;MANDATORY PARAMETER CHECK on cmdlet [Get-History]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;CALLING BeginProcessing&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;BIND PIPELINE object to parameters: [Get-History]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    &lt;font color="#00ffff"&gt;PIPELINE object TYPE = [System.String]&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    RESTORING pipeline parameter's original values&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    Parameter [Id] PIPELINE INPUT ValueFromPipeline NO COERCION&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    BIND arg [1] to parameter [Id]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;        Binding collection parameter Id: argument type [String], parameter type&lt;br&gt;             [System.Int64[]], collection type Array, element type [System.Int64],&lt;br&gt;             no coerceElementType&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;        Creating array with element type [System.Int64] and 1 elements&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;        Argument type String is not IList, treating this as scalar&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;        &lt;strong&gt;&lt;font color="#00ffff"&gt;BIND arg [1] to param [Id] SKIPPED&lt;/font&gt;&lt;/strong&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    Parameter [Id] PIPELINE INPUT ValueFromPipeline WITH COERCION&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;    BIND arg [1] to parameter [Id]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;        COERCE arg type [System.Management.Automation.PSObject] to [System.Int64[]]&lt;br&gt;            ENCODING arg into collection&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;            Binding collection parameter Id: argument type  [PSObject], parameter type&lt;br&gt;                 [System.Int64[]], collection type Array, element type [System.Int64],&lt;br&gt;                 coerceElementType&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;            Creating array with element type [System.Int64] and 1 elements&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;            Argument type PSObject is not IList, treating this as scalar&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;            &lt;font color="#00ffff"&gt;COERCE arg type [System.Management.Automation.PSObject] to [System.Int64]&lt;br&gt;                CONVERT arg type to param type using LanguagePrimitives.ConvertTo&lt;br&gt;                CONVERT SUCCESSFUL using LanguagePrimitives.ConvertTo: [1]&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ffff"&gt;            Adding scalar element of type Int64 to array position 0&lt;/font&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;        Executing VALIDATION metadata: [System.Management.Automation.ValidateRangeAttribute]&lt;br&gt;        BIND arg [System.Int64[]] to param [Id] SUCCESSFUL&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;MANDATORY PARAMETER CHECK on cmdlet [Get-History]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;CALLING ProcessRecord&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;CALLING EndProcessing&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note that on the first attempt, PowerShell tries to convert the string to an array of Int64 and fails.  Then it tries again by treating the input as psobject.  It throws that psobject at an internal help class method LanguagePrimitives.ConvertTo() that successfully converts the string '1' to an Int64[] containing the value 1. 
&lt;p&gt;When a parameter is both ByValue and ByPropertyName bound, PowerShell attempts to bind in this order: 
&lt;ol&gt;
&lt;li&gt;Bind ByValue with no type conversion 
&lt;li&gt;Bind ByPropertyName with no type conversion 
&lt;li&gt;Bind ByValue with type conversion 
&lt;li&gt;Bind ByPropertyName with type conversion&lt;/ol&gt;
&lt;p&gt;There is more to the parameter binding algorithm like finding the best match amongst different parameter sets.  BTW one last tidbit related to parameters.  The PowerShell help topics aren't completely automatically generated and as a result they aren't always correct.  For instance, look up the parameters on Get-Content and see if you find a -Wait parameter - you won't.  :-)  However the metadata is always complete and correct e.g.: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; Get-Command Get-Content -Syntax&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Get-Content [-Path] &amp;lt;String[]&amp;gt; [-ReadCount &amp;lt;Int64&amp;gt;] [-TotalCount &amp;lt;Int64&amp;gt;] [-Filter &amp;lt;String&amp;gt;] &lt;br&gt;  [-Include &amp;lt;String[]&amp;gt;] [-Exclude &amp;lt;String[]&amp;gt;] [-Force] [-Credential &amp;lt;PSCredential&amp;gt;] [-Verbose] &lt;br&gt;  [-Debug] [-ErrorAction &amp;lt;ActionPreference&amp;gt;] [-ErrorVariable &amp;lt;String&amp;gt;] [-OutVariable &amp;lt;String&amp;gt;] &lt;br&gt;  [-OutBuffer &amp;lt;Int32&amp;gt;] [-Delimiter &amp;lt;String&amp;gt;] &lt;font color="#00ffff"&gt;[-Wait]&lt;/font&gt; [-Encoding &amp;lt;FileSystemCmdletProviderEncoding&amp;gt;]&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Get-Content [-LiteralPath] &amp;lt;String[]&amp;gt; [-ReadCount &amp;lt;Int64&amp;gt;] [-TotalCount &amp;lt;Int64&amp;gt;] [-Filter &amp;lt;String&amp;gt;]&lt;br&gt;  [-Include &amp;lt;String[]&amp;gt;] [-Exclude &amp;lt;String[]&amp;gt;] [-Force] [-Credential &amp;lt;PSCredential&amp;gt;] [-Verbose] &lt;br&gt;  [-Debug] [-ErrorAction &amp;lt;ActionPreference&amp;gt;] [-ErrorVariable &amp;lt;String&amp;gt;] [-OutVariable &amp;lt;String&amp;gt;] &lt;br&gt;  [-OutBuffer &amp;lt;Int32&amp;gt;] [-Delimiter &amp;lt;String&amp;gt;] &lt;font color="#00ffff"&gt;[-Wait]&lt;/font&gt; [-Encoding &amp;lt;FileSystemCmdletProviderEncoding&amp;gt;]&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Hopefully this post has given you more knowledge about ByValue parameters and how to explore and get more information on cmdlet parameters in general.  In summary, there actually isn't much you need to know about ByValue pipeline bound parameters because in most cases they just work intuitively.  Just be sure to keep your eye out for those parameters that bind ByPropertyName. They are the ones whose pipeline bound usage isn't as obvious. &lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Effective+PowerShell+Item+12%3a+Understanding+ByValue+Pipeline+Bound+Parameters&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>Effective PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6158.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6158.entry</guid><pubDate>Sat, 10 May 2008 03:32:30 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6158/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6158.entry#comment</wfw:comment><dcterms:modified>2008-05-10T03:33:47Z</dcterms:modified></item><item><title>Windows PowerShell V2 CTP2 Is Available</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6142.entry</link><description>&lt;p&gt;The PowerShell team just posted the &lt;a href="http://blogs.msdn.com/powershell/archive/2008/05/02/announcing-the-release-of-community-technology-preview-2-ctp2-of-windows-powershell-v2.aspx" target="_blank"&gt;announcement&lt;/a&gt; late last night.  There is a download link in the announcement.  This drop has lots of new features like Module support for organizing and loading related functionality as well as transaction support for registry operations using the Registry provider.   There have also been some changes since the first CTP so take a look at the release notes. &lt;p&gt;Let me reiterate the caution that these are &amp;quot;preview&amp;quot; (the P in CTP) bits.  There aren't even consider beta quality although I would qualify that caution mostly applies to the new functionality.  That said, I would &lt;strong&gt;not&lt;/strong&gt; put these bits on a production machine.  In fact, there have been reports about incompatibility between the System Center Virtual Machine Manager latest drop and V2 CTP bits.   &lt;p&gt;If you don't have a spare/test PC on which to play with these bits then go grab &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=04D26402-3199-48A3-AFA2-2DC0B40A73B6&amp;amp;displaylang=en" target="_blank"&gt;Virtual PC&lt;/a&gt; (free), Virtual Server or VMWare and create a sandbox VM with which to play with this CTP.  You will want to create that image based on either Vista SP1 or Windows Server 2008 if you want to take the remote management features for a spin. &lt;p&gt;One last thing.  The Graphical PoweShell is new in this release and is in need of feedback.  Folks, now is the time to influence the direction of this feature.  If you wait too long the team won't have time to make anything but very minor changes.  So please use it for a while and send your feedback to &lt;a href="mailto:gPSFback@microsoft.com"&gt;gPSFback@microsoft.com&lt;/a&gt;.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Windows+PowerShell+V2+CTP2+Is+Available&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6142.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6142.entry</guid><pubDate>Sat, 03 May 2008 17:11:04 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6142/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6142.entry#comment</wfw:comment><dcterms:modified>2008-05-03T17:11:04Z</dcterms:modified></item><item><title>PowerShell Makes It Into Top 50 Programming Languages!</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6140.entry</link><description>&lt;p&gt;At #46 in the &lt;a href="http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html" target="_blank"&gt;TIOBE Programming Community Index for April 2008&lt;/a&gt;, PowerShell sits above such languages as:  &lt;ul&gt; &lt;li&gt;AppleScript  &lt;li&gt;Boo  &lt;li&gt;Caml  &lt;li&gt;Csh  &lt;li&gt;Eiffel  &lt;li&gt;Modula-2  &lt;li&gt;Oberon  &lt;li&gt;VBScript  &lt;li&gt;XSLT&lt;/ul&gt; &lt;p&gt;Now what can we do to bump it up the list a few spots past REXX (44), Tcl/Tk (39) and Bash (37)?  Hmm....&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+PowerShell+Makes+It+Into+Top+50+Programming+Languages!&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6140.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6140.entry</guid><pubDate>Fri, 25 Apr 2008 15:41:30 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6140/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6140.entry#comment</wfw:comment><dcterms:modified>2008-04-25T15:41:30Z</dcterms:modified></item><item><title>Effective PowerShell Item 11: Understanding ByPropertyName Pipeline Bound Parameters</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry</link><description>&lt;p&gt;Everybody likes to be efficient, right?  I mean we all generally like to solve a problem in an efficient way.  In PowerShell that usually culminates in a &amp;quot;one-liner&amp;quot;.  Honestly for pedagogical purposes I find it better much better to expand these terse, almost &lt;a href="http://en.wikipedia.org/wiki/Obfuscated_C" target="_blank"&gt;'Obfuscated C'&lt;/a&gt; style commands into multiple lines.  However there is no denying that when you want to bang out something quick at the console - given PowerShell's current line editing features - a one-liner helps stave off repetitive stress injuries.  It's not PowerShell's fault.  They're just using the antiquated console subsystem in Windows that hasn't changed much since NT shipped in 1993. 
&lt;p&gt;One trick to less typing is to take advantage of pipeline bound parameters.  Quite often I see folks write a command like: 
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Get-ChildItem . *.cs -r | foreach { get-content $_.fullname } | ...&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That works but the use of the &lt;em&gt;Foreach-Object&lt;/em&gt; cmdlet is technically unnecessary.  Many PowerShell cmdlets bind their &amp;quot;primary&amp;quot; parameter to the pipeline.  This is indicated in the help file for Get-Content as shown below: 
&lt;p&gt;&lt;font face="Courier New" size=2&gt;-path &amp;lt;string[]&amp;gt;&lt;br&gt;    Specifies the path to an item. Get-Content retrieves the content of the item. Wildcards &lt;br&gt;    are permitted. The parameter name (&amp;quot;-Path&amp;quot; or &amp;quot;-FilePath&amp;quot;) is optional. &lt;/font&gt;
&lt;p&gt;&lt;font face="Courier New" size=2&gt;    Required?                    true&lt;br&gt;    Position?                    1&lt;br&gt;    Default value                N/A - The path must be specified&lt;br&gt;&lt;strong&gt;    Accept pipeline input?       true (ByPropertyName)&lt;br&gt;&lt;/strong&gt;    Accept wildcard characters?  true &lt;/font&gt;
&lt;p&gt;&lt;font face="Courier New" size=2&gt;&amp;lt;snip&amp;gt;&lt;/font&gt; 
&lt;p&gt;&lt;font face="Courier New" size=2&gt;-literalPath &amp;lt;string[]&amp;gt;&lt;br&gt;    Specifies the path to an item. Unlike Path, the value of LiteralPath is used &lt;br&gt;&lt;/font&gt;&lt;font face="Courier New" size=2&gt;    exactly as it is typed. No characters are interpreted as wildcards. If the path &lt;br&gt;    includes escape characters, enclose it in single quotation marks.&lt;br&gt;    Single quotation marks tell Windows PowerShell not to interpret any characters as escape sequences. &lt;/font&gt;
&lt;p&gt;&lt;font face="Courier New" size=2&gt;    Required?                    true&lt;br&gt;    Position?                    1&lt;br&gt;    Default value&lt;br&gt;&lt;strong&gt;    Accept pipeline input?       true (ByPropertyName)&lt;br&gt;&lt;/strong&gt;    Accept wildcard characters?  false&lt;/font&gt; 
&lt;p&gt; &lt;font face="Courier New" size=2&gt;&lt;/font&gt; 
&lt;p&gt;Note that there are actually four parameters on &lt;em&gt;Get-Content&lt;/em&gt; that accept pipeline input &lt;em&gt;ByPropertyName&lt;/em&gt;.  Two of which are shown above.  The other two are ReadCount and TotalCount.  The qualifier &lt;em&gt;ByProperyName&lt;/em&gt; simply means that if the incoming object has a property of that name it is available to be &amp;quot;bound&amp;quot; as input to that parameter.  That is, if a type match can be found or coerced. 
&lt;p&gt;For instance, we could simplify the command above by eliminating the &lt;em&gt;Foreach-Object&lt;/em&gt; cmdlet altogether: 
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Get-ChildItem . *.cs -r | get-content | ...&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;While it is intuitive that Get-Content should be able to handle the System.IO.FileInfo objects that &lt;em&gt;Get-ChildItem&lt;/em&gt; outputs, it isn't obvious based on the &lt;em&gt;ByPropertyValue&lt;/em&gt; rule I just mentioned.  Why?  Well the FileInfo objects output by &lt;em&gt;Get-ChildItem&lt;/em&gt; don't have either a Path property or a &lt;em&gt;LiteralPath&lt;/em&gt; property even accounting for the extended properties like &lt;em&gt;PSPath&lt;/em&gt;.  So how the heck does &lt;em&gt;Get-Content&lt;/em&gt; determine the path of a file in this pipeline scenario?  There are at least two ways to find this out.  The first is the easier approach.  It uses a PowerShell cmdlet called &lt;em&gt;Trace-Command&lt;/em&gt; that shows you how PowerShell binds parameters.  The second approach involves spelunking in the PowerShell assemblies using Lutz Roeder's .NET Reflector.  Let's tackle this problem initially using &lt;em&gt;Trace-Command&lt;/em&gt;. 
&lt;p&gt;&lt;em&gt;Trace-Command&lt;/em&gt; is a built-in tracing facility that shows a lot of the inner workings of PowerShell.  I will warn you that it tends to be prolific with its output.  One particularly useful area you can trace is parameter binding.  Here's how we would do this for the command above: 
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Trace-Command -Name ParameterBinding -PSHost -Expression { Get-ChildItem log.txt | get-content }&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;This outputs a lot of text and unfortunately it is &amp;quot;Debug&amp;quot; stream text that isn't easily searchable or redirectable to a file.  Oh well.  The interesting output from this command are the following lines: 
&lt;p&gt;&lt;font face="Courier New" size=2&gt;     BIND PIPELINE object to parameters: [Get-Content]&lt;br&gt;         PIPELINE object TYPE = [System.IO.FileInfo]&lt;br&gt;         RESTORING pipeline parameter's original values&lt;br&gt;         Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION&lt;br&gt;         Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION&lt;br&gt;         Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION&lt;br&gt;         Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION&lt;br&gt;         Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION&lt;br&gt;         Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName NO COERCION&lt;br&gt;         Parameter [LiteralPath] PIPELINE INPUT ValueFromPipelineByPropertyName  NO COERCION&lt;br&gt; &lt;strong&gt;        BIND arg [Microsoft.PowerShell.Core\FileSystem::C:\Users\Keith\log.txt] to parameter [LiteralPath]&lt;/strong&gt;&lt;/font&gt; 
&lt;p&gt;This output has been simplified a bit to be more readable in this post.  I also changed the initial command to output just a single FileInfo object to reduce the amount of output.  The information we get from &lt;em&gt;Trace-Command&lt;/em&gt; shows us that PowerShell tries to bind the FileInfo object to the Get-Content parameters and fails (NO COERCION) on all except for the LiteralPath parameter.  OK well that tells us definitively how Get-Content is getting the path but it doesn't make sense.  There is no LiteralPath property on a FileInfo object and there is no extended property called LiteralPath either.  
&lt;p&gt;This is where the second technique of using .NET Reflector (download &lt;a href="http://www.aisto.com/roeder/dotnet/" target="_blank"&gt;here&lt;/a&gt;) can be used to see a reverse compiled version of the PowerShell source.  After starting .NET Reflector and loading the Microsoft.PowerShell.Commands.Management.dll assembly, we find the GetContentCommand and inspect the LiteralPath parameter shown below:&lt;pre&gt;[&lt;span style="color:rgb(43,145,175)"&gt;Alias&lt;/span&gt;(&lt;span style="color:rgb(0,0,255)"&gt;new&lt;/span&gt; &lt;span style="color:rgb(0,0,255)"&gt;string&lt;/span&gt;[] { &lt;span style="color:rgb(163,21,21)"&gt;&amp;quot;PSPath&amp;quot;&lt;/span&gt; }),
 &lt;span style="color:rgb(43,145,175)"&gt;Parameter&lt;/span&gt;(Position = 0, ParameterSetName = &lt;span style="color:rgb(163,21,21)"&gt;&amp;quot;LiteralPath&amp;quot;&lt;/span&gt;, Mandatory = &lt;span style="color:rgb(0,0,255)"&gt;true&lt;/span&gt;, ValueFromPipeline = &lt;span style="color:rgb(0,0,255)"&gt;false&lt;/span&gt;,
           ValueFromPipelineByPropertyName = &lt;span style="color:rgb(0,0,255)"&gt;true&lt;/span&gt;)]
&lt;span style="color:rgb(0,0,255)"&gt;public&lt;/span&gt; &lt;span style="color:rgb(0,0,255)"&gt;string&lt;/span&gt;[] LiteralPath { } &lt;/pre&gt;
&lt;p&gt;Note the Alias attribute on this parameter.  It creates another valid name for the LiteralPath parameter - PSPath which corresponds to the extended PSPath property on all FileInfo objects.  That is what allows the &lt;em&gt;ByPropertyName&lt;/em&gt; pipeline input binding to succeed.  The property named PSPath matches the parameter name albeit via an alias. 
&lt;p&gt;Where does that leave us?  There are a number  of cases where we can pipe an object directly to a cmdlet in the next stage of the pipeline because of pipeline input binding where PowerShell searches for the most appropriate parameter to bind that object to.  
&lt;p&gt;Here is another example of piping directly to another cmdlet without resorting to the use of the &lt;em&gt;Foreach-Object&lt;/em&gt; cmdlet: 
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Get-ChildItem *.txt | Rename-Item -NewName {$_.name + '.bak'}&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;You also now have a way to determine how PowerShell binds pipeline input to a parameter of a cmdlet.  And thanks to Reflector we know that some parameters have aliases like PSPath to assist in this binding process.  
&lt;p&gt;That's it for ByPropertyName pipeline input binding.  There is another type of pipeline input binding called ByValue that I'll cover in a future post.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Effective+PowerShell+Item+11%3a+Understanding+ByPropertyName+Pipeline+Bound+Parameters&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>Effective PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry</guid><pubDate>Mon, 07 Apr 2008 05:33:20 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6130/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6130.entry#comment</wfw:comment><dcterms:modified>2008-05-10T03:34:15Z</dcterms:modified></item><item><title>Nothing's Perfect Including PowerShell</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6121.entry</link><description>&lt;p&gt;Today I needed to count the number of errors in a log file.  Pretty straightforward stuff that I would typically accomplish like so: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;5&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Select-String '^\d+,Error' Messages.log | Measure-Object&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;And that normally works well for me - except for today.  It turns out that this log file is big, really big - as in 600MB worth of log file!  The command above runs for quite some time and then fails ignominiously with a System.OutOfMemoryException.  Sure enough, a quick execution of &amp;quot;gps -id $pid&amp;quot; revealed that the PowerShell process was consuming 1.7 GB of private memory.  No wonder we hit an OOM exception.  
&lt;p&gt;So back to the drawing board on how to accomplish this in PowerShell.  But first I had to do something about the memory footprint of my current PowerShell session.  In &lt;a href="http://www.codeplex.com/powershellcx" target="_blank"&gt;PowerShell Community Extensions &lt;/a&gt;we have a Collect function (which just calls [System.GC]::Collect()).  This brought the private memory footprint back down to ~76MB which tells me that PowerShell's pipeline or one of the cmdlets above is hoarding memory.  No matter.  One of the best things about PowerShell is this awesome escape hatch it provides - direct access to the .NET Framework.  Fortunately there is a simple class in the .NET Framework called System.IO.StreamReader that allows you to read text files a line at a time which is important when you' re dealing with huge log files.  Here is the resulting solution I came up with: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;7&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $sr = new-object System.IO.StreamReader(&amp;quot;$pwd\Messages.log&amp;quot;)&lt;br&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;8&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $sum = 0; while (($line = $sr.ReadLine()) -ne $null) {if ($line -match '^\d+,Error') {$sum++}}; $sum&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;2702996&lt;br&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;9&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; $sr.Dispose()&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;I monitored the private memory usage of the PowerShell process during the execution of this script.  The private memory usage increased about 200K and then didn't budge until the script was finished.  No doubt this contributed to the script finishing much faster as compared to the time it took my first attempt to finish, err, run out of memory -  1 min 43 secs versus 7 min 16 secs respectively. 
&lt;p&gt;When it comes to reading files, another useful .NET Framework method is the static method: [System.IO.File]::ReadAllText(string path) which returns a single string containing the file's entire contents.  If you ever need to load the entire contents of a file into a variable for manipulation (say you need to execute a regex over an entire file's contents  - not just line-by-line) this method is a good way to go. I find the ReadAllText() method a bit easier to use in this case than Get-Content piped to Out-String.  The other benefit of ReadAllText() is that it doesn't add an extra line terminator to the end of the string which is something Out-String will do.  It seems like Get-Content should have a parameter to indicate that it should read the entire file into a single string and output that.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Nothing's+Perfect+Including+PowerShell&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6121.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6121.entry</guid><pubDate>Sun, 02 Mar 2008 22:36:57 GMT</pubDate><slash:comments>6</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6121/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6121.entry#comment</wfw:comment><dcterms:modified>2008-03-02T23:06:15Z</dcterms:modified></item><item><title>PowerShell Community Extensions - It's the Little Things</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6118.entry</link><description>&lt;p&gt;Today I was posting about an issue I was having with Team Foundation Server 2008 HTML alert emails that get generated for check-ins.  The second column in the details area of the email is way too narrow.  I was able to copy/paste the HTML into Expression Web so I could get to the HTML.  I wanted to post that HTML into the MSDN Forum post editor but, well, it doesn't like you putting in non-escaped HTML.  Fortunately PowerShell and PSCX are at my beckon call.  Here is all I had to do to escape my HTML so I could paste it into the HtmlView of the MSDN forum editor: 
&lt;p&gt;
&lt;table bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;font color="#00ff00"&gt;PS&amp;gt;&lt;/font&gt; Get-Clipboard | Foreach {[System.Web.HttpUtility]::HtmlEncode($_)} | Out-Clipboard  &lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;I just love tools that save me time!&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+PowerShell+Community+Extensions+-+It's+the+Little+Things&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PSCX</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6118.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6118.entry</guid><pubDate>Wed, 20 Feb 2008 18:55:33 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6118/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6118.entry#comment</wfw:comment><dcterms:modified>2008-02-20T18:57:13Z</dcterms:modified></item><item><title>Microsoft Dev Days in Denver</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6098.entry</link><description>&lt;p&gt;If you want to get some free exposure to the VS 2008 and Office technologies, sign up for Dev Days.  It is coming to my local MS office (Denver) - details listed below. &lt;p&gt;&lt;b&gt;When&lt;/b&gt;: Thursday, January 31, 2008 8:30 AM - 5:00 PM&lt;br&gt;&lt;b&gt;Where&lt;/b&gt;: &lt;a href="http://maps.live.com/?v=2&amp;amp;where1=4900 S Syracuse St, Denver, CO 80237-2725&amp;amp;encType=1"&gt;Marriott DTC&lt;/a&gt;, 4900 S. Syracuse St, Denver Colorado 80237&lt;br&gt;&lt;b&gt;Registration is appreciated&lt;/b&gt;: &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032364690&amp;amp;culture=en-US"&gt;Click here to register&lt;/a&gt;&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Microsoft+Dev+Days+in+Denver&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>Software Development</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6098.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6098.entry</guid><pubDate>Tue, 08 Jan 2008 00:10:05 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6098/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6098.entry#comment</wfw:comment><dcterms:modified>2008-01-08T00:10:05Z</dcterms:modified></item><item><title>XPath Expressions and PSCX's Select-Xml</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6096.entry</link><description>&lt;p&gt;MoW wrote up a nice post on invoking XPATH expressions.  Check it out &lt;a href="http://thepowershellguy.com/blogs/posh/archive/2007/12/30/processing-xml-with-powershell.aspx" target="_blank"&gt;here&lt;/a&gt;.  Just wanted to let the PSCX users out there know that the equivalent of MoW's  &lt;div&gt; &lt;div&gt; &lt;div&gt; &lt;div&gt; &lt;div&gt; &lt;div&gt; &lt;div&gt;&lt;pre style="color:#eeedf0;background-color:#012456"&gt;PS I:\PowerShell&amp;gt; Function invoke-XpathExpression ([xml]$xml,$expression) {                                             
&amp;gt;&amp;gt;   $xn = $xml.PSBase.CreateNavigator()                                                                                
&amp;gt;&amp;gt;   $xn.Evaluate($expression)                                                                                          
&amp;gt;&amp;gt; }                                                                                                                    
&amp;gt;&amp;gt;    

                                                                                                                  
PS I:\PowerShell&amp;gt; # Example using the function                                                                          
PS I:\PowerShell&amp;gt;                                                                                                       
PS I:\PowerShell&amp;gt; invoke-XpathExpression -xml (type gl.xml) -exp &amp;quot;sum(GroceryList/Item/Price)&amp;quot;                          
29.15                                                                                                  &lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;in PSCX would be:
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Select-Xml gl.xml -xpath '/GroceryList/Item/Price' | measure value -sum&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Count    : 4&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Average  :&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Sum      : 29.15&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Maximum  :&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Minimum  :&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Property : Value&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Note that the PSCX cmdlet Select-Xml is oriented towards &amp;quot;selecting&amp;quot; node-sets hence the name.  Unfortunately xpath expressions that don't result in node-sets will error.  No worries though because PowerShell's Measure-Object cmdlet (measure alias provided by PSCX) can compute the sum easily. 
&lt;p&gt;OK so that was a bit shorter but what's the big deal.  Here's the deal.  If your XML uses XML namespaces then this all gets a good bit harder to deal with yourself.  Not impossible mind you.  I have written a &lt;a href="http://search.live.com/results.aspx?q=xml+xpath+site:keithhill.spaces.live.com&amp;amp;src=IE-SearchBox" target="_blank"&gt;number of posts&lt;/a&gt; on handling XML that uses XML namespaces but with Select-Xml it is pretty simple.  For instance, let's tweak the XML ever so slightly:
&lt;p&gt;&lt;font face="Courier New" size=2&gt;&amp;lt;GroceryList &lt;strong&gt;xmlns=&amp;quot;tempuri.org&amp;quot;&lt;/strong&gt;&amp;gt;&lt;br&gt;  &amp;lt;Item&amp;gt;&lt;br&gt;    &amp;lt;Dept&amp;gt;Produce&amp;lt;/Dept&amp;gt;&lt;br&gt;    &amp;lt;Name&amp;gt;Orange&amp;lt;/Name&amp;gt;&lt;br&gt;    &amp;lt;Price&amp;gt;3.20&amp;lt;/Price&amp;gt;&lt;br&gt;  &amp;lt;/Item&amp;gt;&lt;br&gt;  &amp;lt;Item&amp;gt;&lt;br&gt;    &amp;lt;Dept&amp;gt;Meat&amp;lt;/Dept&amp;gt;&lt;br&gt;    &amp;lt;Name&amp;gt;Steak&amp;lt;/Name&amp;gt;&lt;br&gt;    &amp;lt;Price&amp;gt;13.20&amp;lt;/Price&amp;gt;&lt;br&gt;  &amp;lt;/Item&amp;gt;&lt;br&gt;  &amp;lt;Item&amp;gt;&lt;br&gt;    &amp;lt;Dept&amp;gt;Produce&amp;lt;/Dept&amp;gt;&lt;br&gt;    &amp;lt;Name&amp;gt;Lettuce&amp;lt;/Name&amp;gt;&lt;br&gt;    &amp;lt;Price&amp;gt;1.34&amp;lt;/Price&amp;gt;&lt;br&gt;  &amp;lt;/Item&amp;gt;&lt;br&gt;  &amp;lt;Item&amp;gt;&lt;br&gt;    &amp;lt;Dept&amp;gt;Meat&amp;lt;/Dept&amp;gt;&lt;br&gt;    &amp;lt;Name&amp;gt;Ham&amp;lt;/Name&amp;gt;&lt;br&gt;    &amp;lt;Price&amp;gt;11.41&amp;lt;/Price&amp;gt;&lt;br&gt;  &amp;lt;/Item&amp;gt;&lt;br&gt;&amp;lt;/GroceryList&amp;gt;&lt;/font&gt;
&lt;p&gt;Note the default namespace declaration on the root element.  Now the previous XPath expressions won't work but here is all we need to do with Select-Xml to make this work:
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;PS&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; Select-Xml gl.xml -xpath '/ns:GroceryList/ns:Item/ns:Price' -Namespace &amp;quot;ns=tempuri.org&amp;quot; |&lt;br&gt;&amp;gt;&amp;gt; measure value -sum&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Count    : 4&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Average  :&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Sum      : 29.15&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Maximum  :&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Minimum  :&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Property : Value&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;All we needed to do was provide the namespace and a temp prefix (ns) to use in the xpath query.  Note that the -Namespace parameter will take an array of strings that match this format: &amp;quot;&amp;lt;prefix&amp;gt;=&amp;lt;namespace&amp;gt;&amp;quot;.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+XPath+Expressions+and+PSCX's+Select-Xml&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PSCX</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6096.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6096.entry</guid><pubDate>Wed, 02 Jan 2008 08:20:44 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6096/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6096.entry#comment</wfw:comment><dcterms:modified>2008-01-02T08:20:44Z</dcterms:modified></item><item><title>Renewed as Windows PowerShell MVP for 2008</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6093.entry</link><description>&lt;p&gt;Woohoo!  Just got word earlier today.  I look forward to another awesome year of PowerShell adoption and just maybe v 2.0 - hopefully.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Renewed+as+Windows+PowerShell+MVP+for+2008&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6093.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6093.entry</guid><pubDate>Wed, 02 Jan 2008 07:13:27 GMT</pubDate><slash:comments>1</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6093/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6093.entry#comment</wfw:comment><dcterms:modified>2008-01-02T07:13:27Z</dcterms:modified></item><item><title>Windows PowerShell Help Available Online</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6086.entry</link><description>&lt;p&gt;Just got word that the PowerShell help is now available &lt;a href="http://technet.microsoft.com/en-us/library/bb978526.aspx" target="_blank"&gt;online on the TechNet site&lt;/a&gt;.  This is very nice because we will now be able to reference PowerShell help topics by URL like say the &lt;a href="http://technet.microsoft.com/en-us/library/bb978676.aspx" target="_blank"&gt;help topic for the Certificate provider&lt;/a&gt;.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Windows+PowerShell+Help+Available+Online&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6086.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6086.entry</guid><pubDate>Tue, 18 Dec 2007 17:39:34 GMT</pubDate><slash:comments>0</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6086/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6086.entry#comment</wfw:comment><dcterms:modified>2007-12-18T17:39:34Z</dcterms:modified></item><item><title>Visual Studio 2008 Training Kit Requires PowerShell</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6077.entry</link><description>&lt;p&gt;I just &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=8BDAA836-0BBA-4393-94DB-6C3C4A0C98A1&amp;amp;displaylang=en&amp;amp;mdc_uxref=sl" target="_blank"&gt;downloaded this training kit&lt;/a&gt; and took a look at its requirements and guess what - PowerShell is required!  Cool. 
&lt;blockquote&gt;
&lt;h4&gt;&lt;em&gt;Prerequisite software&lt;/em&gt;&lt;/h4&gt;&lt;em&gt;The following software packages must be installed in order to complete the labs in this training kit. Items that are required only for specific parts of the kit are indicated below. &lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Microsoft Windows Vista &lt;/em&gt;
&lt;li&gt;&lt;em&gt;Microsoft Visual Studio 2008 &lt;/em&gt;
&lt;li&gt;&lt;em&gt;Microsoft SQL Server 2005 (Express recommended) &lt;/em&gt;
&lt;li&gt;&lt;em&gt;Microsoft IIS 7 (All components) &lt;/em&gt;
&lt;li&gt;&lt;em&gt;Microsoft Office Powerpoint 2007 or the &lt;/em&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=048dc840-14e1-467d-8dca-19d2a8fd7485&amp;amp;displaylang=en"&gt;&lt;em&gt;PowerPoint Viewer 2007&lt;/em&gt;&lt;/a&gt;&lt;em&gt; - Required to view the presentations &lt;/em&gt;
&lt;li&gt;&lt;a href="http://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx"&gt;&lt;em&gt;Windows PowerShell 1.0 RTM&lt;/em&gt;&lt;/a&gt;&lt;/ul&gt;&lt;/blockquote&gt;
&lt;p&gt;After looking through the installed files, it appears that PowerShell is being used for primarily testing code via verify.ps1 and testLib.ps1 scripts.  Here are all the PowerShell script files used by the training kit:
&lt;blockquote dir=ltr style="margin-right:0px"&gt;
&lt;p&gt;&lt;em&gt;D:\VS2008TrainingKit\Labs\CardSpace\Ex01-RegisterWithCardSpace\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\CardSpace\Setup\scripts\elevate.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\CardSpace\Setup\scripts\powershellscripts\CertificatesLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\CardSpace\Setup\scripts\powershellscripts\HostLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\CardSpace\Setup\scripts\powershellscripts\setdefaultdocument.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex01-DataAccessWithLINQ\begin\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex01-DataAccessWithLINQ\begin\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex01-DataAccessWithLINQ\end\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex01-DataAccessWithLINQ\end\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\begin\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\begin\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\begin\PowerShellTests\vs90vars.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\begin\PowerShellTests\wcfserviceTest.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\end\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\end\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\end\PowerShellTests\vs90vars.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\DynamicSites\Ex02-ExposeData\end\PowerShellTests\wcfserviceTest.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\LinqToSql\Ex01-DalUsingLinq\begin\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\LinqToSql\Ex01-DalUsingLinq\begin\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\LinqToSql\Ex01-DalUsingLinq\begin\PowerShellTests\vs90vars.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\LinqToSql\Ex01-DalUsingLinq\end\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\LinqToSql\Ex01-DalUsingLinq\end\PowerShellTests\verify.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\LinqToSql\Ex01-DalUsingLinq\end\PowerShellTests\vs90vars.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\WF\Ex01-CreateStateMachineWF\begin\PowerShellTests\testLib.ps1&lt;br&gt;D:\VS2008TrainingKit\Labs\WF\Ex01-CreateStateMachineWF\begin\PowerShellTests\verify.ps1&lt;/em&gt;&lt;/blockquote&gt;
&lt;p&gt;It is really great to see the devdiv folks adopting PowerShell.  The requirement to have PowerShell installed will help adoption in the developer space which I think is on the verge of exploding anyway.&lt;img src="http://c.services.spaces.live.com/CollectionWebService/c.gif?cid=6524913499512388247&amp;page=RSS%3a+Visual+Studio+2008+Training+Kit+Requires+PowerShell&amp;referrer=" width="1px" height="1px" border="0" alt=""&gt;&lt;img style="position:absolute" alt="" width="0px" height="0px" src="http://c.live.com/c.gif?NC=31263&amp;amp;NA=1149&amp;amp;PI=73329&amp;amp;RF=&amp;amp;DI=3919&amp;amp;PS=85545&amp;amp;TP=keithhill.spaces.live.com&amp;amp;GT1=keithhill"&gt;</description><category>PowerShell</category><comments>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6077.entry#comment</comments><guid isPermaLink="true">http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6077.entry</guid><pubDate>Sun, 02 Dec 2007 17:32:57 GMT</pubDate><slash:comments>3</slash:comments><msn:type>blogentry</msn:type><live:type>blogentry</live:type><live:typelabel>Blog entry</live:typelabel><wfw:commentRss>http://keithhill.spaces.live.com/blog/cns!5A8D2641E0963A97!6077/comments/feed.rss</wfw:commentRss><wfw:comment>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6077.entry#comment</wfw:comment><dcterms:modified>2007-12-02T17:36:21Z</dcterms:modified></item><item><title>Effective PowerShell Item 10: Understanding PowerShell Parsing Modes</title><link>http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!6058.entry</link><description>&lt;p&gt;The way PowerShell parses commands can be surprising especially to those that are used to shells with more simplistic parsing like CMD.EXE.  Parsing in PowerShell is a bit different because PowerShell needs to work well as both an interactive command line shell &lt;strong&gt;and&lt;/strong&gt; a scripting language.  This need is driven by use cases such as: 
&lt;ol&gt;
&lt;li&gt;Allow execution of commands and programs with parameters at the command line.  Consequence: names (filenames, paths) should not &lt;strong&gt;require&lt;/strong&gt; quotes unless there is a space in the name  (or path). 
&lt;li&gt;Allow scripts to contain expressions as found in most other programming/script languages.  Consequence: PowerShell script should be able to evaluate expressions like &lt;em&gt;2 + 2&lt;/em&gt; and &lt;em&gt;$date.Second &lt;/em&gt;as well as specify string using quotes e.g. &amp;quot;del -r * is being executed&amp;quot;. 
&lt;li&gt;Take code written interactively at the command line and paste it into a script for execution again at some point in the future. Consequence: These two worlds - interactive and script - need to coexist peacefully.&lt;/ol&gt;
&lt;p&gt;Part and parcel with providing a powerful scripting language is to support more types than just the string type.  In fact, PowerShell supports most .NET types including &lt;em&gt;String&lt;/em&gt;, &lt;em&gt;Int8&lt;/em&gt;, &lt;em&gt;Int16&lt;/em&gt;, &lt;em&gt;Int32&lt;/em&gt;, &lt;em&gt;Decimal&lt;/em&gt;, &lt;em&gt;Single&lt;/em&gt;, &lt;em&gt;Double&lt;/em&gt;, &lt;em&gt;Boolean&lt;/em&gt;, &lt;em&gt;Array&lt;/em&gt;, &lt;em&gt;ArrayList&lt;/em&gt;, &lt;em&gt;StringBuilder&lt;/em&gt; among many, many other .NET types.  That's very nice you say but what's this got to do with parsing modes?  Think about this.  How would you expect a language to represent a string literal?  Well most folks would probably expect this representation: &amp;quot;Hello World&amp;quot; 
&lt;p&gt;And in fact, that is recognized by PowerShell as a string e.g.: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; &amp;quot;Hello World&amp;quot;.GetType().Name&lt;/span&gt;
&lt;span style="color:rgb(255,255,255)"&gt;String&lt;br&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; &amp;quot;Hello World&amp;quot;&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;Hello World&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;And if you type a string at the prompt and hit the &lt;em&gt;Enter&lt;/em&gt; key, PowerShell, being a very nice &lt;a href="http://en.wikipedia.org/wiki/REPL" target="_blank"&gt;REPL&lt;/a&gt; environment, echoes the string back to the console as shown above.  However what if I had to specify filenames using quotes as shown below? 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; del &amp;quot;foo.txt&amp;quot;, &amp;quot;bar.txt&amp;quot;, &amp;quot;baz.txt&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That would immediately &amp;quot;feel&amp;quot; different than any other command line shell out there.  Even worse, typing all those quotes would get really annoying, really fast.  What to do, what to do?  Well my guess is that the team, pretty early on, decided that they were going to need two different ways to parse.  First they would need to parse like a traditional shell where strings (filenames, dir names, process names, etc) do not need to be quoted.  Second they would need to be able to parse like a traditional language where strings are quoted and expressions feel like those you would find in a programming language.  In PowerShell, the former is called Command parsing mode and the latter is called Expression parsing mode. It is important to understand which mode you are in and more importantly, how you can manipulate the parsing mode. 
&lt;p&gt;Let's look at an example.  Obviously we would prefer to type the following to delete files: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt; &lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;del foo.txt, bar.txt, baz.txt&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That's better.  No bloody quotes required on the filenames.  PowerShell treats these filenames as strings even without the quotes in command parsing mode.  But what happens if my path has a space in it?  You would naturally try: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; del 'C:\Documents and Settings\Keith\_lesshst'&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;And that works as you would expect.  OK now what if I want to execute a program with a space in its path: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; 'C:\Program Files\Windows NT\Accessories\wordpad.exe'&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;C:\Program Files\Windows NT\Accessories\wordpad.exe&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;That didn't work because are far as PowerShell is concerned we gave it a string, so it just echoes it back to the screen.  It did this because it parsed this line in expression mode.  We need to tell PowerShell to parse the line in command mode.  To do that we use the call operator '&lt;font face="Courier New" size=3&gt;&amp;amp;&lt;/font&gt;' like so: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; &lt;/span&gt;&lt;span style="color:rgb(255,255,255)"&gt;&amp;amp; 'C:\Program Files\Windows NT\Accessories\wordpad.exe'&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Help prevent repetitive stress injuries to your wrists and use tab (and shift+tab) completion for auto-completing the parts of a path.  If the resulting path contains a space PowerShell will insert the call operator for you as well as surround the path with quotes.  &lt;/em&gt;
&lt;p&gt;What's going on with this example is that PowerShell looks at the first non-whitespace character of a line to determine which mode to start parsing in.  If it sees &lt;font face="Courier New" size=2&gt;[_aA-zZ]&lt;/font&gt; or &lt;font face="Courier New" size=2&gt;&amp;amp;&lt;/font&gt; or &lt;font face="Courier New" size=2&gt;.&lt;/font&gt; or &lt;font face="Courier New" size=2&gt;\&lt;/font&gt; then PowerShell parses in Command mode.  One exception to these rules happens when the line starts with a name that corresponds to a PowerShell language keyword like &amp;quot;if&amp;quot;, &amp;quot;do&amp;quot;, &amp;quot;while&amp;quot;, etc.  In this case, PowerShell uses expression parsing mode and expects you to provide the rest of the syntax associated with that keyword.  The benefits of Command mode are: 
&lt;ul&gt;
&lt;li&gt;Strings do not need to be quoted unless there are embedded spaces in the string. 
&lt;li&gt;Numbers are parsed as numbers and all other arguments are treated as strings except those that start with the characters: &lt;font face="Courier New" size=2&gt;@&lt;/font&gt;, &lt;font face="Courier New" size=2&gt;$&lt;/font&gt;, &lt;font face="Courier New" size=2&gt;(&lt;/font&gt;, &lt;font face="Courier New" size=2&gt;' &lt;/font&gt;or &lt;font face="Courier New" size=2&gt;&amp;quot;&lt;/font&gt;.  Numbers are interpreted as either &lt;em&gt;Int32&lt;/em&gt;, &lt;em&gt;Int64&lt;/em&gt;, &lt;em&gt;Double&lt;/em&gt; or &lt;em&gt;Decimal&lt;/em&gt; depending on how the number is decorated and the range required to hold the number e.g. 12, 30GB, 1E-3, 100.01d.&lt;/ul&gt;
&lt;p&gt;So why do we need expression parsing mode?  Well as I mentioned before it sure would be nice to be able to evaluate expressions like so: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt;&lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt; 64-2&lt;/span&gt;
&lt;font color="#ffffff"&gt;62&lt;/font&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;It isn't a stretch to see how some shells might interpret this example as trying to invoke a command named '64-2'.  So how does PowerShell determine if the line should be parsed in expression mode?  If the line starts with a number [0-9] or one of these characters: &lt;font face="Courier New" size=2&gt;@&lt;/font&gt;, &lt;font face="Courier New" size=2&gt;$&lt;/font&gt;, &lt;font face="Courier New" size=2&gt;(&lt;/font&gt;, &lt;font face="Courier New" size=2&gt;' &lt;/font&gt;or &lt;font face="Courier New" size=2&gt;&amp;quot;&lt;/font&gt; then the line is evaluated in expression mode. The benefits of expression mode are: 
&lt;ul&gt;
&lt;li&gt;It is possible to disambiguate commands from strings e.g. &lt;em&gt;&lt;u&gt;del -recurse *&lt;/u&gt;&lt;/em&gt; is a command whereas &lt;em&gt;&amp;quot;del -recurse *&amp;quot;&lt;/em&gt; is just a string. 
&lt;li&gt;Arithmetic and comparison expressions are straight forward to specify e.g. 64-2 (62) and $array.count -gt 100.  In command mode, -gt would be interpreted as a parameter if in fact the previous token corresponded to a valid command.&lt;/ul&gt;
&lt;p&gt;One consequence of the rules for expression parsing mode is that if you want to execute an EXE or script whose name starts with a number you have to quote the name and use the call operator e.g.: 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt; &lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;&amp;amp; '64E1'&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;If you were to attempt to execute &amp;quot;64E1&amp;quot; without using the call operator, PowerShell can't tell if you want to interpret that as the number 64E1 (640) or execute the exe named 64E1.exe or the script named 64E1.ps1.  It is up to you to make sure you have placed PowerShell in the correct parsing mode to get the behavior you want which in this case means putting PowerShell into command parsing mode by using the call operator.  Note I have observed that if you specify the full command name e.g. 64E1.ps1 or 64E1.exe, it isn't necessary to quote the command. 
&lt;p&gt;Now what if you want to mix and match parsing modes on the same line?  Easy.  Just use either a grouping expression &lt;font face="Courier New" size=2&gt;()&lt;/font&gt;, a subexpression&lt;font face="Courier New" size=2&gt; $()&lt;/font&gt; or an array subexpression &lt;font face="Courier New" size=2&gt;@(). &lt;/font&gt;This will cause the parser to re-evaluate the parsing mode based on the first non-whitespace character inside the parens.  
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Sidebar:&lt;/strong&gt; What's the difference between grouping expressions (), subexpressions $() and array subexpressions @()?  A grouping expression can contain just a single statement.  A subexpression can contain multiple semicolon separated statements.  The output of each statement contributes to the output of the subexpression.  An array subexpression behaves just like a subexpression except that it guarantees that the output will be an array.  The two cases where this makes a difference are 1) there is no output at all so the result will be an empy array and 2) the result is a scalar value so the result will be a single element array containg the scalar value.  If the output is already an array then the use of an array subexpession will have no affect on the output i.e. array subexpressions do not wrap arrays inside of another array.&lt;/em&gt; 
&lt;p&gt; In the following example I have embedded a command &amp;quot;Get-ChildItem C:\Windows&amp;quot; into a line that started out parsing in expression mode.  When it encounters the grouping expression (get-childitem c:\windows), it begins parsing mode re-evaluation, finds the character &lt;font face="Courier New" size=2&gt;'g'&lt;/font&gt; and kicks into command mode parsing for the remainder of the text inside the grouping expression.  Note that &amp;quot;.Length&amp;quot; is parsed using expression mode because it is outside the grouping expression, so PowerShell reverts back to the previous parsing mode.  &amp;quot;.Length&amp;quot; instructs PowerShell to get the Length property of the object output by what was evaluated inside the grouping expression.  In this case, it is an array of FileInfo and DirectoryInfo objects.  The Length property tells us how many items are in that array. 
&lt;p&gt;
&lt;table width="90%" bgcolor=black border=0&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;pre&gt;&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;font color="#c0c0c0"&gt;PS&amp;gt; &lt;/font&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;10 + (get-childitem c:\windows).Length&lt;/span&gt;
&lt;b&gt;&lt;span style="color:rgb(0,255,0)"&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="color:rgb(255,255,255)"&gt;115&lt;/span&gt;&lt;/pre&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;We can do the opposite.  That is, put express