{"id":8931,"date":"2012-06-26T00:01:00","date_gmt":"2012-06-26T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/06\/26\/search-windows-index-with-powershell-helping-with-input\/"},"modified":"2012-06-26T00:01:00","modified_gmt":"2012-06-26T00:01:00","slug":"search-windows-index-with-powershell-helping-with-input","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/search-windows-index-with-powershell-helping-with-input\/","title":{"rendered":"Search Windows Index with PowerShell: Helping with Input"},"content":{"rendered":"<p><b>Summary<\/b>: Guest blogger, James O&#8217;Neill, uses Windows PowerShell to help users with input for searching the Windows Index.\nMicrosoft Scripting Guy, Ed Wilson, is here. Today James O&rsquo;Neill is back with Part Two.<\/p>\n<p style=\"padding-left: 30px\"><b>Note<\/b>: This is Part Two of a three part series about using Windows PowerShell to search the Windows Index. Yesterday, James talked about <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/06\/25\/build-a-query-to-search-the-windows-index-from-powershell.aspx\" target=\"_blank\">building a query string to search the Windows Index<\/a>.\nTake it away, James&hellip;\nIn Part One, I developed a working Windows PowerShell function to query the Windows Index. It outputs data rows, which isn&#8217;t the ideal behaviour, and I&#8217;ll address that in Part Three. Today, I&#8217;ll address another drawback: search terms passed as parameters to the function must be &#8220;SQL-Ready.&#8221; I think that makes for a bad user experience, so I am going to look at the half-dozen bits of logic that I added to allow my function to process input that is a little more human. Regular expressions are the way to recognize text that must be changed, and I&#8217;ll pay particular attention to those because I know a lot of people find them daunting. Let&rsquo;s address the items from yesterday&rsquo;s list that I want the function to do for me&hellip;<\/p>\n<h3>Replace* with %<\/h3>\n<p>SQL statements use <b>%<\/b> for a wildcard, but selecting files at the command prompt traditionally uses <b>*<\/b>. It&#8217;s a simple matter to replace. For the need to &#8220;escape&#8221; the <b>*<\/b> character, replacing <b>*<\/b> with <b>%<\/b> would be as simple as a <b>&ndash;Replace<\/b> statement gets. This command is shown here.<\/p>\n<p style=\"padding-left: 30px\">$Filter = $Filter -replace &#8220;*&#8221;,&#8221;%&#8221;\nFor some reason, I am never sure if the camera maker is Canon or Cannon, so I would rather search for Can*&hellip;or rather Can%, and that replace operation will turn &#8220;CameraManufacturer=Can*&#8221; into &#8220;CameraManufacturer=Can%&#8221;. It is worth noting that &ndash;<b>Replace<\/b> is just as happy to process an array of strings in <b>$filter<\/b> as it is to process one.\nSearching for a term across all fields uses &#8220;CONTAINS (*,&#8217;Stingray&#8217;)&#8221;, and if the &ndash;<b>Replace<\/b> operation changes <b>*<\/b> to <b>%<\/b> inside CONTAINS(), the result is no longer a valid SQL statement. So the regular expression needs to be a little more sophisticated, using a &#8220;negative look behind.&#8221;<\/p>\n<p style=\"padding-left: 30px\">$Filter = $Filter -replace &#8221; &#8220;(?&lt;!(s*)*&#8221;,&#8221;%&#8221;\nTo filter out cases like CONTAINS(*&hellip; , the new regular expression qualifies &#8220;Match on *&#8221;, with a look behind &#8220;(?&lt;!(s*)&#8221;, which says, &#8220;If it isn&rsquo;t immediately preceded by an opening bracket and any spaces.&#8221; In regular expression syntax:<\/p>\n<ul>\n<li>(?= x) says, &#8220;Look ahead for x&#8221;<\/li>\n<li>(?&lt;= x) says, &#8220;Look behind for x&#8221;<\/li>\n<li>(?!= x) is &ldquo;look ahead for anything EXCEPT x&rdquo;<\/li>\n<li>(?&lt;!x) is &ldquo;look behind for anything EXCEPT x&rdquo;<\/li>\n<\/ul>\n<p>These will see a lot of use in this function. Here, (?&lt;!&nbsp;&nbsp;&nbsp; ) is being used. The open bracket needs to be escaped, so it is written as ( , and s* means 0 or more spaces.<\/p>\n<h3>Convert orphan search terms into Contains conditions<\/h3>\n<p>A term that needs to be wrapped as a &#8220;CONTAINS&#8221; search can be identified by the absence of quotation marks, = , &lt; , or &gt; signs, or the LIKE, CONTAINS, or FREETEXT search predicates. When these are present, the search term is left alone; otherwise, it goes to CONTAINS like this.<\/p>\n<p style=\"padding-left: 30px\">$filter = ($filter | ForEach-Object {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($_ -match &#8220;&#8216;|=|&lt;|&gt;|like|contains|freetext&#8221;) {$_}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {&#8220;Contains(*,&#8217;$_&#8217;)&#8221;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; })<\/p>\n<h3>Add quotation marks if the user omits them<\/h3>\n<p>The next thing I check for is omitted quotation marks. I said I wanted to be able to use <b>Can*<\/b>, and we&rsquo;ve seen it changed to <b>Can%<\/b>, but the search term needs to be transformed into &#8220;CameraManufacturer=&#8217;Can%&#8217; &#8220;. Here is a <b>&ndash;Replace <\/b>operation to do that:<\/p>\n<p style=\"padding-left: 30px\">$Filter = $Filter -replace &#8220;s*(=|&lt;|&gt;|like)s*([^&#8217;d][^s&#8217;]*)$&#8221;,&#8217; $1 &#8221;$2&#8221; &#8216;\nThis is a more complex regular expression which takes a few moments to understand.<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"158\">  <b>Regular expression<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p><b>Meaning<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p><b>Application <\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p><b><span style=\"text-decoration: underline\">s*<\/span><\/b>(=|&lt;|&gt;|like)<b><span style=\"text-decoration: underline\">s*<\/span><\/b><br \/> ([^&#8217;d][^s&#8217;]*)$<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Any spaces (or none)<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*<b>(=|&lt;|&gt;|like)<\/b>s*<br \/> ([^&#8217;d][^s&#8217;]*)$<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>= or &lt; or &gt; or &#8220;Like&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer<b><span style=\"text-decoration: underline\">=<\/span><\/b>Can%<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*(=|&lt;|&gt;|like)s*<br \/> (<b><span style=\"text-decoration: underline\">[^&#8217;d]<\/span><\/b>[^s&#8217;]*)$<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Anything that is NOT a &#8216; character or a digit<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer=<b><span style=\"text-decoration: underline\">C<\/span><\/b>an%<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*(=|&lt;|&gt;|like)s*<br \/> ([^&#8217;d]<b><span style=\"text-decoration: underline\">[^s&#8217;]*<\/span><\/b>)$<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Any number of non-quotation mark, non-space characters (or none)<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer=C<b><span style=\"text-decoration: underline\">an%<\/span><\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*(=|&lt;|&gt;|like)s*<br \/> ([^&#8217;d][^s&#8217;]*)<b><span style=\"text-decoration: underline\">$<\/span><\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>End of line<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*<b><span style=\"text-decoration: underline\">(<\/span><\/b>=|&lt;|&gt;|like<b><span style=\"text-decoration: underline\">)<\/span><\/b>s*<br \/> <b><span style=\"text-decoration: underline\">(<\/span><\/b>[^&#8217;d][^s&#8217;]*<b><span style=\"text-decoration: underline\">)<\/span><\/b>$<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Capture the enclosed sections as matches<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>$Matches[0]=&nbsp; &#8220;=Can%&#8221;<br \/> $Matches[1]=&nbsp; &#8220;=&#8221;<br \/> $Matches[2]=&nbsp; &#8220;Can%&#8221;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>&#8216; $1 &#8221;$2&#8221; &#8216;0<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Replace Matches[0] (&#8220;=Can%&#8221;) with an expression that uses the two submatches &#8220;=&#8221; and &#8220;can%&#8221;.<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>&nbsp;= &#8216;Can%&#8217;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"padding-left: 30px\"><b>Note<\/b>&nbsp;&nbsp;&nbsp;The expression that is being inserted uses $1 and $2 to mean matches [1] and [2]. If this is wrapped in double quotation marks, Windows PowerShell will try to evaluate these terms before they get to the regex handler, so the replacement string must be wrapped in single quotation marks. But the desired replacement text contains single quotation marks, so they need to be doubled up.<\/p>\n<h3>Replace &#8216;=&#8217; with &#8216;like&#8217; for wildcards<\/h3>\n<p>So far, =Can* has become =&#8217;Can%&#8217;, which is good, but SQL needs &#8220;LIKE&#8221; instead of &#8220;=&#8221; to evaluate a wildcard. So the next operation converts &#8220;CameraManufacturer = &#8216;Can%&#8217; &#8221; into &#8220;CameraManufacturer LIKE &#8216;Can%&#8217; &#8220;.<\/p>\n<p style=\"padding-left: 30px\">$Filter = $Filter -replace &#8220;s*=s*(?=&#8217;.+%&#8217;s*$)&#8221; ,&#8221; LIKE &#8220;<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"158\">  <b>Regular expression<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p><b>Meaning<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p><b>Application<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p><b><span style=\"text-decoration: underline\">s*=s*<\/span><\/b>(?=&#8217;.+%&#8217;s*$)<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>= sign surrounded by any spaces<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer<b><span style=\"text-decoration: underline\"> = <\/span><\/b>&#8216;Can%&#8217;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*=s*(?=<b><span style=\"text-decoration: underline\">&#8216;<\/span><\/b>.+%&#8217;s*$)<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>A quotation mark character<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer = <b><span style=\"text-decoration: underline\">&#8216;<\/span><\/b>Can%&#8217;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*=s*(?=&#8217;<b><span style=\"text-decoration: underline\">.+<\/span><\/b>%&#8217;s*$)<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Any characters (at least one)<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer = &#8216;<b><span style=\"text-decoration: underline\">Can<\/span><\/b>%&#8217;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*=s*(?=&#8217;.+<b><span style=\"text-decoration: underline\">%&#8217;<\/span><\/b>s*$)<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>% character followed by &#8216;<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>CameraManufacturer = &#8216;Can<b><span style=\"text-decoration: underline\">%&#8217;<\/span><\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*=s*(?=&#8217;.+%&#8217;<b><span style=\"text-decoration: underline\">s*$<\/span><\/b>)<\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Any spaces (or none) followed by end of line<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"158\">\n<p>s*=s*<b><span style=\"text-decoration: underline\">(?=<\/span><\/b>&#8216;.+%&#8217;s*$<b><span style=\"text-decoration: underline\">)<\/span><\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"246\">\n<p>Look ahead for the enclosed expression, but don&#8217;t include it in the match<\/p>\n<\/td>\n<td valign=\"top\" width=\"212\">\n<p>$Matches[0] = &#8220;=&#8221; <br \/> (but only if &#8216;Can%&#8217; is present)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Provide aliases<\/h3>\n<p>The previous steps reconstruct &#8220;WHERE&#8221; terms to build syntactically correct SQL, but what if I get confused and enter CameraMaker instead of CameraManufacturer or Keyword instead of Keyword<span style=\"text-decoration: underline\">s<\/span>? I need Aliases, and they should work anywhere in the SQL statement&mdash;not just in the &#8220;WHERE&#8221; clause, but also in &#8220;ORDER BY&#8221;.\nI defined a hash table (aka a &#8220;dictionary&#8221; or an &#8220;associative array&#8221;) near the top of the script to act as a single place to store the aliases with their associated full canonical names, like this:<\/p>\n<p style=\"padding-left: 30px\">$PropertyAliases = @{Width=&#8221;System.Image.HorizontalSize&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Height=&#8221;System.Image.VerticalSize&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name=&#8221;System.FileName&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Extension=&#8221;System.FileExtension&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Keyword=&#8221;System.Keywords&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CameraMaker=&#8221;System.Photo.CameraManufacturer }\nLater in the script, after the SQL statement is built, a loop runs through the aliases replacing each with its canonical name:<\/p>\n<p style=\"padding-left: 30px\">$PropertyAliases.Keys | ForEach-Object {<br \/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL= $SQL -replace &#8220;(?&lt;=s)$($_)(?=s*(=|&gt;|&lt;|,|Like))&#8221;,$PropertyAliases[$_]<\/p>\n<p style=\"padding-left: 30px\">}\nA hash table has <b>.Keys<\/b> and <b>.Values<\/b> properties, which return what is on the left and right of the equals sign respectively. $hashTable.keyName or $hashtable[keyName] will return the value, so <b>$_<\/b> will start by taking the value &#8220;width&#8221;, and its replacement will be $PropertyAliases[&#8220;width&#8221;], which is &#8220;System.Image.HorizontalSize&#8221;. On the next pass through the loop, &#8220;height&#8221; is replaced, and so on. To ensure that it matches on a field name and not text being searched for, the regular expression stipulates that the name must be preceded by a space and followed by &#8220;=&#8221;or &#8220;like&#8221;, and so on.<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"222\">  <b>Regular expression<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p><b>Meaning<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p><b>Application <\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)<b><span style=\"text-decoration: underline\">Width<\/span><\/b>(?=s*(=|&gt;|&lt;|,|Like))<\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p>The literal text &#8220;Width&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p>&nbsp; <b><span style=\"text-decoration: underline\">Width<\/span><\/b> &gt; 1024<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=<b><span style=\"text-decoration: underline\">s<\/span><\/b>)Width(?=s*(=|&gt;|&lt;|,|Like))<\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p>A space<\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p><b><span style=\"text-decoration: underline\">(?&lt;=<\/span><\/b>s<b>)<\/b>Width(?=s*(=|&gt;|&lt;|,|Like))<\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p>Look behind for the enclosed expression, but don&#8217;t include it in the match.<\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p>$Matches[0] = &#8220;Width&#8221; <br \/> (but only if a leading space is present)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)Width(?=<b><span style=\"text-decoration: underline\">s*<\/span><\/b>(=|&gt;|&lt;|,|Like))<\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p>Any spaces (or none)<\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)Width(?=s*<b><span style=\"text-decoration: underline\">(=|&gt;|&lt;|,|Like)<\/span><\/b>)<\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p>The literal text &#8220;Like&#8221;, or any of the following characters: comma, equals, greater than, or less than<\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p>&nbsp; Width <b><span style=\"text-decoration: underline\">&gt;<\/span><\/b> 1024<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)Width<b><span style=\"text-decoration: underline\">(?=<\/span><\/b>s*(=|&gt;|&lt;|,|Like)<b><span style=\"text-decoration: underline\">)<\/span><\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"209\">\n<p>Look ahead for the enclosed expression, but don&#8217;t include it in the match.<\/p>\n<\/td>\n<td valign=\"top\" width=\"185\">\n<p>$Matches[0] = &#8220;Width&#8221; <br \/> (but only if &#8221; &gt;&#8221; is present)<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Add the correct prefix if it is omitted<\/h3>\n<p>This builds on the ideas we&#8217;ve seen already. I want the list of fields and prefixes to be easy to maintain, so just after I define my aliases, I define a list of field types:<\/p>\n<p style=\"padding-left: 30px\">$FieldTypes = &#8220;System&#8221;,&#8221;Photo&#8221;,&#8221;Image&#8221;,&#8221;Music&#8221;,&#8221;Media&#8221;,&#8221;RecordedTv&#8221;,&#8221;Search&#8221;\nFor each type, I define two variables, a <b>prefix<\/b> and a <b>fieldslist<\/b>. The names must be <i>Fieldtype<\/i>PREFIX and <i>FieldType<\/i>FIELDS. The reason for this will become clear shortly, but here is what they look like:<\/p>\n<p style=\"padding-left: 30px\">$SystemPrefix = &#8220;System.&#8221;<\/p>\n<p style=\"padding-left: 30px\">$SystemFields = &#8220;ItemName|ItemUrl&#8221;<\/p>\n<p style=\"padding-left: 30px\">$PhotoPrefix&nbsp; = &#8220;System.Photo.&#8221;<br \/> $PhotoFields&nbsp; = &#8220;cameramodel|cameramanufacturer|orientation&#8221;\nIn practice, the field lists are much longer. System contains 25 field names, not just the two shown here. The lists are written with &#8220;|&#8221; between the names so they become a regular expression meaning<i> <\/i>&#8220;ItemName or ItemUrl Or &hellip;&#8221;. The following code runs after aliases have been processed:<\/p>\n<p style=\"padding-left: 30px\">foreach ($type in $FieldTypes) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $fields = (get-variable &#8220;$($type)Fields&#8221;).value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $prefix = (get-variable &#8220;$($type)Prefix&#8221;).value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $sql = $sql -replace &#8220;(?&lt;=s)(?=($Fields)s*(=|&gt;|&lt;|,|Like))&#8221; , $Prefix<\/p>\n<p style=\"padding-left: 30px\">&nbsp;}\nI can save repeating code by using <b>Get-Variable<\/b> in a loop to get <b>$<span style=\"text-decoration: underline\">system<\/span>Fields<\/b>, <b>$<span style=\"text-decoration: underline\">photo<\/span>Fields<\/b>, and so on. If I want to add one more field or a whole type, I only need to change the variable declarations at the start of the script. The regular expression in the <b>-Replace<\/b> works like this:<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"222\">  <b>Regular expression<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"201\">\n<p><b>Meaning<\/b><\/p>\n<\/td>\n<td valign=\"top\" width=\"193\">\n<p><b>Application<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p><b><span style=\"text-decoration: underline\">(?&lt;=s)<\/span><\/b>(?=(cameramanufacturer|<br \/> orientation)s*(=|&gt;|&lt;|,|Like))&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"201\">\n<p>Look behind for a space, but don&#8217;t include it in the match.<\/p>\n<\/td>\n<td valign=\"top\" width=\"193\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)(?=(<b><span style=\"text-decoration: underline\">cameramanufacturer|<br \/> orientation<\/span><\/b>)s*(=|&gt;|&lt;|,|Like))&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"201\">\n<p>The literal text &#8220;orientation&#8221;&nbsp; or &#8220;cameramanufacturer&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"193\">\n<p>&nbsp;CameraManufacturer LIKE &#8216;Can%&#8217;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)(?=(cameramanufacturer|<br \/> orientation)<b><span style=\"text-decoration: underline\">s*<\/span><\/b>(=|&gt;|&lt;|,|Like))&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"201\">\n<p>Any spaces (or none)<\/p>\n<\/td>\n<td valign=\"top\" width=\"193\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)(?=(cameramanufacturer|<br \/> orientation)s*<b><span style=\"text-decoration: underline\">(=|&gt;|&lt;|,|Like)<\/span><\/b>)&#8221;<\/p>\n<\/td>\n<td valign=\"top\" width=\"201\">\n<p>The literal text &#8220;Like&#8221;, or any of the following characters: comma, equals, greater than, or less than<\/p>\n<\/td>\n<td valign=\"top\" width=\"193\">\n<p>&nbsp;CameraManufacturer <b><span style=\"text-decoration: underline\">LIKE<\/span><\/b> &#8216;Can%&#8217;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"222\">\n<p>(?&lt;=s)<b><span style=\"text-decoration: underline\">(?=<\/span><\/b>(cameramanufacturer|<br \/> orientation)s*(=|&gt;|&lt;|,|Like)<b><span style=\"text-decoration: underline\">)<\/span><\/b>&#8220;<\/p>\n<\/td>\n<td valign=\"top\" width=\"201\">\n<p>Look ahead for the enclosed expression, but don&#8217;t include it in the match.<\/p>\n<\/td>\n<td valign=\"top\" width=\"193\">\n<p>$match[0] is the point between the leading space and &#8220;CameraManufacturer LIKE&#8221;, but it doesn&#8217;t include either.<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h3>Use &#8209;Replace with a regular expression<\/h3>\n<p>We get the effect of an &#8220;insert&#8221; operator by using <b>&#8209;Replace<\/b> with a regular expression that finds a place in the text, but doesn&#8217;t select any of it.\nThis part of the function allows &#8220;CameraManufacturer LIKE &#8216;Can%'&#8221; to become &#8220;System.Photo CameraManufacturer LIKE &#8216;Can%&#8217; &#8221; in a WHERE clause. I also wanted &#8220;CameraManufacturer&#8221; in an ORDER BY clause to become &#8220;System.Photo CameraManufacturer&#8221;.\nVery sharp-eyed readers may have noticed that I look for a comma after the fieldname in addition to &lt;, &gt;, =, and LIKE. I modified the code that appeared in Part One so that when an ORDER BY clause is inserted, it is followed by a trailing comma like this:<\/p>\n<p style=\"padding-left: 30px\">if ($orderby) { $sql += &#8221; ORDER BY &#8221; + ($OrderBy&nbsp;&nbsp; -join &#8221; , &#8221; ) + &#8220;,&#8221;}\nThe new version will work with this regular expression, but the extra comma will cause a SQL error, so it must be removed later. When I introduced the SQL, I said the SELECT statement looks like this:<\/p>\n<p style=\"padding-left: 30px\">SELECT System.ItemName, System.ItemUrl, System.FileExtension, System.FileName, System.FileAttributes, System.FileOwner, System.ItemType, System.ItemTypeText , System.KindText, System.Kind, System.MIMEType, System.Size\nBuilding this clause from the field lists simplifies code maintenance, and as a bonus, anything declared in the field lists will be retrieved by the query and accepted as input by its short name.&nbsp; The SELECT clause is prepared like this:<\/p>\n<p style=\"padding-left: 30px\">&nbsp;if ($First)&nbsp; {$SQL = &#8220;SELECT TOP $First &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {$SQL = &#8220;SELECT &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;foreach ($type in $FieldTypes) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $SQL += ((get-variable &#8220;$($type)Fields&#8221;).value -replace &#8220;|&#8221;,&#8221;, &#8221; ) + &#8220;, &#8220;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;}\nThis replaces the &#8220;|&#8221; with a comma and puts a comma after each set of fields. This means that there is a comma between the last field and FROM. This allows the regular expression to recognize field names, but it will break the SQL, so it is removed after the prefixes have been inserted (just like ORDER BY).\nThis might seem inefficient, but when I checked the time it took to run the function and get the results (but not output them), it was typically about 0.05 seconds (50 ms) on my laptop. It takes more time to output the results.\nCombining all the bits in this part with the bits in Part One turns my 36-line function into about a 60-line one as follows:<\/p>\n<p style=\"padding-left: 30px\"><strong>Function Get-IndexedItem{<\/strong><\/p>\n<p style=\"padding-left: 30px\">Param ( [Alias(&#8220;Where&#8221;,&#8221;Include&#8221;)][String[]]$Filter ,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Alias(&#8220;Sort&#8221;)][String[]]$OrderBy,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Alias(&#8220;Top&#8221;)][String[]]$First,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]$Path,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]$Recurse )<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $PropertyAliases = @{Width =&#8221;System.Image.HorizontalSize&#8221;;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Height = &#8220;System.Image.VerticalSize&#8221;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $FieldTypes&nbsp;&nbsp; = &#8220;System&#8221;,&#8221;Photo&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $PhotoPrefix&nbsp; = &#8220;System.Photo.&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $PhotoFields&nbsp; = &#8220;cameramodel|cameramanufacturer|orientation&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $SystemPrefix = &#8220;System.&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $SystemFields = &#8220;ItemName|ItemUrl|FileExtension|FileName&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($First)&nbsp; {$SQL = &#8220;SELECT TOP $First &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {$SQL = &#8220;SELECT &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; foreach ($type in $FieldTypes) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL += ((get-variable &#8220;$($type)Fields&#8221;).value -replace &#8220;|&#8221;,&#8221;, &#8220;)+&#8221;, &#8220;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($Path -match &#8220;\\\\([^\\]+)\\.&#8221;) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL += &#8221; FROM $($matches[1]).SYSTEMINDEX WHERE &#8221;&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; else {$SQL += &#8221; FROM SYSTEMINDEX WHERE &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($Filter) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Filter = $Filter -replace &#8220;*&#8221;,&#8221;%&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Filter = $Filter -replace&#8221;s*(=|&lt;|&gt;|like)s*([^&#8217;d][^s&#8217;]*)$&#8221;,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8216; $1 &#8221;$2&#8221; &#8216;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Filter = $Filter -replace &#8220;s*=s*(?=&#8217;.+%&#8217;s*$)&#8221; ,&#8221; LIKE &#8220;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Filter = ($Filter | ForEach-Object {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($_ -match &#8220;&#8216;|=|&lt;|&gt;|like|contains|freetext&#8221;) {$_}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else {&#8220;Contains(*,&#8217;$_&#8217;)&#8221;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; })<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL += $Filter -join &#8221; AND &#8220;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($Path) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($Path -notmatch &#8220;w{4}:&#8221;)&nbsp; {$Path = &#8220;file:&#8221; + $Path}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Path&nbsp; = $Path -replace &#8220;\\&#8221;,&#8221;\/&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($SQL -notmatch &#8220;WHEREs$&#8221;) {$SQL += &#8221; AND &#8221; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ($Recurse)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {$SQL += &#8221; SCOPE = &#8216;$Path&#8217; &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {$SQL += &#8221; DIRECTORY = &#8216;$Path&#8217; &#8220;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($SQL -match &#8220;WHEREs*$&#8221;) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-warning &#8220;You need to specify either a path , or a filter.&#8221; ; return<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($OrderBy) { $SQL += &#8221; ORDER BY &#8221; + ($OrderBy&nbsp;&nbsp; -join &#8221; , &#8221; ) + &#8220;,&#8221;}<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $PropertyAliases.Keys | ForEach-Object {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL= $SQL -replace &#8220;(?&lt;=s)$($_)(?=s*(=|&gt;|&lt;|,|Like))&#8221;,<br \/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $PropertyAliases.$_<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; foreach ($type in $FieldTypes) {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $fields = (get-variable &#8220;$($type)Fields&#8221;).value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $prefix = (get-variable &#8220;$($type)Prefix&#8221;).value<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $SQL = $SQL -replace &#8220;(?&lt;=s)(?=($Fields)s*(=|&gt;|&lt;|,|Like))&#8221; , $Prefix<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $SQL = $SQL -replace &#8220;s*,s*FROMs+&#8221; , &#8221; FROM &#8220;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $SQL = $SQL -replace &#8220;s*,s*$&#8221;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , &#8220;&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $Provider=&#8221;Provider=Search.CollatorDSO;&#8221;+<br \/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Extended Properties=&rsquo;Application=Windows&rsquo;;&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $Adapter = new-object system.data.oledb.oleDBDataadapter -argument $SQL,<br \/> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Provider<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $DS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = new-object system.data.dataset<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($Adapter.Fill($DS)) { $DS.Tables[0] }<\/p>\n<p style=\"padding-left: 30px\">}\n~James\nAwesome job, James! I want to thank you for taking the time to share with us today. Guest Blogger Week will continue tomorrow when James returns with Part Three.\nI invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.\n<b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, James O&#8217;Neill, uses Windows PowerShell to help users with input for searching the Windows Index. Microsoft Scripting Guy, Ed Wilson, is here. Today James O&rsquo;Neill is back with Part Two. Note: This is Part Two of a three part series about using Windows PowerShell to search the Windows Index. Yesterday, James talked [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[56,353,31,3,4,147,45],"class_list":["post-8931","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-guest-blogger","tag-james-oneill","tag-operating-system","tag-scripting-guy","tag-scripting-techniques","tag-search","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, James O&#8217;Neill, uses Windows PowerShell to help users with input for searching the Windows Index. Microsoft Scripting Guy, Ed Wilson, is here. Today James O&rsquo;Neill is back with Part Two. Note: This is Part Two of a three part series about using Windows PowerShell to search the Windows Index. Yesterday, James talked [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/8931","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=8931"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/8931\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=8931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=8931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=8931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}